codama-renderers-dart 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/{readme.md → README.md} +38 -42
  2. package/dist/index.browser.cjs +628 -147
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +628 -148
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.node.cjs +628 -147
  7. package/dist/index.node.cjs.map +1 -1
  8. package/dist/index.node.js +628 -148
  9. package/dist/index.node.js.map +1 -1
  10. package/dist/index.react-native.js +628 -148
  11. package/dist/index.react-native.js.map +1 -1
  12. package/dist/types/fragments/accountPage.d.ts.map +1 -1
  13. package/dist/types/fragments/instructionPage.d.ts.map +1 -1
  14. package/dist/types/fragments/typePage.d.ts.map +1 -1
  15. package/dist/types/index.d.ts +1 -0
  16. package/dist/types/index.d.ts.map +1 -1
  17. package/dist/types/utils/discriminators.d.ts +10 -0
  18. package/dist/types/utils/discriminators.d.ts.map +1 -0
  19. package/dist/types/utils/exactDecoder.d.ts +17 -0
  20. package/dist/types/utils/exactDecoder.d.ts.map +1 -0
  21. package/dist/types/utils/formatCode.d.ts +1 -1
  22. package/dist/types/utils/formatCode.d.ts.map +1 -1
  23. package/dist/types/utils/index.d.ts +4 -0
  24. package/dist/types/utils/index.d.ts.map +1 -1
  25. package/dist/types/utils/nameTransformers.d.ts +5 -0
  26. package/dist/types/utils/nameTransformers.d.ts.map +1 -1
  27. package/dist/types/utils/normalizeRootNode.d.ts +11 -0
  28. package/dist/types/utils/normalizeRootNode.d.ts.map +1 -0
  29. package/dist/types/utils/valueNodes.d.ts +16 -0
  30. package/dist/types/utils/valueNodes.d.ts.map +1 -0
  31. package/dist/types/visitors/getTypeManifestVisitor.d.ts +1 -1
  32. package/dist/types/visitors/getTypeManifestVisitor.d.ts.map +1 -1
  33. package/dist/types/visitors/renderVisitor.d.ts.map +1 -1
  34. package/package.json +21 -18
  35. package/src/fragments/accountPage.ts +90 -17
  36. package/src/fragments/instructionPage.ts +112 -79
  37. package/src/fragments/typePage.ts +134 -31
  38. package/src/index.ts +1 -0
  39. package/src/utils/discriminators.ts +121 -0
  40. package/src/utils/exactDecoder.ts +82 -0
  41. package/src/utils/formatCode.ts +7 -11
  42. package/src/utils/index.ts +4 -0
  43. package/src/utils/nameTransformers.ts +28 -1
  44. package/src/utils/normalizeRootNode.ts +76 -0
  45. package/src/utils/valueNodes.ts +87 -0
  46. package/src/visitors/getRenderMapVisitor.ts +1 -1
  47. package/src/visitors/getTypeManifestVisitor.ts +37 -14
  48. package/src/visitors/renderVisitor.ts +4 -1
@@ -12,13 +12,71 @@ var errors = require('@codama/errors');
12
12
 
13
13
  // src/visitors/renderVisitor.ts
14
14
  function formatDartDirectory(dir) {
15
- try {
16
- child_process.execSync(`dart format --fix "${dir}"`, {
17
- encoding: "utf-8",
18
- timeout: 6e4,
19
- stdio: ["pipe", "pipe", "pipe"]
20
- });
21
- } catch {
15
+ child_process.execSync(`dart format "${dir}"`, {
16
+ encoding: "utf-8",
17
+ timeout: 6e4,
18
+ stdio: ["pipe", "pipe", "pipe"]
19
+ });
20
+ }
21
+
22
+ // src/utils/normalizeRootNode.ts
23
+ function normalizeRootNode(root) {
24
+ return normalizeNode(root);
25
+ }
26
+ function normalizeNode(value) {
27
+ if (Array.isArray(value)) {
28
+ return value.map(normalizeNode);
29
+ }
30
+ if (!isRecord(value)) {
31
+ return value;
32
+ }
33
+ const normalized = Object.fromEntries(
34
+ Object.entries(value).map(([key, child]) => [key, normalizeNode(child)])
35
+ );
36
+ switch (normalized.kind) {
37
+ case "rootNode":
38
+ setEmptyCollection(normalized, "additionalPrograms");
39
+ break;
40
+ case "programNode":
41
+ setEmptyCollection(normalized, "accounts");
42
+ setEmptyCollection(normalized, "constants");
43
+ setEmptyCollection(normalized, "definedTypes");
44
+ setEmptyCollection(normalized, "errors");
45
+ setEmptyCollection(normalized, "events");
46
+ setEmptyCollection(normalized, "instructions");
47
+ setEmptyCollection(normalized, "pdas");
48
+ break;
49
+ case "instructionNode":
50
+ setEmptyCollection(normalized, "accounts");
51
+ setEmptyCollection(normalized, "arguments");
52
+ break;
53
+ case "pdaNode":
54
+ setEmptyCollection(normalized, "seeds");
55
+ break;
56
+ case "structTypeNode":
57
+ setEmptyCollection(normalized, "fields");
58
+ break;
59
+ case "enumTypeNode":
60
+ setEmptyCollection(normalized, "variants");
61
+ break;
62
+ case "tupleTypeNode":
63
+ setEmptyCollection(normalized, "items");
64
+ break;
65
+ case "hiddenPrefixTypeNode":
66
+ setEmptyCollection(normalized, "prefix");
67
+ break;
68
+ case "hiddenSuffixTypeNode":
69
+ setEmptyCollection(normalized, "suffix");
70
+ break;
71
+ }
72
+ return normalized;
73
+ }
74
+ function isRecord(value) {
75
+ return typeof value === "object" && value !== null;
76
+ }
77
+ function setEmptyCollection(record, key) {
78
+ if (record[key] === void 0) {
79
+ record[key] = [];
22
80
  }
23
81
  }
24
82
 
@@ -26,9 +84,83 @@ function formatDartDirectory(dir) {
26
84
  function pascalCase(str) {
27
85
  return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (c) => c.toUpperCase());
28
86
  }
87
+ var DART_RESERVED_WORDS = /* @__PURE__ */ new Set([
88
+ "abstract",
89
+ "as",
90
+ "assert",
91
+ "async",
92
+ "augment",
93
+ "await",
94
+ "base",
95
+ "break",
96
+ "case",
97
+ "catch",
98
+ "class",
99
+ "const",
100
+ "continue",
101
+ "covariant",
102
+ "default",
103
+ "deferred",
104
+ "do",
105
+ "dynamic",
106
+ "else",
107
+ "enum",
108
+ "export",
109
+ "extends",
110
+ "extension",
111
+ "external",
112
+ "factory",
113
+ "false",
114
+ "final",
115
+ "finally",
116
+ "for",
117
+ "get",
118
+ "hide",
119
+ "if",
120
+ "implements",
121
+ "import",
122
+ "in",
123
+ "interface",
124
+ "is",
125
+ "late",
126
+ "library",
127
+ "mixin",
128
+ "native",
129
+ "new",
130
+ "null",
131
+ "of",
132
+ "on",
133
+ "operator",
134
+ "part",
135
+ "required",
136
+ "rethrow",
137
+ "return",
138
+ "sealed",
139
+ "set",
140
+ "show",
141
+ "static",
142
+ "super",
143
+ "switch",
144
+ "sync",
145
+ "this",
146
+ "throw",
147
+ "true",
148
+ "try",
149
+ "typedef",
150
+ "var",
151
+ "void",
152
+ "when",
153
+ "while",
154
+ "with",
155
+ "yield"
156
+ ]);
157
+ function escapeDartIdentifier(name) {
158
+ return DART_RESERVED_WORDS.has(name) ? `${name}_` : name;
159
+ }
29
160
  function camelCase(str) {
30
161
  const pascal = pascalCase(str);
31
- return pascal.charAt(0).toLowerCase() + pascal.slice(1);
162
+ const cased = pascal.charAt(0).toLowerCase() + pascal.slice(1);
163
+ return escapeDartIdentifier(cased);
32
164
  }
33
165
  function snakeCase(str) {
34
166
  return str.replace(/([A-Z])/g, "_$1").replace(/[-\s]+/g, "_").replace(/^_/, "").replace(/_+/g, "_").toLowerCase();
@@ -208,17 +340,6 @@ function use(typeName, module) {
208
340
  return { content: typeName, imports };
209
341
  }
210
342
 
211
- // src/utils/typeManifest.ts
212
- function emptyTypeManifest() {
213
- return {
214
- type: emptyFragment(),
215
- encoder: emptyFragment(),
216
- decoder: emptyFragment(),
217
- value: emptyFragment(),
218
- isEnum: false
219
- };
220
- }
221
-
222
343
  // src/utils/wellKnownAddresses.ts
223
344
  var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
224
345
  // Agave / Solana native programs
@@ -273,6 +394,207 @@ var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
273
394
  ["Es9vMFrzaCERm6YKXx6bqKr1Rmd9b5v3J8rM5e4rfF4", "usdtAddress"]
274
395
  ]);
275
396
 
397
+ // src/utils/valueNodes.ts
398
+ function getDartValueFragment(value, dartType) {
399
+ switch (value.kind) {
400
+ case "numberValueNode":
401
+ return fragmentFromString(
402
+ dartType === "BigInt" ? `BigInt.from(${value.number})` : String(value.number)
403
+ );
404
+ case "booleanValueNode":
405
+ return fragmentFromString(String(value.boolean));
406
+ case "stringValueNode":
407
+ return fragmentFromString(toDartStringLiteral(value.string));
408
+ case "noneValueNode":
409
+ return fragmentFromString("null");
410
+ case "bytesValueNode": {
411
+ if (value.encoding !== "base16") {
412
+ throw new Error(
413
+ `Unsupported deterministic bytes encoding: ${value.encoding}`
414
+ );
415
+ }
416
+ const clean = value.data.replace(/^0x/, "");
417
+ if (clean.length % 2 !== 0 || !/^[0-9a-f]*$/i.test(clean)) {
418
+ throw new Error(`Invalid hexadecimal bytes value: ${value.data}`);
419
+ }
420
+ const bytes = clean.match(/.{2}/g)?.map((byte) => `0x${byte}`) ?? [];
421
+ return fragment`${use("Uint8List", "dartTypedData")}.fromList([${fragmentFromString(bytes.join(", "))}])`;
422
+ }
423
+ case "publicKeyValueNode": {
424
+ const wellKnownName = WELL_KNOWN_ADDRESSES.get(value.publicKey);
425
+ return wellKnownName ? fragment`${use(wellKnownName, "solanaAddresses")}` : fragment`${use("Address", "solanaAddresses")}(${fragmentFromString(toDartStringLiteral(value.publicKey))})`;
426
+ }
427
+ default:
428
+ throw new Error(
429
+ `Unsupported deterministic Dart value node: ${value.kind}`
430
+ );
431
+ }
432
+ }
433
+ function isConstDartValueNode(value) {
434
+ switch (value.kind) {
435
+ case "numberValueNode":
436
+ case "booleanValueNode":
437
+ case "stringValueNode":
438
+ case "noneValueNode":
439
+ case "publicKeyValueNode":
440
+ return true;
441
+ default:
442
+ return false;
443
+ }
444
+ }
445
+ function toDartStringLiteral(value) {
446
+ return `'${value.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t").replaceAll("\b", "\\b").replaceAll("\f", "\\f").replaceAll("$", "\\$").replaceAll("'", "\\'")}'`;
447
+ }
448
+
449
+ // src/utils/discriminators.ts
450
+ function getDiscriminatorValidationFragment(node, scope) {
451
+ const discriminators = node.discriminators ?? [];
452
+ if (discriminators.length === 0) return emptyFragment();
453
+ const fields = getDiscriminatorFields(node);
454
+ const fragments = discriminators.map((discriminator) => {
455
+ switch (discriminator.kind) {
456
+ case "constantDiscriminatorNode":
457
+ return getConstantValidationFragment(
458
+ discriminator.constant,
459
+ discriminator.offset,
460
+ scope
461
+ );
462
+ case "fieldDiscriminatorNode": {
463
+ const field = fields.find(
464
+ (candidate) => candidate.name === discriminator.name
465
+ );
466
+ if (field?.defaultValue == null) {
467
+ throw new Error(
468
+ `Field discriminator "${discriminator.name}" on ${node.kind} "${node.name}" must reference a field with a default value.`
469
+ );
470
+ }
471
+ return getConstantValidationFragment(
472
+ {
473
+ type: field.type,
474
+ value: field.defaultValue
475
+ },
476
+ discriminator.offset,
477
+ scope
478
+ );
479
+ }
480
+ case "sizeDiscriminatorNode": {
481
+ if (!Number.isSafeInteger(discriminator.size) || discriminator.size < 0) {
482
+ throw new Error(
483
+ `Discriminator size must be a non-negative safe integer, got ${discriminator.size}.`
484
+ );
485
+ }
486
+ return fragment`if (bytes.length - offset != ${fragmentFromString(String(discriminator.size))}) {
487
+ throw ${use("SolanaError", "solanaErrors")}(
488
+ ${use("SolanaErrorCode", "solanaErrors")}.codecsInvalidByteLength,
489
+ {
490
+ 'codecDescription': '${fragmentFromString(node.name)} discriminator',
491
+ 'expected': ${fragmentFromString(String(discriminator.size))},
492
+ 'bytesLength': bytes.length - offset,
493
+ },
494
+ );
495
+ }`;
496
+ }
497
+ }
498
+ });
499
+ return mergeFragments(fragments, (contents) => contents.join("\n"));
500
+ }
501
+ function getConstantValidationFragment(constant, discriminatorOffset, scope) {
502
+ if (!Number.isSafeInteger(discriminatorOffset) || discriminatorOffset < 0) {
503
+ throw new Error(
504
+ `Discriminator offset must be a non-negative safe integer, got ${discriminatorOffset}.`
505
+ );
506
+ }
507
+ const manifest = visitorsCore.visit(constant.type, scope.typeManifestVisitor);
508
+ const value = getDartValueFragment(
509
+ constant.value,
510
+ manifest.type.content
511
+ );
512
+ return fragment`${use("getConstantDecoder", "solanaCodecsDataStructures")}(
513
+ ${manifest.encoder}.encode(${value}),
514
+ ).read(bytes, offset + ${fragmentFromString(String(discriminatorOffset))});`;
515
+ }
516
+ function getDiscriminatorFields(node) {
517
+ if (node.kind === "accountNode") {
518
+ return nodes.resolveNestedTypeNode(node.data).fields ?? [];
519
+ }
520
+ return (node.arguments ?? []).map(
521
+ (argument) => ({
522
+ ...argument,
523
+ kind: "structFieldTypeNode"
524
+ })
525
+ );
526
+ }
527
+
528
+ // src/utils/exactDecoder.ts
529
+ function getTopLevelDecoderFragment({
530
+ typeName,
531
+ description,
532
+ discriminatorValidation,
533
+ fromMapFields,
534
+ requireExactConsumption
535
+ }) {
536
+ const validation = discriminatorValidation.content ? ` ${discriminatorValidation.content.replaceAll("\n", "\n ")}
537
+ ` : "";
538
+ const consumptionCheck = requireExactConsumption ? ` if (newOffset != bytes.length) {
539
+ throwInvalidByteLength(newOffset - offset, bytes.length - offset);
540
+ }
541
+ ` : "";
542
+ const fixedSizeCheck = requireExactConsumption ? "bytesLength != structDecoder.fixedSize" : "bytesLength < structDecoder.fixedSize";
543
+ const result = fragment` Never throwInvalidByteLength(int expected, int bytesLength) {
544
+ throw ${use("SolanaError", "solanaErrors")}(
545
+ ${use("SolanaErrorCode", "solanaErrors")}.codecsInvalidByteLength,
546
+ {
547
+ 'codecDescription': '${fragmentFromString(description)}',
548
+ 'expected': expected,
549
+ 'bytesLength': bytesLength,
550
+ },
551
+ );
552
+ }
553
+
554
+ (${fragmentFromString(typeName)}, int) readTopLevel(Uint8List bytes, int offset) {
555
+ ${fragmentFromString(validation)} final (map, newOffset) = structDecoder.read(bytes, offset);
556
+ ${fragmentFromString(consumptionCheck)}
557
+ return (
558
+ ${fragmentFromString(typeName)}(
559
+ ${fragmentFromString(fromMapFields)}
560
+ ),
561
+ newOffset,
562
+ );
563
+ }
564
+
565
+ return switch (structDecoder) {
566
+ ${use("FixedSizeDecoder", "solanaCodecsCore")}<Map<String, Object?>>() =>
567
+ ${use("FixedSizeDecoder", "solanaCodecsCore")}<${fragmentFromString(typeName)}>(
568
+ fixedSize: structDecoder.fixedSize,
569
+ read: (bytes, offset) {
570
+ final bytesLength = bytes.length - offset;
571
+ if (${fragmentFromString(fixedSizeCheck)}) {
572
+ throwInvalidByteLength(structDecoder.fixedSize, bytesLength);
573
+ }
574
+ return readTopLevel(bytes, offset);
575
+ },
576
+ ),
577
+ ${use("VariableSizeDecoder", "solanaCodecsCore")}<Map<String, Object?>>() =>
578
+ ${use("VariableSizeDecoder", "solanaCodecsCore")}<${fragmentFromString(typeName)}>(
579
+ read: readTopLevel,
580
+ maxSize: structDecoder.maxSize,
581
+ ),
582
+ };`;
583
+ result.imports.mergeWith(discriminatorValidation.imports);
584
+ return result;
585
+ }
586
+
587
+ // src/utils/typeManifest.ts
588
+ function emptyTypeManifest() {
589
+ return {
590
+ type: emptyFragment(),
591
+ encoder: emptyFragment(),
592
+ decoder: emptyFragment(),
593
+ value: emptyFragment(),
594
+ isEnum: false
595
+ };
596
+ }
597
+
276
598
  // src/visitors/getTypeManifestVisitor.ts
277
599
  function getTypeManifestVisitor(input) {
278
600
  const { nameApi, linkables, nonScalarEnums = [] } = input;
@@ -416,12 +738,17 @@ function getTypeManifestVisitor(input) {
416
738
  const itemManifest = visitorsCore.visit(node.item, self);
417
739
  const encoderSizeExpr = getArraySizeExpression(node, "Encoder");
418
740
  const decoderSizeExpr = getArraySizeExpression(node, "Decoder");
741
+ const itemType = fragmentFromString(itemManifest.type.content);
742
+ const itemEncoder = fragment`${use(
743
+ "transformEncoder",
744
+ "solanaCodecsCore"
745
+ )}(${itemManifest.encoder}, (${itemType} value) => value)`;
419
746
  return {
420
747
  type: fragment`List<${itemManifest.type}>`,
421
748
  encoder: fragment`${use(
422
749
  "getArrayEncoder",
423
750
  "solanaCodecsDataStructures"
424
- )}(${itemManifest.encoder}${encoderSizeExpr})`,
751
+ )}(${itemEncoder}${encoderSizeExpr})`,
425
752
  decoder: fragment`${use(
426
753
  "getArrayDecoder",
427
754
  "solanaCodecsDataStructures"
@@ -468,7 +795,7 @@ function getTypeManifestVisitor(input) {
468
795
  };
469
796
  },
470
797
  visitTupleType(node, { self }) {
471
- const itemManifests = node.items.map((item) => visitorsCore.visit(item, self));
798
+ const itemManifests = (node.items ?? []).map((item) => visitorsCore.visit(item, self));
472
799
  const typeList = itemManifests.map((m) => m.type.content).join(", ");
473
800
  const encoderList = itemManifests.map((m) => m.encoder);
474
801
  const decoderList = itemManifests.map((m) => m.decoder);
@@ -477,18 +804,28 @@ function getTypeManifestVisitor(input) {
477
804
  typeFragment.imports.mergeWith(m.type.imports);
478
805
  }
479
806
  const encoderListStr = encoderList.map((e) => e.content).join(", ");
807
+ const decoderListStr = decoderList.map((d) => d.content).join(", ");
808
+ let tupleEncoderFn = "getTupleEncoder";
809
+ let tupleDecoderFn = "getTupleDecoder";
810
+ let tupleEncoderArgs = `[${encoderListStr}]`;
811
+ let tupleDecoderArgs = `[${decoderListStr}]`;
812
+ if (itemManifests.length === 2) {
813
+ tupleEncoderFn = "getTuple2Encoder";
814
+ tupleDecoderFn = "getTuple2Decoder";
815
+ tupleEncoderArgs = encoderListStr;
816
+ tupleDecoderArgs = decoderListStr;
817
+ }
480
818
  const encoderFrag = fragment`${use(
481
- "getTupleEncoder",
819
+ tupleEncoderFn,
482
820
  "solanaCodecsDataStructures"
483
- )}([${fragmentFromString(encoderListStr)}])`;
821
+ )}(${tupleEncoderArgs})`;
484
822
  for (const e of encoderList) {
485
823
  encoderFrag.imports.mergeWith(e.imports);
486
824
  }
487
- const decoderListStr = decoderList.map((d) => d.content).join(", ");
488
825
  const decoderFrag = fragment`${use(
489
- "getTupleDecoder",
826
+ tupleDecoderFn,
490
827
  "solanaCodecsDataStructures"
491
- )}([${fragmentFromString(decoderListStr)}])`;
828
+ )}(${tupleDecoderArgs})`;
492
829
  for (const d of decoderList) {
493
830
  decoderFrag.imports.mergeWith(d.imports);
494
831
  }
@@ -501,8 +838,9 @@ function getTypeManifestVisitor(input) {
501
838
  };
502
839
  },
503
840
  visitStructType(node, { self }) {
504
- const fields = node.fields.map((f) => visitorsCore.visit(f, self));
505
- const fieldNames = node.fields.map((f) => f.name);
841
+ const nodeFields = node.fields ?? [];
842
+ const fields = nodeFields.map((f) => visitorsCore.visit(f, self));
843
+ const fieldNames = nodeFields.map((f) => f.name);
506
844
  const typeStr = "Map<String, Object?>";
507
845
  const encoderFields = fields.map((f, i) => `('${fieldNames[i]}', ${f.encoder.content})`).join(", ");
508
846
  const encoderFrag = fragment`${use(
@@ -532,7 +870,7 @@ function getTypeManifestVisitor(input) {
532
870
  return visitorsCore.visit(node.type, self);
533
871
  },
534
872
  visitEnumType(node, { self }) {
535
- const isScalar = node.variants.every(
873
+ const isScalar = (node.variants ?? []).every(
536
874
  (v) => v.kind === "enumEmptyVariantTypeNode"
537
875
  );
538
876
  if (isScalar) {
@@ -574,7 +912,10 @@ function getTypeManifestVisitor(input) {
574
912
  encoder: fragment`${use(
575
913
  "getNullableEncoder",
576
914
  "solanaCodecsDataStructures"
577
- )}<${fragmentFromString(itemTypeStr)}>(${itemManifest.encoder}${fragmentFromString(prefixExpr)}${fragmentFromString(noneValueExpr)})`,
915
+ )}<${fragmentFromString(itemTypeStr)}>(${use(
916
+ "transformEncoder",
917
+ "solanaCodecsCore"
918
+ )}(${itemManifest.encoder}, (${fragmentFromString(itemTypeStr)} value) => value)${fragmentFromString(prefixExpr)}${fragmentFromString(noneValueExpr)})`,
578
919
  decoder: fragment`${use(
579
920
  "getNullableDecoder",
580
921
  "solanaCodecsDataStructures"
@@ -624,7 +965,7 @@ function getTypeManifestVisitor(input) {
624
965
  encoder: fragment`${use(
625
966
  "fixEncoderSize",
626
967
  "solanaCodecsCore"
627
- )}(${innerManifest.encoder}, ${fragmentFromString(String(node.size))})`,
968
+ )}(${innerManifest.encoder}, ${fragmentFromString(String(node.size))}, allowTruncation: false)`,
628
969
  decoder: fragment`${use(
629
970
  "fixDecoderSize",
630
971
  "solanaCodecsCore"
@@ -662,7 +1003,7 @@ function getTypeManifestVisitor(input) {
662
1003
  },
663
1004
  visitHiddenPrefixType(node, { self }) {
664
1005
  const innerManifest = visitorsCore.visit(node.type, self);
665
- const prefixes = node.prefix.map((p) => getHiddenAffixManifest(p, self));
1006
+ const prefixes = (node.prefix ?? []).map((p) => getHiddenAffixManifest(p, self));
666
1007
  const prefixEncoders = prefixes.map((p) => p.encoder.content).join(", ");
667
1008
  const prefixDecoders = prefixes.map((p) => p.decoder.content).join(", ");
668
1009
  const encoderFrag = fragment`${use(
@@ -689,7 +1030,7 @@ function getTypeManifestVisitor(input) {
689
1030
  },
690
1031
  visitHiddenSuffixType(node, { self }) {
691
1032
  const innerManifest = visitorsCore.visit(node.type, self);
692
- const suffixes = node.suffix.map((s) => getHiddenAffixManifest(s, self));
1033
+ const suffixes = (node.suffix ?? []).map((s) => getHiddenAffixManifest(s, self));
693
1034
  const suffixEncoders = suffixes.map((s) => s.encoder.content).join(", ");
694
1035
  const suffixDecoders = suffixes.map((s) => s.decoder.content).join(", ");
695
1036
  const encoderFrag = fragment`${use(
@@ -976,19 +1317,52 @@ function hexToBytes(hex) {
976
1317
  function getAccountPageFragment(node, scope) {
977
1318
  const name = node.name;
978
1319
  const typeName = scope.nameApi.dataType(name);
979
- const dataNode = nodes.resolveNestedTypeNode(node.data);
980
- const fields = dataNode.fields;
1320
+ const fields = nodes.resolveNestedTypeNode(node.data).fields ?? [];
981
1321
  const fieldManifests = fields.map((f) => ({
982
1322
  field: f,
983
1323
  manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
984
1324
  }));
1325
+ const omittedFields = fields.filter(isOmittedDefaultField);
1326
+ const constructorFields = fields.filter(
1327
+ (field) => !isOmittedDefaultField(field)
1328
+ );
1329
+ const forcedFields = /* @__PURE__ */ new Set([
1330
+ ...omittedFields,
1331
+ ...fields.filter((field) => isFieldDiscriminator(field, node))
1332
+ ]);
1333
+ const fieldDefaults = new Map(
1334
+ fieldManifests.flatMap(({ field, manifest }) => {
1335
+ if (!forcedFields.has(field) || field.defaultValue == null) return [];
1336
+ return [
1337
+ [
1338
+ field,
1339
+ getDartValueFragment(field.defaultValue, manifest.type.content)
1340
+ ]
1341
+ ];
1342
+ })
1343
+ );
1344
+ for (const field of forcedFields) {
1345
+ if (!fieldDefaults.has(field)) {
1346
+ throw new Error(
1347
+ `Forced field "${field.name}" on account "${node.name}" must have a deterministic default value.`
1348
+ );
1349
+ }
1350
+ }
985
1351
  const fieldDecls = fieldManifests.map(({ field: f, manifest }) => {
986
1352
  return ` final ${manifest.type.content} ${camelCase(f.name)};`;
987
1353
  }).join("\n");
988
- const ctorParams = fields.map((f) => ` required this.${camelCase(f.name)},`).join("\n");
989
- const ctorSignature = fields.length === 0 ? `const ${typeName}();` : `const ${typeName}({
1354
+ const ctorParams = constructorFields.map((f) => ` required this.${camelCase(f.name)},`).join("\n");
1355
+ const ctorInitializers = omittedFields.map((field) => {
1356
+ const fieldName = camelCase(field.name);
1357
+ return `${fieldName} = ${fieldDefaults.get(field).content}`;
1358
+ }).join(",\n ");
1359
+ const ctorKeyword = omittedFields.every(
1360
+ (field) => isConstDartValueNode(field.defaultValue)
1361
+ ) ? "const " : "";
1362
+ const ctorSignature = constructorFields.length === 0 ? `${ctorKeyword}${typeName}()${ctorInitializers ? ` : ${ctorInitializers}` : ""};` : `${ctorKeyword}${typeName}({
990
1363
  ${ctorParams}
991
- });`;
1364
+ })${ctorInitializers ? ` :
1365
+ ${ctorInitializers}` : ""};`;
992
1366
  const eqChecks = fields.length === 0 ? "true" : fields.map(
993
1367
  (f) => `${camelCase(f.name)} == other.${camelCase(f.name)}`
994
1368
  ).join(" &&\n ");
@@ -1003,10 +1377,11 @@ ${ctorParams}
1003
1377
  const decFields = fieldManifests.map(({ field: f, manifest }) => {
1004
1378
  return ` ('${f.name}', ${manifest.decoder.content}),`;
1005
1379
  }).join("\n");
1006
- const toMapFields = fields.map(
1007
- (f) => ` '${f.name}': value.${camelCase(f.name)},`
1008
- ).join("\n");
1009
- const fromMapFields = fieldManifests.map(({ field: f, manifest }) => {
1380
+ const toMapFields = fields.map((f) => {
1381
+ const value = forcedFields.has(f) ? fieldDefaults.get(f).content : `value.${camelCase(f.name)}`;
1382
+ return ` '${f.name}': ${value},`;
1383
+ }).join("\n");
1384
+ const fromMapFields = fieldManifests.filter(({ field }) => !isOmittedDefaultField(field)).map(({ field: f, manifest }) => {
1010
1385
  const typeStr = manifest.type.content;
1011
1386
  const isNullable = typeStr.endsWith("?");
1012
1387
  const accessor = isNullable ? `map['${f.name}']` : `map['${f.name}']!`;
@@ -1020,6 +1395,19 @@ ${ctorParams}
1020
1395
  /// The size of the [${fragmentFromString(typeName)}] account data in bytes.
1021
1396
  const int ${fragmentFromString(scope.nameApi.accountSizeConstant(name))} = ${fragmentFromString(String(node.size))};` : emptyFragment();
1022
1397
  const discFragment = getDiscriminatorConstantsFragment(node, scope);
1398
+ const discriminatorValidation = getDiscriminatorValidationFragment(
1399
+ node,
1400
+ scope
1401
+ );
1402
+ const topLevelDecoder = getTopLevelDecoderFragment({
1403
+ typeName,
1404
+ description: `${name} account decoder`,
1405
+ discriminatorValidation,
1406
+ fromMapFields,
1407
+ requireExactConsumption: (node.discriminators ?? []).some(
1408
+ (discriminator) => discriminator.kind === "sizeDiscriminatorNode"
1409
+ )
1410
+ });
1023
1411
  const parts = [
1024
1412
  fragment`// Auto-generated. Do not edit.
1025
1413
  // ignore_for_file: type=lint
@@ -1079,12 +1467,7 @@ Decoder<${fragmentFromString(typeName)}> ${fragmentFromString(decoderName)}() {
1079
1467
  ${fragmentFromString(decFields)}
1080
1468
  ]);
1081
1469
 
1082
- return transformDecoder(
1083
- structDecoder,
1084
- (Map<String, Object?> map, Uint8List bytes, int offset) => ${fragmentFromString(typeName)}(
1085
- ${fragmentFromString(fromMapFields)}
1086
- ),
1087
- );
1470
+ ${topLevelDecoder}
1088
1471
  }
1089
1472
 
1090
1473
  Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragmentFromString(codecName)}() {
@@ -1100,8 +1483,19 @@ Account<${fragmentFromString(typeName)}> ${fragmentFromString(decodeFnName)}(Enc
1100
1483
  result.imports.mergeWith(manifest.decoder.imports);
1101
1484
  result.imports.mergeWith(manifest.type.imports);
1102
1485
  }
1486
+ for (const defaultValue of fieldDefaults.values()) {
1487
+ result.imports.mergeWith(defaultValue.imports);
1488
+ }
1103
1489
  return result;
1104
1490
  }
1491
+ function isOmittedDefaultField(field) {
1492
+ return field.defaultValue != null && field.defaultValueStrategy === "omitted";
1493
+ }
1494
+ function isFieldDiscriminator(field, node) {
1495
+ return (node.discriminators ?? []).some(
1496
+ (discriminator) => discriminator.kind === "fieldDiscriminatorNode" && discriminator.name === field.name
1497
+ );
1498
+ }
1105
1499
 
1106
1500
  // src/fragments/errorPage.ts
1107
1501
  function getErrorPageFragment(programNode, scope) {
@@ -1162,7 +1556,7 @@ function getIndexPageFragment(fileNames, relativePath = "") {
1162
1556
  "// Auto-generated. Do not edit.\n// ignore_for_file: type=lint\n"
1163
1557
  );
1164
1558
  }
1165
- const exports$1 = fileNames.sort().map((f) => {
1559
+ const exports = fileNames.sort().map((f) => {
1166
1560
  const path = relativePath ? `${relativePath}/${f}` : f;
1167
1561
  return `export '${path}';`;
1168
1562
  }).join("\n");
@@ -1170,17 +1564,17 @@ function getIndexPageFragment(fileNames, relativePath = "") {
1170
1564
  `// Auto-generated. Do not edit.
1171
1565
  // ignore_for_file: type=lint
1172
1566
 
1173
- ${exports$1}
1567
+ ${exports}
1174
1568
  `
1175
1569
  );
1176
1570
  }
1177
1571
  function getRootIndexPageFragment(categories) {
1178
- const exports$1 = categories.sort().map((cat) => `export '${cat}/${cat}.dart';`).join("\n");
1572
+ const exports = categories.sort().map((cat) => `export '${cat}/${cat}.dart';`).join("\n");
1179
1573
  return fragmentFromString(
1180
1574
  `// Auto-generated. Do not edit.
1181
1575
  // ignore_for_file: type=lint
1182
1576
 
1183
- ${exports$1}
1577
+ ${exports}
1184
1578
  `
1185
1579
  );
1186
1580
  }
@@ -1190,30 +1584,62 @@ function getInstructionPageFragment(node, scope) {
1190
1584
  const instrFnName = scope.nameApi.instructionFunction(name);
1191
1585
  const parseFnName = scope.nameApi.instructionParseFunction(name);
1192
1586
  const accounts = node.accounts ?? [];
1193
- const args = (node.arguments ?? []).filter(
1194
- (arg) => !isDiscriminatorArg(arg, node)
1195
- );
1196
1587
  const allArgs = node.arguments ?? [];
1588
+ const optionalAccountStrategy = node.optionalAccountStrategy ?? "programId";
1589
+ if (optionalAccountStrategy !== "programId" && optionalAccountStrategy !== "omitted") {
1590
+ throw new Error(
1591
+ `Unsupported optional account strategy on instruction "${node.name}": ${optionalAccountStrategy}`
1592
+ );
1593
+ }
1594
+ const args = allArgs.filter(
1595
+ (arg) => !isDiscriminatorArg(arg, node) && !isOmittedDefaultArgument(arg)
1596
+ );
1197
1597
  const dataClassName = `${typeName}InstructionData`;
1198
- const allArgManifests = allArgs.map((arg) => ({
1598
+ const allArgManifests = (node.arguments ?? []).map((arg) => ({
1199
1599
  arg,
1200
1600
  manifest: visitorsCore.visit(arg.type, scope.typeManifestVisitor)
1201
1601
  }));
1602
+ const argDefaultValues = new Map(
1603
+ allArgManifests.flatMap(({ arg, manifest }) => {
1604
+ if (arg.defaultValue == null) return [];
1605
+ const needsRenderedDefault = isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node) || arg.defaultValue.kind !== "accountBumpValueNode";
1606
+ if (!needsRenderedDefault) return [];
1607
+ return [
1608
+ [
1609
+ arg,
1610
+ getDartValueFragment(arg.defaultValue, manifest.type.content)
1611
+ ]
1612
+ ];
1613
+ })
1614
+ );
1615
+ for (const arg of allArgs.filter(
1616
+ (candidate) => isDiscriminatorArg(candidate, node)
1617
+ )) {
1618
+ if (!argDefaultValues.has(arg)) {
1619
+ throw new Error(
1620
+ `Field discriminator "${arg.name}" on instruction "${node.name}" must reference a field with a default value.`
1621
+ );
1622
+ }
1623
+ }
1202
1624
  const dataFieldDecls = allArgManifests.map(({ arg, manifest }) => {
1203
1625
  const fieldName = camelCase(arg.name);
1204
1626
  return ` final ${manifest.type.content} ${fieldName};`;
1205
1627
  }).join("\n");
1206
1628
  const dataCtorParams = allArgManifests.map(({ arg, manifest }) => {
1207
1629
  const fieldName = camelCase(arg.name);
1630
+ if (isOmittedDefaultArgument(arg)) return "";
1208
1631
  if (isDiscriminatorArg(arg, node)) {
1209
- return isConstDefaultValue(arg.defaultValue) ? ` this.${fieldName} = ${getDiscriminatorDefault(arg)},` : ` ${manifest.type.content}? ${fieldName},`;
1632
+ return isConstDefaultValue(arg.defaultValue) ? ` this.${fieldName} = ${argDefaultValues.get(arg).content},` : ` ${manifest.type.content}? ${fieldName},`;
1210
1633
  }
1211
1634
  return ` required this.${fieldName},`;
1212
- }).join("\n");
1635
+ }).filter(Boolean).join("\n");
1213
1636
  const dataCtorInitializers = allArgManifests.map(({ arg }) => {
1214
1637
  const fieldName = camelCase(arg.name);
1638
+ if (isOmittedDefaultArgument(arg)) {
1639
+ return ` ${fieldName} = ${argDefaultValues.get(arg).content}`;
1640
+ }
1215
1641
  if (isDiscriminatorArg(arg, node) && !isConstDefaultValue(arg.defaultValue)) {
1216
- return ` ${fieldName} = ${fieldName} ?? ${getDiscriminatorDefault(arg)}`;
1642
+ return ` ${fieldName} = ${fieldName} ?? ${argDefaultValues.get(arg).content}`;
1217
1643
  }
1218
1644
  return null;
1219
1645
  }).filter((value) => value !== null).join(",\n");
@@ -1223,16 +1649,26 @@ function getInstructionPageFragment(node, scope) {
1223
1649
  const decFields = allArgManifests.map(({ arg, manifest }) => {
1224
1650
  return ` ('${arg.name}', ${manifest.decoder.content}),`;
1225
1651
  }).join("\n");
1226
- const toMapFields = allArgs.map(
1227
- (arg) => ` '${arg.name}': value.${camelCase(arg.name)},`
1228
- ).join("\n");
1229
- const fromMapFields = allArgManifests.map(({ arg, manifest }) => {
1652
+ const toMapFields = allArgs.map((arg) => {
1653
+ const value = isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node) ? argDefaultValues.get(arg).content : `value.${camelCase(arg.name)}`;
1654
+ return ` '${arg.name}': ${value},`;
1655
+ }).join("\n");
1656
+ const fromMapFields = allArgManifests.filter(({ arg }) => !isOmittedDefaultArgument(arg)).map(({ arg, manifest }) => {
1230
1657
  const typeStr = manifest.type.content;
1231
1658
  const isNullable = typeStr.endsWith("?");
1232
1659
  const accessor = isNullable ? `map['${arg.name}']` : `map['${arg.name}']!`;
1233
1660
  return ` ${camelCase(arg.name)}: ${accessor} as ${typeStr},`;
1234
1661
  }).join("\n");
1235
- const dataCtorKeyword = dataCtorInitializers ? "" : "const ";
1662
+ const dataCtorKeyword = allArgs.every(
1663
+ (arg) => !isOmittedDefaultArgument(arg) || isConstDartValueNode(arg.defaultValue)
1664
+ ) && allArgs.every(
1665
+ (arg) => !isDiscriminatorArg(arg, node) || isConstDefaultValue(arg.defaultValue)
1666
+ ) ? "const " : "";
1667
+ const dataCtorSignature = dataCtorParams ? `${dataCtorKeyword}${dataClassName}({
1668
+ ${dataCtorParams}
1669
+ })${dataCtorInitializers ? ` :
1670
+ ${dataCtorInitializers}` : ""};` : `${dataCtorKeyword}${dataClassName}()${dataCtorInitializers ? ` :
1671
+ ${dataCtorInitializers}` : ""};`;
1236
1672
  const dataEncoderName = `get${typeName}InstructionDataEncoder`;
1237
1673
  const dataDecoderName = `get${typeName}InstructionDataDecoder`;
1238
1674
  const dataCodecName = `get${typeName}InstructionDataCodec`;
@@ -1240,6 +1676,10 @@ function getInstructionPageFragment(node, scope) {
1240
1676
  const accountNames = new Set(accounts.map((a) => camelCase(a.name)));
1241
1677
  const hasProgramAddressCollision = argNames.has("programAddress") || accountNames.has("programAddress");
1242
1678
  const instrProgramParam = hasProgramAddressCollision ? "instructionProgramAddress" : "programAddress";
1679
+ let instructionDataLocal = "instructionData";
1680
+ while (argNames.has(instructionDataLocal) || accountNames.has(instructionDataLocal)) {
1681
+ instructionDataLocal = `${instructionDataLocal}_`;
1682
+ }
1243
1683
  const accountParams = accounts.map((acc) => {
1244
1684
  const fieldName = camelCase(acc.name);
1245
1685
  const isRequired = !(acc.isOptional ?? false);
@@ -1262,20 +1702,33 @@ function getInstructionPageFragment(node, scope) {
1262
1702
  const role = getAccountRole(acc);
1263
1703
  const isOptional = acc.isOptional ?? false;
1264
1704
  if (isOptional) {
1265
- return ` if (${fieldName} != null) AccountMeta(address: ${fieldName}, role: ${role}),`;
1705
+ if (optionalAccountStrategy === "omitted") {
1706
+ return ` if (${fieldName} != null) AccountMeta(address: ${fieldName}, role: ${role}),`;
1707
+ }
1708
+ return ` if (${fieldName} != null) AccountMeta(address: ${fieldName}, role: ${role}) else AccountMeta(address: ${instrProgramParam}, role: AccountRole.readonly),`;
1266
1709
  }
1267
1710
  return ` AccountMeta(address: ${fieldName}, role: ${role}),`;
1268
1711
  }).join("\n");
1269
1712
  const dataConstruction = allArgs.map((arg) => {
1270
1713
  const fieldName = camelCase(arg.name);
1271
- if (isDiscriminatorArg(arg, node)) {
1714
+ if (isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node)) {
1272
1715
  return "";
1273
1716
  }
1274
- const typeStr2 = argManifestMap.get(arg)?.type.content;
1275
1717
  const skipDefault = arg.defaultValue?.kind === "accountBumpValueNode";
1276
- return ` ${fieldName}: ${fieldName}${arg.defaultValue != null && !skipDefault ? ` ?? ${getDefaultValue(arg, typeStr2)}` : ""},`;
1718
+ return ` ${fieldName}: ${fieldName}${arg.defaultValue != null && !skipDefault ? ` ?? ${argDefaultValues.get(arg).content}` : ""},`;
1277
1719
  }).filter(Boolean).join("\n");
1278
1720
  const discFragment = getDiscriminatorConstantsFragment(node, scope);
1721
+ const discriminatorValidation = getDiscriminatorValidationFragment(
1722
+ node,
1723
+ scope
1724
+ );
1725
+ const topLevelDecoder = getTopLevelDecoderFragment({
1726
+ typeName: dataClassName,
1727
+ description: `${name} instruction decoder`,
1728
+ discriminatorValidation,
1729
+ fromMapFields,
1730
+ requireExactConsumption: true
1731
+ });
1279
1732
  const parts = [
1280
1733
  fragment`// Auto-generated. Do not edit.
1281
1734
  // ignore_for_file: type=lint
@@ -1299,10 +1752,7 @@ ${use("AccountRole", "solanaInstructions")}`
1299
1752
  parts.push(fragment`
1300
1753
  @immutable
1301
1754
  class ${fragmentFromString(dataClassName)} {
1302
- ${fragmentFromString(dataCtorKeyword)}${fragmentFromString(dataClassName)}({
1303
- ${fragmentFromString(dataCtorParams)}
1304
- })${fragmentFromString(dataCtorInitializers ? ` :
1305
- ${dataCtorInitializers}` : "")};
1755
+ ${fragmentFromString(dataCtorSignature)}
1306
1756
 
1307
1757
  ${fragmentFromString(dataFieldDecls)}
1308
1758
  }`);
@@ -1325,12 +1775,7 @@ Decoder<${fragmentFromString(dataClassName)}> ${fragmentFromString(dataDecoderNa
1325
1775
  ${fragmentFromString(decFields)}
1326
1776
  ]);
1327
1777
 
1328
- return transformDecoder(
1329
- structDecoder,
1330
- (Map<String, Object?> map, Uint8List bytes, int offset) => ${fragmentFromString(dataClassName)}(
1331
- ${fragmentFromString(fromMapFields)}
1332
- ),
1333
- );
1778
+ ${topLevelDecoder}
1334
1779
  }
1335
1780
 
1336
1781
  Codec<${fragmentFromString(dataClassName)}, ${fragmentFromString(dataClassName)}> ${fragmentFromString(dataCodecName)}() {
@@ -1343,7 +1788,7 @@ Instruction ${fragmentFromString(instrFnName)}({
1343
1788
  ${fragmentFromString(accountParams)}
1344
1789
  ${fragmentFromString(argParams)}
1345
1790
  }) {
1346
- final instructionData = ${fragmentFromString(dataClassName)}(
1791
+ final ${instructionDataLocal} = ${fragmentFromString(dataClassName)}(
1347
1792
  ${fragmentFromString(dataConstruction)}
1348
1793
  );
1349
1794
 
@@ -1352,7 +1797,7 @@ ${fragmentFromString(dataConstruction)}
1352
1797
  accounts: [
1353
1798
  ${fragmentFromString(accountMetas)}
1354
1799
  ],
1355
- data: ${fragmentFromString(dataEncoderName)}().encode(instructionData),
1800
+ data: ${fragmentFromString(dataEncoderName)}().encode(${instructionDataLocal}),
1356
1801
  );
1357
1802
  }`);
1358
1803
  parts.push(fragment`
@@ -1366,6 +1811,9 @@ ${fragmentFromString(dataClassName)} ${fragmentFromString(parseFnName)}(Instruct
1366
1811
  result.imports.mergeWith(manifest.decoder.imports);
1367
1812
  result.imports.mergeWith(manifest.type.imports);
1368
1813
  }
1814
+ for (const defaultValue of argDefaultValues.values()) {
1815
+ result.imports.mergeWith(defaultValue.imports);
1816
+ }
1369
1817
  return result;
1370
1818
  }
1371
1819
  function getAccountRole(acc) {
@@ -1382,19 +1830,6 @@ function isDiscriminatorArg(arg, node) {
1382
1830
  (d) => d.kind === "fieldDiscriminatorNode" && d.name === arg.name
1383
1831
  );
1384
1832
  }
1385
- function getDiscriminatorDefault(arg, _node) {
1386
- if (arg.defaultValue) {
1387
- if (arg.defaultValue.kind === "numberValueNode") {
1388
- return String(arg.defaultValue.number);
1389
- }
1390
- if (arg.defaultValue.kind === "bytesValueNode") {
1391
- const data = arg.defaultValue.data;
1392
- const bytes = data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
1393
- return `Uint8List.fromList([${bytes.join(", ")}])`;
1394
- }
1395
- }
1396
- return "0";
1397
- }
1398
1833
  function isConstDefaultValue(defaultValue) {
1399
1834
  if (!defaultValue) return false;
1400
1835
  switch (defaultValue.kind) {
@@ -1407,34 +1842,8 @@ function isConstDefaultValue(defaultValue) {
1407
1842
  return false;
1408
1843
  }
1409
1844
  }
1410
- function getDefaultValue(arg, typeStr) {
1411
- if (!arg.defaultValue) return "null";
1412
- const isBigInt = typeStr === "BigInt";
1413
- const dv = arg.defaultValue;
1414
- switch (dv.kind) {
1415
- case "numberValueNode":
1416
- return isBigInt ? `BigInt.from(${dv.number})` : String(dv.number);
1417
- case "booleanValueNode":
1418
- return String(dv.boolean);
1419
- case "stringValueNode":
1420
- return `'${dv.string}'`;
1421
- case "publicKeyValueNode": {
1422
- const wellKnownName = WELL_KNOWN_ADDRESSES.get(dv.publicKey);
1423
- if (wellKnownName) {
1424
- use(wellKnownName, "solanaAddresses");
1425
- return wellKnownName;
1426
- }
1427
- return `Address('${dv.publicKey}')`;
1428
- }
1429
- case "noneValueNode":
1430
- return "null";
1431
- case "bytesValueNode": {
1432
- const bytes = dv.data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
1433
- return `Uint8List.fromList([${bytes.join(", ")}])`;
1434
- }
1435
- default:
1436
- return "null";
1437
- }
1845
+ function isOmittedDefaultArgument(arg) {
1846
+ return arg.defaultValue != null && arg.defaultValueStrategy === "omitted";
1438
1847
  }
1439
1848
  function getPdaPageFragment(node, scope) {
1440
1849
  const name = node.name;
@@ -1729,25 +2138,26 @@ function getTypePageFragment(node, scope) {
1729
2138
  scope.nameApi.dataType(name);
1730
2139
  const typeNode = node.type;
1731
2140
  if (typeNode.kind === "enumTypeNode") {
1732
- const isScalar = typeNode.variants.every(
2141
+ const variants = typeNode.variants ?? [];
2142
+ const isScalar = variants.every(
1733
2143
  (v) => v.kind === "enumEmptyVariantTypeNode"
1734
2144
  );
1735
2145
  if (isScalar) {
1736
- return getScalarEnumPageFragment(node, scope);
2146
+ return getScalarEnumPageFragment(node, variants, scope);
1737
2147
  }
1738
- return getDataEnumPageFragment(node, scope);
2148
+ return getDataEnumPageFragment(node, variants, scope);
1739
2149
  }
1740
2150
  if (typeNode.kind === "structTypeNode") {
1741
2151
  return getStructPageFragment(node, scope);
1742
2152
  }
1743
2153
  return getTypeAliasPageFragment(node, scope);
1744
2154
  }
1745
- function getScalarEnumPageFragment(node, scope) {
2155
+ function getScalarEnumPageFragment(node, enumVariants, scope) {
1746
2156
  const name = node.name;
1747
2157
  const typeName = scope.nameApi.dataType(name);
1748
2158
  const enumNode = node.type;
1749
2159
  if (enumNode.kind !== "enumTypeNode") return emptyFragment();
1750
- const variants = enumNode.variants.map((v) => {
2160
+ const variants = enumVariants.map((v) => {
1751
2161
  const variantName = scope.nameApi.enumVariant(v.name);
1752
2162
  return variantName;
1753
2163
  });
@@ -1758,6 +2168,14 @@ function getScalarEnumPageFragment(node, scope) {
1758
2168
  const resolvedSize = nodes.resolveNestedTypeNode(enumNode.size);
1759
2169
  const sizeType = resolvedSize.format ?? "u8";
1760
2170
  const sizeCodecName = getNumberCodecName2(sizeType);
2171
+ const isU64 = sizeType === "u64";
2172
+ const encodedVariantIndex = isU64 ? "BigInt.from(value.index)" : "value.index";
2173
+ const decodedVariant = isU64 ? `(BigInt value, Uint8List bytes, int offset) {
2174
+ if (value.isNegative || value >= BigInt.from(${typeName}.values.length)) {
2175
+ throw RangeError('Invalid ${typeName} discriminator: ' + value.toString());
2176
+ }
2177
+ return ${typeName}.values[value.toInt()];
2178
+ }` : `(int value, Uint8List bytes, int offset) => ${typeName}.values[value]`;
1761
2179
  return fragment`// Auto-generated. Do not edit.
1762
2180
  // ignore_for_file: type=lint
1763
2181
 
@@ -1778,14 +2196,14 @@ ${fragmentFromString(variantLines)}
1778
2196
  Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
1779
2197
  return transformEncoder(
1780
2198
  get${fragmentFromString(sizeCodecName)}Encoder(),
1781
- (${fragmentFromString(typeName)} value) => value.index,
2199
+ (${fragmentFromString(typeName)} value) => ${fragmentFromString(encodedVariantIndex)},
1782
2200
  );
1783
2201
  }
1784
2202
 
1785
2203
  Decoder<${fragmentFromString(typeName)}> ${fragmentFromString(decoderName)}() {
1786
2204
  return transformDecoder(
1787
2205
  get${fragmentFromString(sizeCodecName)}Decoder(),
1788
- (int value, Uint8List bytes, int offset) => ${fragmentFromString(typeName)}.values[value],
2206
+ ${fragmentFromString(decodedVariant)},
1789
2207
  );
1790
2208
  }
1791
2209
 
@@ -1793,7 +2211,7 @@ Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragme
1793
2211
  return combineCodec(${fragmentFromString(encoderName)}(), ${fragmentFromString(decoderName)}());
1794
2212
  }`;
1795
2213
  }
1796
- function getDataEnumPageFragment(node, scope) {
2214
+ function getDataEnumPageFragment(node, variants, scope) {
1797
2215
  const name = node.name;
1798
2216
  const typeName = scope.nameApi.dataType(name);
1799
2217
  const enumNode = node.type;
@@ -1803,9 +2221,10 @@ function getDataEnumPageFragment(node, scope) {
1803
2221
  const decoderVariants = [];
1804
2222
  const encodeCases = [];
1805
2223
  const decodeCases = [];
2224
+ let pageHasListEnums = false;
1806
2225
  const allVariantManifests = [];
1807
- for (let i = 0; i < enumNode.variants.length; i++) {
1808
- const variant = enumNode.variants[i];
2226
+ for (let i = 0; i < variants.length; i++) {
2227
+ const variant = variants[i];
1809
2228
  const variantName = pascalCase(variant.name);
1810
2229
  const variantClassName = scope.nameApi.sealedClassVariant(
1811
2230
  name,
@@ -1835,7 +2254,7 @@ function getDataEnumPageFragment(node, scope) {
1835
2254
  decodeCases.push(`case ${i}: return const ${variantClassName}();`);
1836
2255
  } else if (variant.kind === "enumStructVariantTypeNode") {
1837
2256
  const resolvedStruct = nodes.resolveNestedTypeNode(variant.struct);
1838
- const fields = resolvedStruct.fields;
2257
+ const fields = resolvedStruct.fields ?? [];
1839
2258
  const fieldManifests = fields.map((f) => ({
1840
2259
  field: f,
1841
2260
  manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
@@ -1850,10 +2269,14 @@ function getDataEnumPageFragment(node, scope) {
1850
2269
  const ctorSignature = fields.length === 0 ? ` const ${variantClassName}();` : ` const ${variantClassName}({
1851
2270
  ${ctorParams}
1852
2271
  });`;
1853
- const eqChecks = fields.length === 0 ? "true" : fields.map((f) => `${camelCase(f.name)} == other.${camelCase(f.name)}`).join(" &&\n ");
1854
- const hashExpression = getHashExpression(
1855
- fields.map((f) => camelCase(f.name))
1856
- );
2272
+ const eqChecks = fields.length === 0 ? "true" : fields.map((f, index) => {
2273
+ const fieldName = camelCase(f.name);
2274
+ return isListManifest(fieldManifests[index].manifest) ? `_listEquals(${fieldName}, other.${fieldName})` : `${fieldName} == other.${fieldName}`;
2275
+ }).join(" &&\n ");
2276
+ const hashExpression = getValueHashExpression(fields, fieldManifests);
2277
+ if (fieldManifests.some(({ manifest }) => isListManifest(manifest))) {
2278
+ pageHasListEnums = true;
2279
+ }
1857
2280
  const toStringFields = fields.map((f) => `${camelCase(f.name)}: $${camelCase(f.name)}`).join(", ");
1858
2281
  variantClasses.push(`final class ${variantClassName} extends ${typeName} {
1859
2282
  ${ctorSignature}
@@ -1901,7 +2324,7 @@ ${fieldDecls}
1901
2324
  decodeCases.push(`case ${i}: return ${variantClassName}(${fromMapFields.replace(/\n/g, " ").replace(/,$/, "")});`);
1902
2325
  } else if (variant.kind === "enumTupleVariantTypeNode") {
1903
2326
  const resolvedTuple = nodes.resolveNestedTypeNode(variant.tuple);
1904
- const items = resolvedTuple.items;
2327
+ const items = resolvedTuple.items ?? [];
1905
2328
  if (items.length === 1) {
1906
2329
  const manifest = visitorsCore.visit(items[0], scope.typeManifestVisitor);
1907
2330
  allVariantManifests.push(manifest);
@@ -1959,7 +2382,7 @@ sealed class ${fragmentFromString(typeName)} {
1959
2382
  const ${fragmentFromString(typeName)}();
1960
2383
  }
1961
2384
 
1962
- ${fragmentFromString(variantClasses.join("\n\n"))}
2385
+ ${fragmentFromString(variantClasses.join("\n\n"))}${pageHasListEnums ? LIST_VALUE_HELPERS : ""}
1963
2386
 
1964
2387
  Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
1965
2388
  return transformEncoder<Map<String, Object?>, ${fragmentFromString(typeName)}>(
@@ -2001,7 +2424,8 @@ function getStructPageFragment(node, scope) {
2001
2424
  const typeName = scope.nameApi.dataType(name);
2002
2425
  const structNode = node.type;
2003
2426
  if (structNode.kind !== "structTypeNode") return emptyFragment();
2004
- const fields = structNode.fields;
2427
+ const fields = structNode.fields ?? [];
2428
+ let pageHasListStructs = false;
2005
2429
  const fieldManifests = fields.map((f) => ({
2006
2430
  field: f,
2007
2431
  manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
@@ -2013,10 +2437,13 @@ function getStructPageFragment(node, scope) {
2013
2437
  const ctorSignature = fields.length === 0 ? ` const ${typeName}();` : ` const ${typeName}({
2014
2438
  ${ctorParams}
2015
2439
  });`;
2016
- const eqChecks = fields.length === 0 ? "true" : fields.map(
2017
- (f) => `${camelCase(f.name)} == other.${camelCase(f.name)}`
2018
- ).join(" &&\n ");
2019
- fields.length === 0 ? "runtimeType" : fields.map((f) => camelCase(f.name)).join(", ");
2440
+ const eqChecks = fields.length === 0 ? "true" : fieldManifests.map(({ field: f, manifest }, index) => {
2441
+ const fieldName = camelCase(f.name);
2442
+ return isListManifest(manifest) ? `_listEquals(${fieldName}, other.${fieldName})` : `${fieldName} == other.${fieldName}`;
2443
+ }).join(" &&\n ");
2444
+ if (fieldManifests.some(({ manifest }) => isListManifest(manifest))) {
2445
+ pageHasListStructs = true;
2446
+ }
2020
2447
  const toStringFields = fields.map(
2021
2448
  (f) => `${camelCase(f.name)}: $${camelCase(f.name)}`
2022
2449
  ).join(", ");
@@ -2066,12 +2493,14 @@ ${fragmentFromString(fieldDecls)}
2066
2493
  ${fragmentFromString(eqChecks)};
2067
2494
 
2068
2495
  @override
2069
- int get hashCode => ${fragmentFromString(getHashExpression(fields.map((f) => camelCase(f.name))))};
2496
+ int get hashCode => ${fragmentFromString(
2497
+ getValueHashExpression(fields, fieldManifests)
2498
+ )};
2070
2499
 
2071
2500
  @override
2072
2501
  String toString() => '${fragmentFromString(typeName)}(${fragmentFromString(toStringFields)})';
2073
2502
  }
2074
-
2503
+ ${pageHasListStructs ? LIST_VALUE_HELPERS : ""}
2075
2504
  Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
2076
2505
  final structEncoder = getStructEncoder(<(String, Encoder<Object?>)>[
2077
2506
  ${fragmentFromString(encFields)}
@@ -2137,6 +2566,56 @@ Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragme
2137
2566
  return combineCodec(${fragmentFromString(encoderName)}(), ${fragmentFromString(decoderName)}());
2138
2567
  }`;
2139
2568
  }
2569
+ function isListManifest(manifest) {
2570
+ return manifest.type.content.startsWith("List<") || manifest.type.content === "Uint8List";
2571
+ }
2572
+ var LIST_VALUE_HELPERS = `
2573
+ bool _listEquals<T>(List<T>? a, List<T>? b) {
2574
+ if (identical(a, b)) return true;
2575
+ if (a == null || b == null) return a == b;
2576
+ if (a.length != b.length) return false;
2577
+ for (var i = 0; i < a.length; i++) {
2578
+ final left = a[i];
2579
+ final right = b[i];
2580
+ if (left is List<Object?> && right is List<Object?>) {
2581
+ if (!_listEquals(left, right)) return false;
2582
+ } else if (left != right) {
2583
+ return false;
2584
+ }
2585
+ }
2586
+ return true;
2587
+ }
2588
+
2589
+ Object? _deepHash(Object? value) {
2590
+ if (value is List<Object?>) {
2591
+ return Object.hashAll(value.map(_deepHash));
2592
+ }
2593
+ return value;
2594
+ }
2595
+
2596
+ int _listHashCode<T>(List<T>? a) {
2597
+ if (a == null) return 0;
2598
+ return Object.hashAll(a.map(_deepHash));
2599
+ }
2600
+ `;
2601
+ function getValueHashExpression(fields, fieldManifests) {
2602
+ const fieldNames = fields.map(
2603
+ (f) => camelCase(f.name)
2604
+ );
2605
+ const hasListFields = fieldManifests.some(
2606
+ ({ manifest }) => isListManifest(manifest)
2607
+ );
2608
+ if (!hasListFields) {
2609
+ return getHashExpression(fieldNames);
2610
+ }
2611
+ if (fieldNames.length === 1) {
2612
+ return `_listHashCode(${fieldNames[0]})`;
2613
+ }
2614
+ const hashArgs = fields.map(
2615
+ (f, index) => isListManifest(fieldManifests[index].manifest) ? `_listHashCode(${camelCase(f.name)})` : camelCase(f.name)
2616
+ );
2617
+ return `Object.hash(${hashArgs.join(", ")})`;
2618
+ }
2140
2619
  function getHashExpression(fields) {
2141
2620
  if (fields.length === 0) return "runtimeType.hashCode";
2142
2621
  if (fields.length === 1) return `${fields[0]}.hashCode`;
@@ -2208,7 +2687,7 @@ function getRenderMapVisitor(options = {}) {
2208
2687
  visitRoot(node, { self }) {
2209
2688
  const programMaps = [
2210
2689
  visitorsCore.visit(node.program, self),
2211
- ...node.additionalPrograms.map((p) => visitorsCore.visit(p, self))
2690
+ ...(node.additionalPrograms ?? []).map((p) => visitorsCore.visit(p, self))
2212
2691
  ];
2213
2692
  const mergedProgramMap = renderersCore.mergeRenderMaps(programMaps);
2214
2693
  const categoryMaps = getSharedCategoryIndexMaps(mergedProgramMap);
@@ -2354,11 +2833,12 @@ function renderVisitor(outputDir, options = {}) {
2354
2833
  dependencyMap
2355
2834
  } = options;
2356
2835
  return visitorsCore.rootNodeVisitor((root) => {
2836
+ const normalizedRoot = normalizeRootNode(root);
2357
2837
  if (deleteFolderBeforeRendering && fs.existsSync(outputDir)) {
2358
2838
  renderersCore.deleteDirectory(outputDir);
2359
2839
  }
2360
2840
  const renderMap = visitorsCore.visit(
2361
- root,
2841
+ normalizedRoot,
2362
2842
  getRenderMapVisitor({ nameApi, dependencyMap })
2363
2843
  );
2364
2844
  const typePathMap = {};
@@ -2446,6 +2926,7 @@ exports.createDartNameApi = createDartNameApi;
2446
2926
  exports.default = src_default;
2447
2927
  exports.getRenderMapVisitor = getRenderMapVisitor;
2448
2928
  exports.getTypeManifestVisitor = getTypeManifestVisitor;
2929
+ exports.normalizeRootNode = normalizeRootNode;
2449
2930
  exports.renderVisitor = renderVisitor;
2450
2931
  //# sourceMappingURL=index.browser.cjs.map
2451
2932
  //# sourceMappingURL=index.browser.cjs.map