diff --git a/CarpaNet.Samples.slnx b/CarpaNet.Samples.slnx
index 92984d7..8b28771 100644
--- a/CarpaNet.Samples.slnx
+++ b/CarpaNet.Samples.slnx
@@ -12,6 +12,7 @@
+
diff --git a/samples/MebiByteTest/MebiByteTest.csproj b/samples/MebiByteTest/MebiByteTest.csproj
new file mode 100644
index 0000000..567f277
--- /dev/null
+++ b/samples/MebiByteTest/MebiByteTest.csproj
@@ -0,0 +1,26 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ true
+ true
+ ATProtoJsonContext
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MebiByteTest/Program.cs b/samples/MebiByteTest/Program.cs
new file mode 100644
index 0000000..ae3f5df
--- /dev/null
+++ b/samples/MebiByteTest/Program.cs
@@ -0,0 +1,2 @@
+// MebiByteTest - Verify source generation for MebiByte lexicons
+Console.WriteLine("MebiByteTest: Source generation succeeded.");
diff --git a/samples/MebiByteTest/README.md b/samples/MebiByteTest/README.md
new file mode 100644
index 0000000..5446f8a
--- /dev/null
+++ b/samples/MebiByteTest/README.md
@@ -0,0 +1,3 @@
+# MebiByteTest
+
+This is to test complex, locally referenced, lexicon entries to validate that they compile.
\ No newline at end of file
diff --git a/samples/MebiByteTest/lexicons/social/mebibyte/bff/defs.json b/samples/MebiByteTest/lexicons/social/mebibyte/bff/defs.json
new file mode 100644
index 0000000..06d54fe
--- /dev/null
+++ b/samples/MebiByteTest/lexicons/social/mebibyte/bff/defs.json
@@ -0,0 +1,677 @@
+{
+ "lexicon": 1,
+ "id": "social.mebibyte.bff.defs",
+ "description": "Shared definitions for the Byte File Format (bff): colors, frames, transforms, and the renderable object variants. Because Lexicon has no float primitive, float-valued scalars and float-array entries are typed as `unknown`; consumers must enforce ranges (color channels and opacity in [0.0, 1.0], size/padding > 0, etc.). The bff `type` discriminator is replaced by atproto's `$type` when records are serialized.",
+ "defs": {
+ "color": {
+ "type": "array",
+ "description": "RGBA color expressed as four floats in [0.0, 1.0]: [R, G, B, A].",
+ "items": {
+ "type": "string",
+ "description": "Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "minLength": 4,
+ "maxLength": 4
+ },
+ "frame": {
+ "type": "array",
+ "description": "Position and size of an object: [X, Y, WIDTH, HEIGHT] in points on the 324x570 stage.",
+ "items": {
+ "type": "string",
+ "description": "Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "minLength": 4,
+ "maxLength": 4
+ },
+ "transformRow": {
+ "type": "array",
+ "description": "One row of a 3x2 affine transform: [A, B] (or [C, D], or [TX, TY]).",
+ "items": {
+ "type": "string",
+ "description": "Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "minLength": 2,
+ "maxLength": 2
+ },
+ "transform": {
+ "type": "array",
+ "description": "Top two rows of a 3x3 affine transformation matrix applied after `frame` is set: [[A, B], [C, D], [TX, TY]].",
+ "items": {
+ "type": "ref",
+ "ref": "#transformRow"
+ },
+ "minLength": 3,
+ "maxLength": 3
+ },
+ "effect": {
+ "type": "string",
+ "description": "Animation effect id applied to an object and looped indefinitely. Multiple effects can be combined.",
+ "knownValues": [
+ "sin",
+ "cos",
+ "wave",
+ "rotate",
+ "soon",
+ "fireworks"
+ ],
+ "maxLength": 512
+ },
+ "textAttribute": {
+ "type": "object",
+ "description": "A styling attribute applied to a substring of paragraph text.",
+ "required": [
+ "type",
+ "range"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "bold",
+ "italic",
+ "bold-italic"
+ ],
+ "maxLength": 32
+ },
+ "range": {
+ "type": "array",
+ "description": "[startIndex, length] in utf16 code units.",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minLength": 2,
+ "maxLength": 2
+ }
+ }
+ },
+ "paragraph": {
+ "type": "object",
+ "description": "The Paragraph object renders text that flows and automatically wraps inside its frame. Best for text longer than 1-3 words.",
+ "required": [
+ "frame",
+ "text"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "description": "A unique name or ID for the object. Case sensitive.",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "description": "Optional web url linking to the original source of the object.",
+ "maxLength": 2048
+ },
+ "text": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The text to render. Cannot be purely whitespace.",
+ "maxLength": 3000
+ },
+ "color": {
+ "type": "ref",
+ "ref": "#color"
+ },
+ "style": {
+ "type": "string",
+ "description": "Font style. Paragraph supports sans or serif.",
+ "knownValues": [
+ "sans",
+ "serif"
+ ],
+ "default": "sans",
+ "maxLength": 32
+ },
+ "size": {
+ "type": "string",
+ "description": "Point size to render the text as a float > 0. Default 17.0. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "alignment": {
+ "type": "string",
+ "enum": [
+ "left",
+ "center",
+ "right"
+ ],
+ "default": "left",
+ "maxLength": 16
+ },
+ "attributes": {
+ "type": "array",
+ "description": "Styling attributes applied to ranges of the text (bold, italic, bold-italic).",
+ "items": {
+ "type": "ref",
+ "ref": "#textAttribute"
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "The Text object renders text that dynamically resizes to fill its frame. Always centered. Best for 1-3 words.",
+ "required": [
+ "frame",
+ "text"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "text": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The text to render. Cannot be purely whitespace.",
+ "maxLength": 3000
+ },
+ "color": {
+ "type": "ref",
+ "ref": "#color"
+ },
+ "style": {
+ "type": "string",
+ "description": "Font style. Text supports a wider range of display faces than Paragraph.",
+ "knownValues": [
+ "sans",
+ "serif",
+ "mono",
+ "eightbit",
+ "punchout",
+ "cursive",
+ "poster",
+ "tape",
+ "book"
+ ],
+ "default": "sans",
+ "maxLength": 32
+ },
+ "wordWrap": {
+ "type": "string",
+ "description": "Wrapping policy. `auto` lets the renderer decide; `manual` only wraps at explicit line breaks. Serialized as `word-wrap` in legacy bff.",
+ "enum": [
+ "auto",
+ "manual"
+ ],
+ "default": "auto",
+ "maxLength": 16
+ },
+ "padding": {
+ "type": "string",
+ "description": "Padding (float >= 0) applied inside the frame while sizing the text. Default 20.0. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ }
+ }
+ },
+ "link": {
+ "type": "object",
+ "description": "A pressable object that redirects the viewer to another Byte or website.",
+ "required": [
+ "frame",
+ "url"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Destination URL. Both `byte://` and `http(s)://` are supported. Use `byte://byte.{BYTE_ID}` to link to a Byte by id.",
+ "maxLength": 2048
+ },
+ "title": {
+ "type": "string",
+ "description": "Title shown on the link.",
+ "maxLength": 300
+ },
+ "description": {
+ "type": "string",
+ "description": "Short description of the destination content.",
+ "maxLength": 1000
+ },
+ "color": {
+ "type": "ref",
+ "ref": "#color"
+ },
+ "style": {
+ "type": "string",
+ "knownValues": [
+ "sans",
+ "serif"
+ ],
+ "default": "sans",
+ "maxLength": 32
+ }
+ }
+ },
+ "image": {
+ "type": "object",
+ "description": "An inline PNG, JPEG, or BMP image.",
+ "required": [
+ "frame",
+ "src"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "src": {
+ "type": "blob",
+ "description": "The image asset (PNG, JPEG, or BMP).",
+ "accept": ["image/png", "image/jpeg", "image/bmp"],
+ "maxSize": 2000000
+ },
+ "scaleMode": {
+ "type": "string",
+ "description": "How the image is resized inside its frame.",
+ "enum": [
+ "fit",
+ "fill"
+ ],
+ "default": "fill",
+ "maxLength": 16
+ }
+ }
+ },
+ "graphic": {
+ "type": "object",
+ "description": "A monochromatic PNG that can be dynamically tinted. Always scales to fit its frame.",
+ "required": [
+ "frame",
+ "src"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "src": {
+ "type": "blob",
+ "description": "The monochrome PNG asset.",
+ "accept": ["image/png"],
+ "maxSize": 1000000
+ },
+ "color": {
+ "type": "ref",
+ "ref": "#color"
+ }
+ }
+ },
+ "gif": {
+ "type": "object",
+ "description": "An inline animated GIF.",
+ "required": [
+ "frame",
+ "src"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "src": {
+ "type": "blob",
+ "description": "The GIF asset.",
+ "accept": ["image/gif"],
+ "maxSize": 4000000
+ },
+ "scaleMode": {
+ "type": "string",
+ "enum": [
+ "fit",
+ "fill"
+ ],
+ "default": "fit",
+ "maxLength": 16
+ }
+ }
+ },
+ "video": {
+ "type": "object",
+ "description": "An inline MP4 video. Videos autoplay and loop on completion; 10 seconds or less is recommended.",
+ "required": [
+ "frame",
+ "src"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "src": {
+ "type": "blob",
+ "description": "The MP4 video asset.",
+ "accept": ["video/mp4"],
+ "maxSize": 50000000
+ },
+ "muted": {
+ "type": "boolean",
+ "description": "Whether the video should play with sound muted.",
+ "default": true
+ }
+ }
+ },
+ "musicHit": {
+ "type": "object",
+ "description": "A single note or drum hit inside a music beat.",
+ "required": [
+ "time",
+ "type",
+ "bank",
+ "note",
+ "velo",
+ "duration"
+ ],
+ "properties": {
+ "time": {
+ "type": "string",
+ "description": "Time offset in bars as a float >= 0. May be subdivided to half/quarter/8th/16th/32nd notes. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "type": {
+ "type": "integer",
+ "description": "0 = instrument, 1 = drum.",
+ "enum": [
+ 0,
+ 1
+ ]
+ },
+ "bank": {
+ "type": "string",
+ "description": "When `type` is 0, the instrument bank (e.g. bleep, meow, bass). When `type` is 1, always 'drums'.",
+ "knownValues": [
+ "bleep",
+ "meow",
+ "bass",
+ "ping",
+ "string",
+ "reso",
+ "arp",
+ "bark",
+ "mono1",
+ "mono2",
+ "mono3",
+ "funk",
+ "sax",
+ "bell",
+ "roboto",
+ "do",
+ "drums"
+ ],
+ "maxLength": 16
+ },
+ "note": {
+ "type": "string",
+ "description": "When `type` is 0, a pitch like 'B/3' or 'C#/3' (A/-1 through G/8). When `type` is 1, a drum name like 'Kick' or 'Snare'.",
+ "maxLength": 16
+ },
+ "velo": {
+ "type": "integer",
+ "description": "Velocity (loudness) from 0 to 127.",
+ "minimum": 0,
+ "maximum": 127
+ },
+ "duration": {
+ "type": "string",
+ "description": "Duration in bars as a float > 0. Unsupported in current renderers; should be 1. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ }
+ }
+ },
+ "musicBeat": {
+ "type": "object",
+ "description": "A single beat of a music sequence. Wraps the hit array because Lexicon arrays cannot nest directly. The beat's position in `music.instructions` determines its point on the 4:4 timeline.",
+ "required": [
+ "hits"
+ ],
+ "properties": {
+ "hits": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#musicHit"
+ }
+ }
+ }
+ },
+ "music": {
+ "type": "object",
+ "description": "A MIDI-style sequence played by the Byte soundfont. Autoplays and loops. Only one music object is permitted per Byte.",
+ "required": [
+ "frame",
+ "bpm",
+ "length",
+ "instructions"
+ ],
+ "properties": {
+ "frame": {
+ "type": "ref",
+ "ref": "#frame"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "transform": {
+ "type": "ref",
+ "ref": "#transform"
+ },
+ "opacity": {
+ "type": "string",
+ "description": "Alpha value as a float in [0.0, 1.0]. Encoded as a decimal string because Lexicon lacks a float primitive.",
+ "maxLength": 32
+ },
+ "effects": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "#effect"
+ }
+ },
+ "originalSrc": {
+ "type": "string",
+ "format": "uri",
+ "maxLength": 2048
+ },
+ "bpm": {
+ "type": "integer",
+ "description": "Beats per minute. Must be greater than 0.",
+ "minimum": 1
+ },
+ "length": {
+ "type": "integer",
+ "description": "Length of the sequence in bars. Valid values are 2-16 and must be a multiple of 2.",
+ "minimum": 2,
+ "maximum": 16
+ },
+ "instructions": {
+ "type": "array",
+ "description": "The beats of the sequence. Length must be at least (length * 4).",
+ "items": {
+ "type": "ref",
+ "ref": "#musicBeat"
+ },
+ "minLength": 8
+ }
+ }
+ }
+ }
+}
diff --git a/samples/MebiByteTest/lexicons/social/mebibyte/feed/byte.json b/samples/MebiByteTest/lexicons/social/mebibyte/feed/byte.json
new file mode 100644
index 0000000..b9116ae
--- /dev/null
+++ b/samples/MebiByteTest/lexicons/social/mebibyte/feed/byte.json
@@ -0,0 +1,59 @@
+{
+ "lexicon": 1,
+ "id": "social.mebibyte.feed.byte",
+ "defs": {
+ "main": {
+ "type": "record",
+ "description": "A Byte: a multimedia micro-scene authored in the Byte File Format (bff), rendered on a 324x570 stage with top-left-aligned coordinates.",
+ "key": "tid",
+ "record": {
+ "type": "object",
+ "required": ["version", "objects", "createdAt"],
+ "properties": {
+ "version": {
+ "type": "string",
+ "description": "BFF version in 'MAJOR.MINOR' form. MAJOR bumps are incompatible with older renderers; MINOR bumps add backwards-compatible functionality.",
+ "default": "1.1",
+ "maxLength": 16
+ },
+ "background": {
+ "type": "array",
+ "description": "Background color(s) of the Byte. One entry is a solid fill; two entries form a linear gradient. Defaults to a single opaque white ([1,1,1,1]) if omitted.",
+ "items": { "type": "ref", "ref": "social.mebibyte.bff.defs#color" },
+ "minLength": 1,
+ "maxLength": 2
+ },
+ "objects": {
+ "type": "array",
+ "description": "Ordered list of renderable bff objects. Rendered back-to-front in array order.",
+ "items": {
+ "type": "union",
+ "refs": [
+ "social.mebibyte.bff.defs#paragraph",
+ "social.mebibyte.bff.defs#text",
+ "social.mebibyte.bff.defs#link",
+ "social.mebibyte.bff.defs#image",
+ "social.mebibyte.bff.defs#graphic",
+ "social.mebibyte.bff.defs#gif",
+ "social.mebibyte.bff.defs#video",
+ "social.mebibyte.bff.defs#music"
+ ],
+ "closed": false
+ }
+ },
+ "caption": {
+ "type": "string",
+ "description": "Optional caption shown alongside the Byte.",
+ "maxLength": 3000,
+ "maxGraphemes": 300
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Client-declared timestamp when this Byte was originally authored."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/CarpaNet.SourceGen/Generation/CborContextGenerator.cs b/src/CarpaNet.SourceGen/Generation/CborContextGenerator.cs
index 71a0894..b90aa09 100644
--- a/src/CarpaNet.SourceGen/Generation/CborContextGenerator.cs
+++ b/src/CarpaNet.SourceGen/Generation/CborContextGenerator.cs
@@ -537,6 +537,12 @@ private static string GetConverterExpressionForArrayRef(string refString, string
return ListConverterRef(itemTypeName, CborTypeInfoRef(itemTypeName));
}
+ if (itemRefKind == LexiconTypeKind.Array)
+ {
+ var innerConverter = GetConverterExpressionForArrayRef(items.Ref!, arrayNsid, registry);
+ return ListConverterRef(itemTypeName, innerConverter);
+ }
+
var itemConverter = GetPrimitiveConverterForRef(items.Ref!, arrayNsid, registry);
return ListConverterRef(itemTypeName, itemConverter);
}
diff --git a/tests/CarpaNet.UnitTests/Generation/CborContextGeneratorTests.cs b/tests/CarpaNet.UnitTests/Generation/CborContextGeneratorTests.cs
index fa8f01a..70f4061 100644
--- a/tests/CarpaNet.UnitTests/Generation/CborContextGeneratorTests.cs
+++ b/tests/CarpaNet.UnitTests/Generation/CborContextGeneratorTests.cs
@@ -11,10 +11,6 @@ public class CborContextGeneratorTests
[Fact]
public void ArrayOfArrayRef_UsesListConverterNotStringConverter()
{
- // Arrange: reproduce the MebiByte pattern where "transform" is an array
- // of "transformRow" refs, and "transformRow" is itself an array of strings.
- // Without the fix, the inner List element gets a StringCborConverter
- // instead of a CborListTypeInfo.
var registry = new TypeRegistry();
var doc = new LexiconDocument
{
@@ -57,11 +53,59 @@ public void ArrayOfArrayRef_UsesListConverterNotStringConverter()
var result = sb.ToString();
- // Assert: the transform property should wrap the inner List in a
- // CborListTypeInfo, not pass a StringCborConverter directly as the element
- // converter for List>.
- // Correct: CborListTypeInfo>( CborListTypeInfo( StringCborConverter ) )
- // Wrong: CborListTypeInfo>( StringCborConverter )
+ Assert.Contains("new CarpaNet.Cbor.CborListTypeInfo>(new CarpaNet.Cbor.CborListTypeInfo(new CarpaNet.Cbor.Converters.StringCborConverter()))", result);
+ }
+
+ [Fact]
+ public void RefToArrayOfArrayRefs_UsesListConverterNotStringConverter()
+ {
+ var registry = new TypeRegistry();
+ var doc = new LexiconDocument
+ {
+ Id = "test.nested.refarray",
+ Defs = new Dictionary
+ {
+ ["transformRow"] = new LexiconDefinition
+ {
+ Type = "array",
+ Items = new LexiconDefinition { Type = "string" },
+ },
+ ["transform"] = new LexiconDefinition
+ {
+ Type = "array",
+ Items = new LexiconDefinition
+ {
+ Type = "ref",
+ Ref = "#transformRow",
+ },
+ },
+ ["main"] = new LexiconDefinition
+ {
+ Type = "object",
+ Properties = new Dictionary
+ {
+ ["transform"] = new LexiconDefinition
+ {
+ Type = "ref",
+ Ref = "#transform",
+ },
+ },
+ },
+ },
+ };
+ registry.RegisterDocument(doc);
+
+ var sb = new SourceBuilder();
+ var options = new GeneratorOptions();
+ var mainDef = doc.Defs["main"];
+
+ // Act
+ CborContextGenerator.GenerateCborTypeInfo(
+ sb, "TestNested.Refarray.DefsMain", "TestNested_Refarray_DefsMain",
+ mainDef, "test.nested.refarray", registry, options);
+
+ var result = sb.ToString();
+
Assert.Contains("new CarpaNet.Cbor.CborListTypeInfo>(new CarpaNet.Cbor.CborListTypeInfo(new CarpaNet.Cbor.Converters.StringCborConverter()))", result);
}
}