• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orion-ecs / keen-eye / 20242187228

15 Dec 2025 05:54PM UTC coverage: 91.561% (+0.09%) from 91.473%
20242187228

push

github

tyevco
chore(deps): Bump amannn/action-semantic-pull-request from 5 to 6

Bumps [amannn/action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request) from 5 to 6.
- [Release notes](https://github.com/amannn/action-semantic-pull-request/releases)
- [Changelog](https://github.com/amannn/action-semantic-pull-request/blob/main/CHANGELOG.md)
- [Commits](https://github.com/amannn/action-semantic-pull-request/compare/v5...v6)

---
updated-dependencies:
- dependency-name: amannn/action-semantic-pull-request
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

1848 of 2007 branches covered (92.08%)

Branch coverage included in aggregate %.

10130 of 11075 relevant lines covered (91.47%)

1.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.72
/src/KeenEyes.Generators/SerializationGenerator.cs
1
using System.Collections.Generic;
2
using System.Collections.Immutable;
3
using System.Linq;
4
using System.Text;
5
using KeenEyes.Generators.Utilities;
6
using Microsoft.CodeAnalysis;
7
using Microsoft.CodeAnalysis.CSharp.Syntax;
8
using Microsoft.CodeAnalysis.Text;
9

10
namespace KeenEyes.Generators;
11

12
/// <summary>
13
/// Generates AOT-compatible serialization code for components marked with [Component(Serializable = true)].
14
/// Eliminates runtime reflection by generating strongly-typed serialization methods.
15
/// </summary>
16
[Generator]
17
public sealed class SerializationGenerator : IIncrementalGenerator
18
{
19
    private const string ComponentAttribute = "KeenEyes.ComponentAttribute";
20

21
    /// <inheritdoc />
22
    public void Initialize(IncrementalGeneratorInitializationContext context)
23
    {
24
        // Find all structs with [Component(Serializable = true)]
25
        var serializableComponents = context.SyntaxProvider
1✔
26
            .ForAttributeWithMetadataName(
1✔
27
                ComponentAttribute,
1✔
28
                predicate: static (node, _) => node is StructDeclarationSyntax,
1✔
29
                transform: static (ctx, _) => GetSerializableComponentInfo(ctx))
1✔
30
            .Where(static info => info is not null);
1✔
31

32
        var collected = serializableComponents.Collect();
1✔
33

34
        // Generate the serialization registry only if there are serializable components
35
        context.RegisterSourceOutput(collected, static (ctx, components) =>
1✔
36
        {
1✔
37
            var validComponents = components
1✔
38
                .Where(c => c is not null)
1✔
39
                .Select(c => c!)
1✔
40
                .ToImmutableArray();
1✔
41

1✔
42
            // Don't generate anything if there are no serializable components
1✔
43
            // This avoids conflicts when multiple projects reference KeenEyes.Core
1✔
44
            if (validComponents.Length == 0)
1✔
45
            {
1✔
46
                return;
1✔
47
            }
1✔
48

1✔
49
            var source = GenerateSerializationRegistry(validComponents);
1✔
50
            ctx.AddSource("ComponentSerializer.g.cs", SourceText.From(source, Encoding.UTF8));
1✔
51
        });
1✔
52
    }
1✔
53

54
    private static SerializableComponentInfo? GetSerializableComponentInfo(GeneratorAttributeSyntaxContext context)
55
    {
56
        // TargetSymbol is guaranteed to be INamedTypeSymbol because we filter for StructDeclarationSyntax
57
        var typeSymbol = (INamedTypeSymbol)context.TargetSymbol;
1✔
58

59
        // Check for Serializable = true in attribute
60
        // Attributes is guaranteed non-empty because we use ForAttributeWithMetadataName
61
        var attr = context.Attributes.First();
1✔
62

63
        var serializableArg = attr.NamedArguments
1✔
64
            .FirstOrDefault(a => a.Key == "Serializable");
1✔
65

66
        if (serializableArg.Value.Value is not true)
1✔
67
        {
68
            return null;
1✔
69
        }
70

71
        // Collect fields for serialization
72
        var fields = new List<SerializableFieldInfo>();
1✔
73
        foreach (var member in typeSymbol.GetMembers())
1✔
74
        {
75
            if (member is not IFieldSymbol field)
1✔
76
            {
77
                continue;
78
            }
79

80
            if (field.IsStatic || field.IsConst)
1✔
81
            {
82
                continue;
83
            }
84

85
            var isNullable = field.Type.NullableAnnotation == NullableAnnotation.Annotated;
1✔
86
            fields.Add(new SerializableFieldInfo(
1✔
87
                field.Name,
1✔
88
                field.Type.ToDisplayString(),
1✔
89
                GetJsonTypeName(field.Type),
1✔
90
                isNullable));
1✔
91
        }
92

93
        return new SerializableComponentInfo(
1✔
94
            typeSymbol.Name,
1✔
95
            typeSymbol.ContainingNamespace.ToDisplayString(),
1✔
96
            typeSymbol.ToDisplayString(),
1✔
97
            fields.ToImmutableArray());
1✔
98
    }
99

100
    private static string GetJsonTypeName(ITypeSymbol type)
101
    {
102
        // Map CLR types to JSON reader method names
103
        var displayString = type.ToDisplayString();
1✔
104
        return displayString switch
1✔
105
        {
1✔
106
            "int" or "System.Int32" => "Int32",
1✔
107
            "long" or "System.Int64" => "Int64",
1✔
108
            "short" or "System.Int16" => "Int16",
×
109
            "byte" or "System.Byte" => "Byte",
×
110
            "uint" or "System.UInt32" => "UInt32",
×
111
            "ulong" or "System.UInt64" => "UInt64",
×
112
            "ushort" or "System.UInt16" => "UInt16",
×
113
            "sbyte" or "System.SByte" => "SByte",
×
114
            "float" or "System.Single" => "Single",
1✔
115
            "double" or "System.Double" => "Double",
1✔
116
            "decimal" or "System.Decimal" => "Decimal",
1✔
117
            "bool" or "System.Boolean" => "Boolean",
1✔
118
            "string" or "System.String" => "String",
1✔
119
            _ => "Object" // For complex types, use generic deserialization
1✔
120
        };
1✔
121
    }
122

123
    private static string GenerateSerializationRegistry(ImmutableArray<SerializableComponentInfo> components)
124
    {
125
        var sb = new StringBuilder();
1✔
126

127
        sb.AppendLine("// <auto-generated />");
1✔
128
        sb.AppendLine("#nullable enable");
1✔
129
        sb.AppendLine();
1✔
130
        sb.AppendLine("using System;");
1✔
131
        sb.AppendLine("using System.Collections.Generic;");
1✔
132
        sb.AppendLine("using System.IO;");
1✔
133
        sb.AppendLine("using System.Text.Json;");
1✔
134
        sb.AppendLine("using KeenEyes.Serialization;");
1✔
135
        sb.AppendLine();
1✔
136
        sb.AppendLine("namespace KeenEyes.Generated;");
1✔
137
        sb.AppendLine();
1✔
138
        sb.AppendLine("/// <summary>");
1✔
139
        sb.AppendLine("/// Generated registry for AOT-compatible component serialization.");
1✔
140
        sb.AppendLine("/// Contains serialization methods for components marked with [Component(Serializable = true)].");
1✔
141
        sb.AppendLine("/// </summary>");
1✔
142
        sb.AppendLine("public sealed class ComponentSerializer : IComponentSerializer, IBinaryComponentSerializer");
1✔
143
        sb.AppendLine("{");
1✔
144
        sb.AppendLine("    /// <summary>");
1✔
145
        sb.AppendLine("    /// Shared instance for convenience.");
1✔
146
        sb.AppendLine("    /// </summary>");
1✔
147
        sb.AppendLine("    public static readonly ComponentSerializer Instance = new();");
1✔
148
        sb.AppendLine();
1✔
149
        sb.AppendLine("    private sealed record ComponentSerializationInfo(");
1✔
150
        sb.AppendLine("        Type Type,");
1✔
151
        sb.AppendLine("        Func<JsonElement, object> JsonDeserializer,");
1✔
152
        sb.AppendLine("        Func<object, JsonElement> JsonSerializer,");
1✔
153
        sb.AppendLine("        Func<BinaryReader, object> BinaryDeserializer,");
1✔
154
        sb.AppendLine("        Action<object, BinaryWriter> BinarySerializer,");
1✔
155
        sb.AppendLine("        Func<World, bool, ComponentInfo> Registrar,");
1✔
156
        sb.AppendLine("        Action<World, object> SingletonSetter);");
1✔
157
        sb.AppendLine();
1✔
158
        sb.AppendLine("    private static readonly Dictionary<string, ComponentSerializationInfo> ComponentsByName;");
1✔
159
        sb.AppendLine("    private static readonly Dictionary<Type, ComponentSerializationInfo> ComponentsByType;");
1✔
160
        sb.AppendLine();
1✔
161

162
        // Static constructor to initialize dictionaries
163
        sb.AppendLine("    static ComponentSerializer()");
1✔
164
        sb.AppendLine("    {");
1✔
165
        sb.AppendLine("        ComponentsByName = new Dictionary<string, ComponentSerializationInfo>();");
1✔
166
        sb.AppendLine("        ComponentsByType = new Dictionary<Type, ComponentSerializationInfo>();");
1✔
167
        sb.AppendLine();
1✔
168

169
        foreach (var component in components)
1✔
170
        {
171
            sb.AppendLine($"        var info_{component.Name} = new ComponentSerializationInfo(");
1✔
172
            sb.AppendLine($"            typeof({component.FullName}),");
1✔
173
            sb.AppendLine($"            Deserialize_{component.Name},");
1✔
174
            sb.AppendLine($"            value => Serialize_{component.Name}(({component.FullName})value),");
1✔
175
            sb.AppendLine($"            DeserializeBinary_{component.Name},");
1✔
176
            sb.AppendLine($"            (value, writer) => SerializeBinary_{component.Name}(({component.FullName})value, writer),");
1✔
177
            sb.AppendLine($"            (world, isTag) => world.Components.Register<{component.FullName}>(isTag),");
1✔
178
            sb.AppendLine($"            (world, value) => world.SetSingleton(({component.FullName})value));");
1✔
179
            sb.AppendLine();
1✔
180
            sb.AppendLine($"        ComponentsByName[typeof({component.FullName}).AssemblyQualifiedName!] = info_{component.Name};");
1✔
181
            sb.AppendLine($"        ComponentsByName[\"{component.FullName}\"] = info_{component.Name};");
1✔
182
            sb.AppendLine($"        ComponentsByType[typeof({component.FullName})] = info_{component.Name};");
1✔
183
            sb.AppendLine();
1✔
184
        }
185

186
        sb.AppendLine("    }");
1✔
187
        sb.AppendLine();
1✔
188

189
        // Public API methods implementing IComponentSerializer
190
        sb.AppendLine("    /// <inheritdoc />");
1✔
191
        sb.AppendLine("    public bool IsSerializable(Type type) => ComponentsByType.ContainsKey(type);");
1✔
192
        sb.AppendLine();
1✔
193
        sb.AppendLine("    /// <inheritdoc />");
1✔
194
        sb.AppendLine("    public bool IsSerializable(string typeName) => ComponentsByName.ContainsKey(typeName);");
1✔
195
        sb.AppendLine();
1✔
196
        sb.AppendLine("    /// <inheritdoc />");
1✔
197
        sb.AppendLine("    public object? Deserialize(string typeName, JsonElement json)");
1✔
198
        sb.AppendLine("    {");
1✔
199
        sb.AppendLine("        return ComponentsByName.TryGetValue(typeName, out var info)");
1✔
200
        sb.AppendLine("            ? info.JsonDeserializer(json)");
1✔
201
        sb.AppendLine("            : null;");
1✔
202
        sb.AppendLine("    }");
1✔
203
        sb.AppendLine();
1✔
204
        sb.AppendLine("    /// <inheritdoc />");
1✔
205
        sb.AppendLine("    public JsonElement? Serialize(Type type, object value)");
1✔
206
        sb.AppendLine("    {");
1✔
207
        sb.AppendLine("        if (!ComponentsByType.TryGetValue(type, out var info))");
1✔
208
        sb.AppendLine("        {");
1✔
209
        sb.AppendLine("            return null;");
1✔
210
        sb.AppendLine("        }");
1✔
211
        sb.AppendLine("        return info.JsonSerializer(value);");
1✔
212
        sb.AppendLine("    }");
1✔
213
        sb.AppendLine();
1✔
214
        sb.AppendLine("    /// <inheritdoc />");
1✔
215
        sb.AppendLine("    Type? IComponentSerializer.GetType(string typeName)");
1✔
216
        sb.AppendLine("    {");
1✔
217
        sb.AppendLine("        return ComponentsByName.TryGetValue(typeName, out var info) ? info.Type : null;");
1✔
218
        sb.AppendLine("    }");
1✔
219
        sb.AppendLine();
1✔
220
        sb.AppendLine("    /// <inheritdoc />");
1✔
221
        sb.AppendLine("    public ComponentInfo? RegisterComponent(World world, string typeName, bool isTag)");
1✔
222
        sb.AppendLine("    {");
1✔
223
        sb.AppendLine("        return ComponentsByName.TryGetValue(typeName, out var info) ? info.Registrar(world, isTag) : null;");
1✔
224
        sb.AppendLine("    }");
1✔
225
        sb.AppendLine();
1✔
226
        sb.AppendLine("    /// <inheritdoc />");
1✔
227
        sb.AppendLine("    public bool SetSingleton(World world, string typeName, object value)");
1✔
228
        sb.AppendLine("    {");
1✔
229
        sb.AppendLine("        if (ComponentsByName.TryGetValue(typeName, out var info))");
1✔
230
        sb.AppendLine("        {");
1✔
231
        sb.AppendLine("            info.SingletonSetter(world, value);");
1✔
232
        sb.AppendLine("            return true;");
1✔
233
        sb.AppendLine("        }");
1✔
234
        sb.AppendLine("        return false;");
1✔
235
        sb.AppendLine("    }");
1✔
236
        sb.AppendLine();
1✔
237
        sb.AppendLine("    /// <inheritdoc />");
1✔
238
        sb.AppendLine("    public object? CreateDefault(string typeName)");
1✔
239
        sb.AppendLine("    {");
1✔
240
        sb.AppendLine("        return ComponentsByName.TryGetValue(typeName, out var info) ? Activator.CreateInstance(info.Type) : null;");
1✔
241
        sb.AppendLine("    }");
1✔
242
        sb.AppendLine();
1✔
243
        sb.AppendLine("    /// <summary>");
1✔
244
        sb.AppendLine("    /// Gets all registered serializable type names.");
1✔
245
        sb.AppendLine("    /// </summary>");
1✔
246
        sb.AppendLine("    public IEnumerable<string> GetSerializableTypeNames() => ComponentsByName.Keys;");
1✔
247
        sb.AppendLine();
1✔
248
        sb.AppendLine("    /// <summary>");
1✔
249
        sb.AppendLine("    /// Gets all registered serializable types.");
1✔
250
        sb.AppendLine("    /// </summary>");
1✔
251
        sb.AppendLine("    public IEnumerable<Type> GetSerializableTypes() => ComponentsByType.Keys;");
1✔
252
        sb.AppendLine();
1✔
253

254
        // IBinaryComponentSerializer implementation
255
        sb.AppendLine("    /// <inheritdoc />");
1✔
256
        sb.AppendLine("    public bool WriteTo(Type type, object value, BinaryWriter writer)");
1✔
257
        sb.AppendLine("    {");
1✔
258
        sb.AppendLine("        if (!ComponentsByType.TryGetValue(type, out var info))");
1✔
259
        sb.AppendLine("        {");
1✔
260
        sb.AppendLine("            return false;");
1✔
261
        sb.AppendLine("        }");
1✔
262
        sb.AppendLine("        info.BinarySerializer(value, writer);");
1✔
263
        sb.AppendLine("        return true;");
1✔
264
        sb.AppendLine("    }");
1✔
265
        sb.AppendLine();
1✔
266
        sb.AppendLine("    /// <inheritdoc />");
1✔
267
        sb.AppendLine("    public object? ReadFrom(string typeName, BinaryReader reader)");
1✔
268
        sb.AppendLine("    {");
1✔
269
        sb.AppendLine("        return ComponentsByName.TryGetValue(typeName, out var info)");
1✔
270
        sb.AppendLine("            ? info.BinaryDeserializer(reader)");
1✔
271
        sb.AppendLine("            : null;");
1✔
272
        sb.AppendLine("    }");
1✔
273
        sb.AppendLine();
1✔
274

275
        // Generate individual serialization/deserialization methods
276
        foreach (var component in components)
1✔
277
        {
278
            GenerateComponentMethods(sb, component);
1✔
279
        }
280

281
        sb.AppendLine("}");
1✔
282

283
        return sb.ToString();
1✔
284
    }
285

286
    private static void GenerateComponentMethods(StringBuilder sb, SerializableComponentInfo component)
287
    {
288
        // Deserialize method
289
        sb.AppendLine($"    private static object Deserialize_{component.Name}(JsonElement json)");
1✔
290
        sb.AppendLine("    {");
1✔
291
        sb.AppendLine($"        var result = new {component.FullName}();");
1✔
292

293
        foreach (var field in component.Fields)
1✔
294
        {
295
            var camelFieldName = StringHelpers.ToCamelCase(field.Name);
1✔
296
            sb.AppendLine($"        if (json.TryGetProperty(\"{camelFieldName}\", out var {camelFieldName}Elem))");
1✔
297
            sb.AppendLine("        {");
1✔
298

299
            if (field.JsonTypeName == "Object")
1✔
300
            {
301
                // Complex type - use generic deserialization
302
                if (field.IsNullable)
1✔
303
                {
304
                    sb.AppendLine($"            result.{field.Name} = JsonSerializer.Deserialize<{field.Type}>({camelFieldName}Elem.GetRawText());");
1✔
305
                }
306
                else
307
                {
308
                    sb.AppendLine($"            result.{field.Name} = JsonSerializer.Deserialize<{field.Type}>({camelFieldName}Elem.GetRawText()) ?? throw new JsonException(\"Non-nullable field '{field.Name}' was null in JSON\");");
1✔
309
                }
310
            }
311
            else if (field.JsonTypeName == "String")
1✔
312
            {
313
                if (field.IsNullable)
1✔
314
                {
315
                    sb.AppendLine($"            result.{field.Name} = {camelFieldName}Elem.GetString();");
×
316
                }
317
                else
318
                {
319
                    sb.AppendLine($"            result.{field.Name} = {camelFieldName}Elem.GetString() ?? throw new JsonException(\"Non-nullable field '{field.Name}' was null in JSON\");");
1✔
320
                }
321
            }
322
            else
323
            {
324
                // Value types like int, bool, etc. - GetInt32(), GetBoolean(), etc. never return null
325
                sb.AppendLine($"            result.{field.Name} = {camelFieldName}Elem.Get{field.JsonTypeName}();");
1✔
326
            }
327

328
            sb.AppendLine("        }");
1✔
329
        }
330

331
        sb.AppendLine("        return result;");
1✔
332
        sb.AppendLine("    }");
1✔
333
        sb.AppendLine();
1✔
334

335
        // Serialize method
336
        sb.AppendLine($"    private static JsonElement Serialize_{component.Name}({component.FullName} value)");
1✔
337
        sb.AppendLine("    {");
1✔
338
        sb.AppendLine("        using var stream = new System.IO.MemoryStream();");
1✔
339
        sb.AppendLine("        using var writer = new Utf8JsonWriter(stream);");
1✔
340
        sb.AppendLine("        writer.WriteStartObject();");
1✔
341

342
        foreach (var field in component.Fields)
1✔
343
        {
344
            var camelFieldName = StringHelpers.ToCamelCase(field.Name);
1✔
345

346
            if (field.JsonTypeName == "Object")
1✔
347
            {
348
                sb.AppendLine($"        writer.WritePropertyName(\"{camelFieldName}\");");
1✔
349
                sb.AppendLine($"        JsonSerializer.Serialize(writer, value.{field.Name});");
1✔
350
            }
351
            else if (field.JsonTypeName == "String")
1✔
352
            {
353
                sb.AppendLine($"        writer.WriteString(\"{camelFieldName}\", value.{field.Name});");
1✔
354
            }
355
            else if (field.JsonTypeName == "Boolean")
1✔
356
            {
357
                sb.AppendLine($"        writer.WriteBoolean(\"{camelFieldName}\", value.{field.Name});");
1✔
358
            }
359
            else
360
            {
361
                sb.AppendLine($"        writer.WriteNumber(\"{camelFieldName}\", value.{field.Name});");
1✔
362
            }
363
        }
364

365
        sb.AppendLine("        writer.WriteEndObject();");
1✔
366
        sb.AppendLine("        writer.Flush();");
1✔
367
        sb.AppendLine("        stream.Position = 0;");
1✔
368
        sb.AppendLine("        return JsonDocument.Parse(stream).RootElement.Clone();");
1✔
369
        sb.AppendLine("    }");
1✔
370
        sb.AppendLine();
1✔
371

372
        // Binary deserialize method
373
        sb.AppendLine($"    private static object DeserializeBinary_{component.Name}(BinaryReader reader)");
1✔
374
        sb.AppendLine("    {");
1✔
375
        sb.AppendLine($"        var result = new {component.FullName}();");
1✔
376

377
        foreach (var field in component.Fields)
1✔
378
        {
379
            var binaryRead = GetBinaryReadMethod(field.JsonTypeName, field.Type, field.IsNullable);
1✔
380
            sb.AppendLine($"        result.{field.Name} = {binaryRead};");
1✔
381
        }
382

383
        sb.AppendLine("        return result;");
1✔
384
        sb.AppendLine("    }");
1✔
385
        sb.AppendLine();
1✔
386

387
        // Binary serialize method
388
        sb.AppendLine($"    private static void SerializeBinary_{component.Name}({component.FullName} value, BinaryWriter writer)");
1✔
389
        sb.AppendLine("    {");
1✔
390

391
        foreach (var field in component.Fields)
1✔
392
        {
393
            var binaryWrite = GetBinaryWriteCode(field.JsonTypeName, field.Type, $"value.{field.Name}");
1✔
394
            sb.AppendLine($"        {binaryWrite}");
1✔
395
        }
396

397
        sb.AppendLine("    }");
1✔
398
        sb.AppendLine();
1✔
399
    }
1✔
400

401
    private static string GetBinaryReadMethod(string jsonTypeName, string type, bool isNullable)
402
    {
403
        return jsonTypeName switch
1✔
404
        {
1✔
405
            "Int32" => "reader.ReadInt32()",
1✔
406
            "Int64" => "reader.ReadInt64()",
1✔
407
            "Int16" => "reader.ReadInt16()",
×
408
            "Byte" => "reader.ReadByte()",
×
409
            "UInt32" => "reader.ReadUInt32()",
×
410
            "UInt64" => "reader.ReadUInt64()",
×
411
            "UInt16" => "reader.ReadUInt16()",
×
412
            "SByte" => "reader.ReadSByte()",
×
413
            "Single" => "reader.ReadSingle()",
1✔
414
            "Double" => "reader.ReadDouble()",
1✔
415
            "Decimal" => "reader.ReadDecimal()",
1✔
416
            "Boolean" => "reader.ReadBoolean()",
1✔
417
            "String" => "reader.ReadString()", // BinaryReader.ReadString() never returns null
1✔
418
            _ => isNullable
1✔
419
                ? $"JsonSerializer.Deserialize<{type}>(reader.ReadString())"
1✔
420
                : $"JsonSerializer.Deserialize<{type}>(reader.ReadString()) ?? throw new InvalidDataException(\"Non-nullable field was null in binary data\")"
1✔
421
        };
1✔
422
    }
423

424
    private static string GetBinaryWriteCode(string jsonTypeName, string type, string valueExpr)
425
    {
426
        return jsonTypeName switch
1✔
427
        {
1✔
428
            "Int32" or "Int64" or "Int16" or "Byte" or
1✔
429
            "UInt32" or "UInt64" or "UInt16" or "SByte" or
1✔
430
            "Single" or "Double" or "Decimal" or "Boolean" or "String"
1✔
431
                => $"writer.Write({valueExpr});",
1✔
432
            _ => $"writer.Write(JsonSerializer.Serialize({valueExpr}));" // Complex types as JSON
1✔
433
        };
1✔
434
    }
435

436
    private sealed record SerializableComponentInfo(
1✔
437
        string Name,
1✔
438
        string Namespace,
×
439
        string FullName,
1✔
440
        ImmutableArray<SerializableFieldInfo> Fields);
1✔
441

442
    private sealed record SerializableFieldInfo(
1✔
443
        string Name,
1✔
444
        string Type,
1✔
445
        string JsonTypeName,
1✔
446
        bool IsNullable);
1✔
447
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc