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.
- package/{readme.md → README.md} +38 -42
- package/dist/index.browser.cjs +628 -147
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +628 -148
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +628 -147
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +628 -148
- package/dist/index.node.js.map +1 -1
- package/dist/index.react-native.js +628 -148
- package/dist/index.react-native.js.map +1 -1
- package/dist/types/fragments/accountPage.d.ts.map +1 -1
- package/dist/types/fragments/instructionPage.d.ts.map +1 -1
- package/dist/types/fragments/typePage.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/utils/discriminators.d.ts +10 -0
- package/dist/types/utils/discriminators.d.ts.map +1 -0
- package/dist/types/utils/exactDecoder.d.ts +17 -0
- package/dist/types/utils/exactDecoder.d.ts.map +1 -0
- package/dist/types/utils/formatCode.d.ts +1 -1
- package/dist/types/utils/formatCode.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +4 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/nameTransformers.d.ts +5 -0
- package/dist/types/utils/nameTransformers.d.ts.map +1 -1
- package/dist/types/utils/normalizeRootNode.d.ts +11 -0
- package/dist/types/utils/normalizeRootNode.d.ts.map +1 -0
- package/dist/types/utils/valueNodes.d.ts +16 -0
- package/dist/types/utils/valueNodes.d.ts.map +1 -0
- package/dist/types/visitors/getTypeManifestVisitor.d.ts +1 -1
- package/dist/types/visitors/getTypeManifestVisitor.d.ts.map +1 -1
- package/dist/types/visitors/renderVisitor.d.ts.map +1 -1
- package/package.json +21 -18
- package/src/fragments/accountPage.ts +90 -17
- package/src/fragments/instructionPage.ts +112 -79
- package/src/fragments/typePage.ts +134 -31
- package/src/index.ts +1 -0
- package/src/utils/discriminators.ts +121 -0
- package/src/utils/exactDecoder.ts +82 -0
- package/src/utils/formatCode.ts +7 -11
- package/src/utils/index.ts +4 -0
- package/src/utils/nameTransformers.ts +28 -1
- package/src/utils/normalizeRootNode.ts +76 -0
- package/src/utils/valueNodes.ts +87 -0
- package/src/visitors/getRenderMapVisitor.ts +1 -1
- package/src/visitors/getTypeManifestVisitor.ts +37 -14
- package/src/visitors/renderVisitor.ts +4 -1
package/dist/index.browser.cjs
CHANGED
|
@@ -12,13 +12,71 @@ var errors = require('@codama/errors');
|
|
|
12
12
|
|
|
13
13
|
// src/visitors/renderVisitor.ts
|
|
14
14
|
function formatDartDirectory(dir) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
)}(${
|
|
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
|
-
|
|
819
|
+
tupleEncoderFn,
|
|
482
820
|
"solanaCodecsDataStructures"
|
|
483
|
-
)}(
|
|
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
|
-
|
|
826
|
+
tupleDecoderFn,
|
|
490
827
|
"solanaCodecsDataStructures"
|
|
491
|
-
)}(
|
|
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
|
|
505
|
-
const
|
|
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)}>(${
|
|
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
|
|
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 =
|
|
989
|
-
const
|
|
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)
|
|
1008
|
-
|
|
1009
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
1567
|
+
${exports}
|
|
1174
1568
|
`
|
|
1175
1569
|
);
|
|
1176
1570
|
}
|
|
1177
1571
|
function getRootIndexPageFragment(categories) {
|
|
1178
|
-
const exports
|
|
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
|
|
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 =
|
|
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} = ${
|
|
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} ?? ${
|
|
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)
|
|
1228
|
-
|
|
1229
|
-
|
|
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 =
|
|
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
|
-
|
|
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 ? ` ?? ${
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
1411
|
-
|
|
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
|
|
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 =
|
|
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) =>
|
|
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
|
-
|
|
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 <
|
|
1808
|
-
const variant =
|
|
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) =>
|
|
1854
|
-
|
|
1855
|
-
|
|
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" :
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
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(
|
|
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
|
-
|
|
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
|