codama-renderers-dart 0.4.3 → 0.5.1
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/LICENSE +21 -0
- package/dist/index.browser.cjs +634 -159
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +635 -161
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +634 -159
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +635 -161
- package/dist/index.node.js.map +1 -1
- package/dist/index.react-native.js +635 -161
- 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/programPage.d.ts +1 -1
- package/dist/types/fragments/programPage.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/importMap.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 +1 -1
- 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 +31 -23
- package/readme.md +30 -3
- package/src/fragments/accountPage.ts +90 -17
- package/src/fragments/instructionPage.ts +109 -72
- package/src/fragments/programPage.ts +165 -6
- package/src/fragments/typePage.ts +36 -15
- 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/importMap.ts +16 -3
- package/src/utils/index.ts +4 -0
- package/src/utils/nameTransformers.ts +3 -2
- package/src/utils/normalizeRootNode.ts +76 -0
- package/src/utils/valueNodes.ts +87 -0
- package/src/utils/wellKnownAddresses.ts +4 -4
- package/src/visitors/getRenderMapVisitor.ts +1 -1
- package/src/visitors/getTypeManifestVisitor.ts +48 -29
- package/src/visitors/renderVisitor.ts +11 -4
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
|
|
|
@@ -50,7 +108,7 @@ function createDartNameApi() {
|
|
|
50
108
|
errorConstant: (programName, errorName) => `${camelCase(programName)}Error${pascalCase(errorName)}`,
|
|
51
109
|
errorMessageFunction: (name) => `get${pascalCase(name)}ErrorMessage`,
|
|
52
110
|
enumVariant: (name) => camelCase(name),
|
|
53
|
-
sealedClassVariant: (
|
|
111
|
+
sealedClassVariant: (parentName, variantName) => `${pascalCase(parentName)}${pascalCase(variantName)}`,
|
|
54
112
|
isTypeFunction: (name) => `is${pascalCase(name)}`,
|
|
55
113
|
fileName: (name) => snakeCase(name),
|
|
56
114
|
discriminatorConstant: (name) => `${camelCase(name)}Discriminator`
|
|
@@ -124,11 +182,16 @@ var DartImportMap = class {
|
|
|
124
182
|
const uris = /* @__PURE__ */ new Set();
|
|
125
183
|
for (const module of this._imports) {
|
|
126
184
|
if (module in internalMap) {
|
|
127
|
-
|
|
185
|
+
const uri = internalMap[module];
|
|
186
|
+
if (uri) {
|
|
187
|
+
uris.add(uri);
|
|
188
|
+
}
|
|
128
189
|
} else if (module in DART_EXTERNAL_PACKAGE_MAP) {
|
|
129
190
|
uris.add(DART_EXTERNAL_PACKAGE_MAP[module]);
|
|
130
|
-
} else {
|
|
191
|
+
} else if (isRawDartImportUri(module)) {
|
|
131
192
|
uris.add(module);
|
|
193
|
+
} else {
|
|
194
|
+
throw new Error(`Unresolved Dart import module "${module}"`);
|
|
132
195
|
}
|
|
133
196
|
}
|
|
134
197
|
return [...uris].sort((a, b) => {
|
|
@@ -157,6 +220,9 @@ var DartImportMap = class {
|
|
|
157
220
|
return lines.join("\n");
|
|
158
221
|
}
|
|
159
222
|
};
|
|
223
|
+
function isRawDartImportUri(module) {
|
|
224
|
+
return module.startsWith("dart:") || module.startsWith("package:") || module.endsWith(".dart") && !module.includes(":");
|
|
225
|
+
}
|
|
160
226
|
|
|
161
227
|
// src/utils/fragment.ts
|
|
162
228
|
function fragment(strings, ...values) {
|
|
@@ -200,17 +266,6 @@ function use(typeName, module) {
|
|
|
200
266
|
return { content: typeName, imports };
|
|
201
267
|
}
|
|
202
268
|
|
|
203
|
-
// src/utils/typeManifest.ts
|
|
204
|
-
function emptyTypeManifest() {
|
|
205
|
-
return {
|
|
206
|
-
type: emptyFragment(),
|
|
207
|
-
encoder: emptyFragment(),
|
|
208
|
-
decoder: emptyFragment(),
|
|
209
|
-
value: emptyFragment(),
|
|
210
|
-
isEnum: false
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
269
|
// src/utils/wellKnownAddresses.ts
|
|
215
270
|
var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
|
|
216
271
|
// Agave / Solana native programs
|
|
@@ -248,10 +303,10 @@ var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
|
|
|
248
303
|
["Sysvar1111111111111111111111111111111111111", "sysvarOwnerAddress"],
|
|
249
304
|
// SPL programs
|
|
250
305
|
["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "tokenProgramAddress"],
|
|
251
|
-
["
|
|
252
|
-
["
|
|
253
|
-
["
|
|
254
|
-
["
|
|
306
|
+
["TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", "token2022ProgramAddress"],
|
|
307
|
+
["ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "associatedTokenProgramAddress"],
|
|
308
|
+
["MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr", "memoProgramAddress"],
|
|
309
|
+
["Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo", "memoLegacyProgramAddress"],
|
|
255
310
|
// Metaplex programs
|
|
256
311
|
["metaqbxxU9qX8rZXkmUJ7haCrXXz2W1PSUq1Rn3E1od", "tokenMetadataProgramAddress"],
|
|
257
312
|
["BGUMAp9V1mQ2KV8t34L5u3gZsXYZaYDBdKkc1xYk1qA1", "mplBubblegumProgramAddress"],
|
|
@@ -265,6 +320,207 @@ var WELL_KNOWN_ADDRESSES = /* @__PURE__ */ new Map([
|
|
|
265
320
|
["Es9vMFrzaCERm6YKXx6bqKr1Rmd9b5v3J8rM5e4rfF4", "usdtAddress"]
|
|
266
321
|
]);
|
|
267
322
|
|
|
323
|
+
// src/utils/valueNodes.ts
|
|
324
|
+
function getDartValueFragment(value, dartType) {
|
|
325
|
+
switch (value.kind) {
|
|
326
|
+
case "numberValueNode":
|
|
327
|
+
return fragmentFromString(
|
|
328
|
+
dartType === "BigInt" ? `BigInt.from(${value.number})` : String(value.number)
|
|
329
|
+
);
|
|
330
|
+
case "booleanValueNode":
|
|
331
|
+
return fragmentFromString(String(value.boolean));
|
|
332
|
+
case "stringValueNode":
|
|
333
|
+
return fragmentFromString(toDartStringLiteral(value.string));
|
|
334
|
+
case "noneValueNode":
|
|
335
|
+
return fragmentFromString("null");
|
|
336
|
+
case "bytesValueNode": {
|
|
337
|
+
if (value.encoding !== "base16") {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`Unsupported deterministic bytes encoding: ${value.encoding}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
const clean = value.data.replace(/^0x/, "");
|
|
343
|
+
if (clean.length % 2 !== 0 || !/^[0-9a-f]*$/i.test(clean)) {
|
|
344
|
+
throw new Error(`Invalid hexadecimal bytes value: ${value.data}`);
|
|
345
|
+
}
|
|
346
|
+
const bytes = clean.match(/.{2}/g)?.map((byte) => `0x${byte}`) ?? [];
|
|
347
|
+
return fragment`${use("Uint8List", "dartTypedData")}.fromList([${fragmentFromString(bytes.join(", "))}])`;
|
|
348
|
+
}
|
|
349
|
+
case "publicKeyValueNode": {
|
|
350
|
+
const wellKnownName = WELL_KNOWN_ADDRESSES.get(value.publicKey);
|
|
351
|
+
return wellKnownName ? fragment`${use(wellKnownName, "solanaAddresses")}` : fragment`${use("Address", "solanaAddresses")}(${fragmentFromString(toDartStringLiteral(value.publicKey))})`;
|
|
352
|
+
}
|
|
353
|
+
default:
|
|
354
|
+
throw new Error(
|
|
355
|
+
`Unsupported deterministic Dart value node: ${value.kind}`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function isConstDartValueNode(value) {
|
|
360
|
+
switch (value.kind) {
|
|
361
|
+
case "numberValueNode":
|
|
362
|
+
case "booleanValueNode":
|
|
363
|
+
case "stringValueNode":
|
|
364
|
+
case "noneValueNode":
|
|
365
|
+
case "publicKeyValueNode":
|
|
366
|
+
return true;
|
|
367
|
+
default:
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function toDartStringLiteral(value) {
|
|
372
|
+
return `'${value.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t").replaceAll("\b", "\\b").replaceAll("\f", "\\f").replaceAll("$", "\\$").replaceAll("'", "\\'")}'`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/utils/discriminators.ts
|
|
376
|
+
function getDiscriminatorValidationFragment(node, scope) {
|
|
377
|
+
const discriminators = node.discriminators ?? [];
|
|
378
|
+
if (discriminators.length === 0) return emptyFragment();
|
|
379
|
+
const fields = getDiscriminatorFields(node);
|
|
380
|
+
const fragments = discriminators.map((discriminator) => {
|
|
381
|
+
switch (discriminator.kind) {
|
|
382
|
+
case "constantDiscriminatorNode":
|
|
383
|
+
return getConstantValidationFragment(
|
|
384
|
+
discriminator.constant,
|
|
385
|
+
discriminator.offset,
|
|
386
|
+
scope
|
|
387
|
+
);
|
|
388
|
+
case "fieldDiscriminatorNode": {
|
|
389
|
+
const field = fields.find(
|
|
390
|
+
(candidate) => candidate.name === discriminator.name
|
|
391
|
+
);
|
|
392
|
+
if (field?.defaultValue == null) {
|
|
393
|
+
throw new Error(
|
|
394
|
+
`Field discriminator "${discriminator.name}" on ${node.kind} "${node.name}" must reference a field with a default value.`
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
return getConstantValidationFragment(
|
|
398
|
+
{
|
|
399
|
+
type: field.type,
|
|
400
|
+
value: field.defaultValue
|
|
401
|
+
},
|
|
402
|
+
discriminator.offset,
|
|
403
|
+
scope
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
case "sizeDiscriminatorNode": {
|
|
407
|
+
if (!Number.isSafeInteger(discriminator.size) || discriminator.size < 0) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Discriminator size must be a non-negative safe integer, got ${discriminator.size}.`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
return fragment`if (bytes.length - offset != ${fragmentFromString(String(discriminator.size))}) {
|
|
413
|
+
throw ${use("SolanaError", "solanaErrors")}(
|
|
414
|
+
${use("SolanaErrorCode", "solanaErrors")}.codecsInvalidByteLength,
|
|
415
|
+
{
|
|
416
|
+
'codecDescription': '${fragmentFromString(node.name)} discriminator',
|
|
417
|
+
'expected': ${fragmentFromString(String(discriminator.size))},
|
|
418
|
+
'bytesLength': bytes.length - offset,
|
|
419
|
+
},
|
|
420
|
+
);
|
|
421
|
+
}`;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
return mergeFragments(fragments, (contents) => contents.join("\n"));
|
|
426
|
+
}
|
|
427
|
+
function getConstantValidationFragment(constant, discriminatorOffset, scope) {
|
|
428
|
+
if (!Number.isSafeInteger(discriminatorOffset) || discriminatorOffset < 0) {
|
|
429
|
+
throw new Error(
|
|
430
|
+
`Discriminator offset must be a non-negative safe integer, got ${discriminatorOffset}.`
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
const manifest = visitorsCore.visit(constant.type, scope.typeManifestVisitor);
|
|
434
|
+
const value = getDartValueFragment(
|
|
435
|
+
constant.value,
|
|
436
|
+
manifest.type.content
|
|
437
|
+
);
|
|
438
|
+
return fragment`${use("getConstantDecoder", "solanaCodecsDataStructures")}(
|
|
439
|
+
${manifest.encoder}.encode(${value}),
|
|
440
|
+
).read(bytes, offset + ${fragmentFromString(String(discriminatorOffset))});`;
|
|
441
|
+
}
|
|
442
|
+
function getDiscriminatorFields(node) {
|
|
443
|
+
if (node.kind === "accountNode") {
|
|
444
|
+
return nodes.resolveNestedTypeNode(node.data).fields ?? [];
|
|
445
|
+
}
|
|
446
|
+
return (node.arguments ?? []).map(
|
|
447
|
+
(argument) => ({
|
|
448
|
+
...argument,
|
|
449
|
+
kind: "structFieldTypeNode"
|
|
450
|
+
})
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/utils/exactDecoder.ts
|
|
455
|
+
function getTopLevelDecoderFragment({
|
|
456
|
+
typeName,
|
|
457
|
+
description,
|
|
458
|
+
discriminatorValidation,
|
|
459
|
+
fromMapFields,
|
|
460
|
+
requireExactConsumption
|
|
461
|
+
}) {
|
|
462
|
+
const validation = discriminatorValidation.content ? ` ${discriminatorValidation.content.replaceAll("\n", "\n ")}
|
|
463
|
+
` : "";
|
|
464
|
+
const consumptionCheck = requireExactConsumption ? ` if (newOffset != bytes.length) {
|
|
465
|
+
throwInvalidByteLength(newOffset - offset, bytes.length - offset);
|
|
466
|
+
}
|
|
467
|
+
` : "";
|
|
468
|
+
const fixedSizeCheck = requireExactConsumption ? "bytesLength != structDecoder.fixedSize" : "bytesLength < structDecoder.fixedSize";
|
|
469
|
+
const result = fragment` Never throwInvalidByteLength(int expected, int bytesLength) {
|
|
470
|
+
throw ${use("SolanaError", "solanaErrors")}(
|
|
471
|
+
${use("SolanaErrorCode", "solanaErrors")}.codecsInvalidByteLength,
|
|
472
|
+
{
|
|
473
|
+
'codecDescription': '${fragmentFromString(description)}',
|
|
474
|
+
'expected': expected,
|
|
475
|
+
'bytesLength': bytesLength,
|
|
476
|
+
},
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
(${fragmentFromString(typeName)}, int) readTopLevel(Uint8List bytes, int offset) {
|
|
481
|
+
${fragmentFromString(validation)} final (map, newOffset) = structDecoder.read(bytes, offset);
|
|
482
|
+
${fragmentFromString(consumptionCheck)}
|
|
483
|
+
return (
|
|
484
|
+
${fragmentFromString(typeName)}(
|
|
485
|
+
${fragmentFromString(fromMapFields)}
|
|
486
|
+
),
|
|
487
|
+
newOffset,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return switch (structDecoder) {
|
|
492
|
+
${use("FixedSizeDecoder", "solanaCodecsCore")}<Map<String, Object?>>() =>
|
|
493
|
+
${use("FixedSizeDecoder", "solanaCodecsCore")}<${fragmentFromString(typeName)}>(
|
|
494
|
+
fixedSize: structDecoder.fixedSize,
|
|
495
|
+
read: (bytes, offset) {
|
|
496
|
+
final bytesLength = bytes.length - offset;
|
|
497
|
+
if (${fragmentFromString(fixedSizeCheck)}) {
|
|
498
|
+
throwInvalidByteLength(structDecoder.fixedSize, bytesLength);
|
|
499
|
+
}
|
|
500
|
+
return readTopLevel(bytes, offset);
|
|
501
|
+
},
|
|
502
|
+
),
|
|
503
|
+
${use("VariableSizeDecoder", "solanaCodecsCore")}<Map<String, Object?>>() =>
|
|
504
|
+
${use("VariableSizeDecoder", "solanaCodecsCore")}<${fragmentFromString(typeName)}>(
|
|
505
|
+
read: readTopLevel,
|
|
506
|
+
maxSize: structDecoder.maxSize,
|
|
507
|
+
),
|
|
508
|
+
};`;
|
|
509
|
+
result.imports.mergeWith(discriminatorValidation.imports);
|
|
510
|
+
return result;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/utils/typeManifest.ts
|
|
514
|
+
function emptyTypeManifest() {
|
|
515
|
+
return {
|
|
516
|
+
type: emptyFragment(),
|
|
517
|
+
encoder: emptyFragment(),
|
|
518
|
+
decoder: emptyFragment(),
|
|
519
|
+
value: emptyFragment(),
|
|
520
|
+
isEnum: false
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
268
524
|
// src/visitors/getTypeManifestVisitor.ts
|
|
269
525
|
function getTypeManifestVisitor(input) {
|
|
270
526
|
const { nameApi, linkables, nonScalarEnums = [] } = input;
|
|
@@ -406,17 +662,23 @@ function getTypeManifestVisitor(input) {
|
|
|
406
662
|
},
|
|
407
663
|
visitArrayType(node, { self }) {
|
|
408
664
|
const itemManifest = visitorsCore.visit(node.item, self);
|
|
409
|
-
const
|
|
665
|
+
const encoderSizeExpr = getArraySizeExpression(node, "Encoder");
|
|
666
|
+
const decoderSizeExpr = getArraySizeExpression(node, "Decoder");
|
|
667
|
+
const itemType = fragmentFromString(itemManifest.type.content);
|
|
668
|
+
const itemEncoder = fragment`${use(
|
|
669
|
+
"transformEncoder",
|
|
670
|
+
"solanaCodecsCore"
|
|
671
|
+
)}(${itemManifest.encoder}, (${itemType} value) => value)`;
|
|
410
672
|
return {
|
|
411
673
|
type: fragment`List<${itemManifest.type}>`,
|
|
412
674
|
encoder: fragment`${use(
|
|
413
675
|
"getArrayEncoder",
|
|
414
676
|
"solanaCodecsDataStructures"
|
|
415
|
-
)}(${
|
|
677
|
+
)}<${itemType}>(${itemEncoder}${encoderSizeExpr})`,
|
|
416
678
|
decoder: fragment`${use(
|
|
417
679
|
"getArrayDecoder",
|
|
418
680
|
"solanaCodecsDataStructures"
|
|
419
|
-
)}(${itemManifest.decoder}${
|
|
681
|
+
)}(${itemManifest.decoder}${decoderSizeExpr})`,
|
|
420
682
|
value: emptyTypeManifest().value,
|
|
421
683
|
isEnum: false
|
|
422
684
|
};
|
|
@@ -424,40 +686,42 @@ function getTypeManifestVisitor(input) {
|
|
|
424
686
|
visitMapType(node, { self }) {
|
|
425
687
|
const keyManifest = visitorsCore.visit(node.key, self);
|
|
426
688
|
const valueManifest = visitorsCore.visit(node.value, self);
|
|
427
|
-
const
|
|
689
|
+
const encoderSizeExpr = getMapSizeExpression(node, "Encoder");
|
|
690
|
+
const decoderSizeExpr = getMapSizeExpression(node, "Decoder");
|
|
428
691
|
return {
|
|
429
692
|
type: fragment`Map<${keyManifest.type}, ${valueManifest.type}>`,
|
|
430
693
|
encoder: fragment`${use(
|
|
431
694
|
"getMapEncoder",
|
|
432
695
|
"solanaCodecsDataStructures"
|
|
433
|
-
)}(${keyManifest.encoder}, ${valueManifest.encoder}${
|
|
696
|
+
)}(${keyManifest.encoder}, ${valueManifest.encoder}${encoderSizeExpr})`,
|
|
434
697
|
decoder: fragment`${use(
|
|
435
698
|
"getMapDecoder",
|
|
436
699
|
"solanaCodecsDataStructures"
|
|
437
|
-
)}(${keyManifest.decoder}, ${valueManifest.decoder}${
|
|
700
|
+
)}(${keyManifest.decoder}, ${valueManifest.decoder}${decoderSizeExpr})`,
|
|
438
701
|
value: emptyTypeManifest().value,
|
|
439
702
|
isEnum: false
|
|
440
703
|
};
|
|
441
704
|
},
|
|
442
705
|
visitSetType(node, { self }) {
|
|
443
706
|
const itemManifest = visitorsCore.visit(node.item, self);
|
|
444
|
-
const
|
|
707
|
+
const encoderSizeExpr = getSetSizeExpression(node, "Encoder");
|
|
708
|
+
const decoderSizeExpr = getSetSizeExpression(node, "Decoder");
|
|
445
709
|
return {
|
|
446
710
|
type: fragment`Set<${itemManifest.type}>`,
|
|
447
711
|
encoder: fragment`${use(
|
|
448
712
|
"getSetEncoder",
|
|
449
713
|
"solanaCodecsDataStructures"
|
|
450
|
-
)}(${itemManifest.encoder}${
|
|
714
|
+
)}(${itemManifest.encoder}${encoderSizeExpr})`,
|
|
451
715
|
decoder: fragment`${use(
|
|
452
716
|
"getSetDecoder",
|
|
453
717
|
"solanaCodecsDataStructures"
|
|
454
|
-
)}(${itemManifest.decoder}${
|
|
718
|
+
)}(${itemManifest.decoder}${decoderSizeExpr})`,
|
|
455
719
|
value: emptyTypeManifest().value,
|
|
456
720
|
isEnum: false
|
|
457
721
|
};
|
|
458
722
|
},
|
|
459
723
|
visitTupleType(node, { self }) {
|
|
460
|
-
const itemManifests = node.items.map((item) => visitorsCore.visit(item, self));
|
|
724
|
+
const itemManifests = (node.items ?? []).map((item) => visitorsCore.visit(item, self));
|
|
461
725
|
const typeList = itemManifests.map((m) => m.type.content).join(", ");
|
|
462
726
|
const encoderList = itemManifests.map((m) => m.encoder);
|
|
463
727
|
const decoderList = itemManifests.map((m) => m.decoder);
|
|
@@ -490,8 +754,9 @@ function getTypeManifestVisitor(input) {
|
|
|
490
754
|
};
|
|
491
755
|
},
|
|
492
756
|
visitStructType(node, { self }) {
|
|
493
|
-
const
|
|
494
|
-
const
|
|
757
|
+
const nodeFields = node.fields ?? [];
|
|
758
|
+
const fields = nodeFields.map((f) => visitorsCore.visit(f, self));
|
|
759
|
+
const fieldNames = nodeFields.map((f) => f.name);
|
|
495
760
|
const typeStr = "Map<String, Object?>";
|
|
496
761
|
const encoderFields = fields.map((f, i) => `('${fieldNames[i]}', ${f.encoder.content})`).join(", ");
|
|
497
762
|
const encoderFrag = fragment`${use(
|
|
@@ -521,7 +786,7 @@ function getTypeManifestVisitor(input) {
|
|
|
521
786
|
return visitorsCore.visit(node.type, self);
|
|
522
787
|
},
|
|
523
788
|
visitEnumType(node, { self }) {
|
|
524
|
-
const isScalar = node.variants.every(
|
|
789
|
+
const isScalar = (node.variants ?? []).every(
|
|
525
790
|
(v) => v.kind === "enumEmptyVariantTypeNode"
|
|
526
791
|
);
|
|
527
792
|
if (isScalar) {
|
|
@@ -613,7 +878,7 @@ function getTypeManifestVisitor(input) {
|
|
|
613
878
|
encoder: fragment`${use(
|
|
614
879
|
"fixEncoderSize",
|
|
615
880
|
"solanaCodecsCore"
|
|
616
|
-
)}(${innerManifest.encoder}, ${fragmentFromString(String(node.size))})`,
|
|
881
|
+
)}(${innerManifest.encoder}, ${fragmentFromString(String(node.size))}, allowTruncation: false)`,
|
|
617
882
|
decoder: fragment`${use(
|
|
618
883
|
"fixDecoderSize",
|
|
619
884
|
"solanaCodecsCore"
|
|
@@ -627,9 +892,10 @@ function getTypeManifestVisitor(input) {
|
|
|
627
892
|
const bigIntFormats = /* @__PURE__ */ new Set(["u64", "u128", "i64", "i128"]);
|
|
628
893
|
let prefixManifest;
|
|
629
894
|
if (node.prefix.kind === "numberTypeNode" && bigIntFormats.has(node.prefix.format)) {
|
|
895
|
+
const codecName = getNumberCodecName(node.prefix.format);
|
|
630
896
|
prefixManifest = {
|
|
631
|
-
encoder: fragment
|
|
632
|
-
decoder: fragment
|
|
897
|
+
encoder: fragment`transformEncoder(${use(`get${codecName}Encoder`, "solanaCodecsNumbers")}(), (size) => BigInt.from(size))`,
|
|
898
|
+
decoder: fragment`transformDecoder(${use(`get${codecName}Decoder`, "solanaCodecsNumbers")}(), (size, _, __) => size.toInt())`
|
|
633
899
|
};
|
|
634
900
|
} else {
|
|
635
901
|
prefixManifest = visitorsCore.visit(node.prefix, self);
|
|
@@ -650,7 +916,7 @@ function getTypeManifestVisitor(input) {
|
|
|
650
916
|
},
|
|
651
917
|
visitHiddenPrefixType(node, { self }) {
|
|
652
918
|
const innerManifest = visitorsCore.visit(node.type, self);
|
|
653
|
-
const prefixes = node.prefix.map((p) => getHiddenAffixManifest(p, self));
|
|
919
|
+
const prefixes = (node.prefix ?? []).map((p) => getHiddenAffixManifest(p, self));
|
|
654
920
|
const prefixEncoders = prefixes.map((p) => p.encoder.content).join(", ");
|
|
655
921
|
const prefixDecoders = prefixes.map((p) => p.decoder.content).join(", ");
|
|
656
922
|
const encoderFrag = fragment`${use(
|
|
@@ -677,7 +943,7 @@ function getTypeManifestVisitor(input) {
|
|
|
677
943
|
},
|
|
678
944
|
visitHiddenSuffixType(node, { self }) {
|
|
679
945
|
const innerManifest = visitorsCore.visit(node.type, self);
|
|
680
|
-
const suffixes = node.suffix.map((s) => getHiddenAffixManifest(s, self));
|
|
946
|
+
const suffixes = (node.suffix ?? []).map((s) => getHiddenAffixManifest(s, self));
|
|
681
947
|
const suffixEncoders = suffixes.map((s) => s.encoder.content).join(", ");
|
|
682
948
|
const suffixDecoders = suffixes.map((s) => s.decoder.content).join(", ");
|
|
683
949
|
const encoderFrag = fragment`${use(
|
|
@@ -816,7 +1082,7 @@ function getNumberCodecExpression(format, codecType) {
|
|
|
816
1082
|
const name = getNumberCodecName(format);
|
|
817
1083
|
return `get${name}${codecType}()`;
|
|
818
1084
|
}
|
|
819
|
-
function getArraySizeExpression(node) {
|
|
1085
|
+
function getArraySizeExpression(node, codecType) {
|
|
820
1086
|
if (!("count" in node) || !node.count) return "";
|
|
821
1087
|
const count = node.count;
|
|
822
1088
|
switch (count.kind) {
|
|
@@ -829,13 +1095,13 @@ function getArraySizeExpression(node) {
|
|
|
829
1095
|
if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
|
|
830
1096
|
return "";
|
|
831
1097
|
}
|
|
832
|
-
return `, size: PrefixedArraySize(
|
|
1098
|
+
return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
|
|
833
1099
|
}
|
|
834
1100
|
default:
|
|
835
1101
|
return "";
|
|
836
1102
|
}
|
|
837
1103
|
}
|
|
838
|
-
function getMapSizeExpression(node) {
|
|
1104
|
+
function getMapSizeExpression(node, codecType) {
|
|
839
1105
|
if (!("count" in node) || !node.count) return "";
|
|
840
1106
|
const count = node.count;
|
|
841
1107
|
switch (count.kind) {
|
|
@@ -848,13 +1114,13 @@ function getMapSizeExpression(node) {
|
|
|
848
1114
|
if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
|
|
849
1115
|
return "";
|
|
850
1116
|
}
|
|
851
|
-
return `, size: PrefixedArraySize(
|
|
1117
|
+
return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
|
|
852
1118
|
}
|
|
853
1119
|
default:
|
|
854
1120
|
return "";
|
|
855
1121
|
}
|
|
856
1122
|
}
|
|
857
|
-
function getSetSizeExpression(node) {
|
|
1123
|
+
function getSetSizeExpression(node, codecType) {
|
|
858
1124
|
if (!("count" in node) || !node.count) return "";
|
|
859
1125
|
const count = node.count;
|
|
860
1126
|
switch (count.kind) {
|
|
@@ -867,7 +1133,7 @@ function getSetSizeExpression(node) {
|
|
|
867
1133
|
if (resolvedPrefix.format === "u32" && (!resolvedPrefix.endian || resolvedPrefix.endian === "le")) {
|
|
868
1134
|
return "";
|
|
869
1135
|
}
|
|
870
|
-
return `, size: PrefixedArraySize(
|
|
1136
|
+
return `, size: PrefixedArraySize(${getNumberCodecExpression(resolvedPrefix.format, codecType)})`;
|
|
871
1137
|
}
|
|
872
1138
|
default:
|
|
873
1139
|
return "";
|
|
@@ -964,19 +1230,52 @@ function hexToBytes(hex) {
|
|
|
964
1230
|
function getAccountPageFragment(node, scope) {
|
|
965
1231
|
const name = node.name;
|
|
966
1232
|
const typeName = scope.nameApi.dataType(name);
|
|
967
|
-
const
|
|
968
|
-
const fields = dataNode.fields;
|
|
1233
|
+
const fields = nodes.resolveNestedTypeNode(node.data).fields ?? [];
|
|
969
1234
|
const fieldManifests = fields.map((f) => ({
|
|
970
1235
|
field: f,
|
|
971
1236
|
manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
|
|
972
1237
|
}));
|
|
1238
|
+
const omittedFields = fields.filter(isOmittedDefaultField);
|
|
1239
|
+
const constructorFields = fields.filter(
|
|
1240
|
+
(field) => !isOmittedDefaultField(field)
|
|
1241
|
+
);
|
|
1242
|
+
const forcedFields = /* @__PURE__ */ new Set([
|
|
1243
|
+
...omittedFields,
|
|
1244
|
+
...fields.filter((field) => isFieldDiscriminator(field, node))
|
|
1245
|
+
]);
|
|
1246
|
+
const fieldDefaults = new Map(
|
|
1247
|
+
fieldManifests.flatMap(({ field, manifest }) => {
|
|
1248
|
+
if (!forcedFields.has(field) || field.defaultValue == null) return [];
|
|
1249
|
+
return [
|
|
1250
|
+
[
|
|
1251
|
+
field,
|
|
1252
|
+
getDartValueFragment(field.defaultValue, manifest.type.content)
|
|
1253
|
+
]
|
|
1254
|
+
];
|
|
1255
|
+
})
|
|
1256
|
+
);
|
|
1257
|
+
for (const field of forcedFields) {
|
|
1258
|
+
if (!fieldDefaults.has(field)) {
|
|
1259
|
+
throw new Error(
|
|
1260
|
+
`Forced field "${field.name}" on account "${node.name}" must have a deterministic default value.`
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
973
1264
|
const fieldDecls = fieldManifests.map(({ field: f, manifest }) => {
|
|
974
1265
|
return ` final ${manifest.type.content} ${camelCase(f.name)};`;
|
|
975
1266
|
}).join("\n");
|
|
976
|
-
const ctorParams =
|
|
977
|
-
const
|
|
1267
|
+
const ctorParams = constructorFields.map((f) => ` required this.${camelCase(f.name)},`).join("\n");
|
|
1268
|
+
const ctorInitializers = omittedFields.map((field) => {
|
|
1269
|
+
const fieldName = camelCase(field.name);
|
|
1270
|
+
return `${fieldName} = ${fieldDefaults.get(field).content}`;
|
|
1271
|
+
}).join(",\n ");
|
|
1272
|
+
const ctorKeyword = omittedFields.every(
|
|
1273
|
+
(field) => isConstDartValueNode(field.defaultValue)
|
|
1274
|
+
) ? "const " : "";
|
|
1275
|
+
const ctorSignature = constructorFields.length === 0 ? `${ctorKeyword}${typeName}()${ctorInitializers ? ` : ${ctorInitializers}` : ""};` : `${ctorKeyword}${typeName}({
|
|
978
1276
|
${ctorParams}
|
|
979
|
-
})
|
|
1277
|
+
})${ctorInitializers ? ` :
|
|
1278
|
+
${ctorInitializers}` : ""};`;
|
|
980
1279
|
const eqChecks = fields.length === 0 ? "true" : fields.map(
|
|
981
1280
|
(f) => `${camelCase(f.name)} == other.${camelCase(f.name)}`
|
|
982
1281
|
).join(" &&\n ");
|
|
@@ -991,10 +1290,11 @@ ${ctorParams}
|
|
|
991
1290
|
const decFields = fieldManifests.map(({ field: f, manifest }) => {
|
|
992
1291
|
return ` ('${f.name}', ${manifest.decoder.content}),`;
|
|
993
1292
|
}).join("\n");
|
|
994
|
-
const toMapFields = fields.map(
|
|
995
|
-
(f)
|
|
996
|
-
|
|
997
|
-
|
|
1293
|
+
const toMapFields = fields.map((f) => {
|
|
1294
|
+
const value = forcedFields.has(f) ? fieldDefaults.get(f).content : `value.${camelCase(f.name)}`;
|
|
1295
|
+
return ` '${f.name}': ${value},`;
|
|
1296
|
+
}).join("\n");
|
|
1297
|
+
const fromMapFields = fieldManifests.filter(({ field }) => !isOmittedDefaultField(field)).map(({ field: f, manifest }) => {
|
|
998
1298
|
const typeStr = manifest.type.content;
|
|
999
1299
|
const isNullable = typeStr.endsWith("?");
|
|
1000
1300
|
const accessor = isNullable ? `map['${f.name}']` : `map['${f.name}']!`;
|
|
@@ -1008,6 +1308,19 @@ ${ctorParams}
|
|
|
1008
1308
|
/// The size of the [${fragmentFromString(typeName)}] account data in bytes.
|
|
1009
1309
|
const int ${fragmentFromString(scope.nameApi.accountSizeConstant(name))} = ${fragmentFromString(String(node.size))};` : emptyFragment();
|
|
1010
1310
|
const discFragment = getDiscriminatorConstantsFragment(node, scope);
|
|
1311
|
+
const discriminatorValidation = getDiscriminatorValidationFragment(
|
|
1312
|
+
node,
|
|
1313
|
+
scope
|
|
1314
|
+
);
|
|
1315
|
+
const topLevelDecoder = getTopLevelDecoderFragment({
|
|
1316
|
+
typeName,
|
|
1317
|
+
description: `${name} account decoder`,
|
|
1318
|
+
discriminatorValidation,
|
|
1319
|
+
fromMapFields,
|
|
1320
|
+
requireExactConsumption: (node.discriminators ?? []).some(
|
|
1321
|
+
(discriminator) => discriminator.kind === "sizeDiscriminatorNode"
|
|
1322
|
+
)
|
|
1323
|
+
});
|
|
1011
1324
|
const parts = [
|
|
1012
1325
|
fragment`// Auto-generated. Do not edit.
|
|
1013
1326
|
// ignore_for_file: type=lint
|
|
@@ -1067,12 +1380,7 @@ Decoder<${fragmentFromString(typeName)}> ${fragmentFromString(decoderName)}() {
|
|
|
1067
1380
|
${fragmentFromString(decFields)}
|
|
1068
1381
|
]);
|
|
1069
1382
|
|
|
1070
|
-
|
|
1071
|
-
structDecoder,
|
|
1072
|
-
(Map<String, Object?> map, Uint8List bytes, int offset) => ${fragmentFromString(typeName)}(
|
|
1073
|
-
${fragmentFromString(fromMapFields)}
|
|
1074
|
-
),
|
|
1075
|
-
);
|
|
1383
|
+
${topLevelDecoder}
|
|
1076
1384
|
}
|
|
1077
1385
|
|
|
1078
1386
|
Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragmentFromString(codecName)}() {
|
|
@@ -1088,8 +1396,19 @@ Account<${fragmentFromString(typeName)}> ${fragmentFromString(decodeFnName)}(Enc
|
|
|
1088
1396
|
result.imports.mergeWith(manifest.decoder.imports);
|
|
1089
1397
|
result.imports.mergeWith(manifest.type.imports);
|
|
1090
1398
|
}
|
|
1399
|
+
for (const defaultValue of fieldDefaults.values()) {
|
|
1400
|
+
result.imports.mergeWith(defaultValue.imports);
|
|
1401
|
+
}
|
|
1091
1402
|
return result;
|
|
1092
1403
|
}
|
|
1404
|
+
function isOmittedDefaultField(field) {
|
|
1405
|
+
return field.defaultValue != null && field.defaultValueStrategy === "omitted";
|
|
1406
|
+
}
|
|
1407
|
+
function isFieldDiscriminator(field, node) {
|
|
1408
|
+
return (node.discriminators ?? []).some(
|
|
1409
|
+
(discriminator) => discriminator.kind === "fieldDiscriminatorNode" && discriminator.name === field.name
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1093
1412
|
|
|
1094
1413
|
// src/fragments/errorPage.ts
|
|
1095
1414
|
function getErrorPageFragment(programNode, scope) {
|
|
@@ -1150,7 +1469,7 @@ function getIndexPageFragment(fileNames, relativePath = "") {
|
|
|
1150
1469
|
"// Auto-generated. Do not edit.\n// ignore_for_file: type=lint\n"
|
|
1151
1470
|
);
|
|
1152
1471
|
}
|
|
1153
|
-
const exports
|
|
1472
|
+
const exports = fileNames.sort().map((f) => {
|
|
1154
1473
|
const path = relativePath ? `${relativePath}/${f}` : f;
|
|
1155
1474
|
return `export '${path}';`;
|
|
1156
1475
|
}).join("\n");
|
|
@@ -1158,17 +1477,17 @@ function getIndexPageFragment(fileNames, relativePath = "") {
|
|
|
1158
1477
|
`// Auto-generated. Do not edit.
|
|
1159
1478
|
// ignore_for_file: type=lint
|
|
1160
1479
|
|
|
1161
|
-
${exports
|
|
1480
|
+
${exports}
|
|
1162
1481
|
`
|
|
1163
1482
|
);
|
|
1164
1483
|
}
|
|
1165
1484
|
function getRootIndexPageFragment(categories) {
|
|
1166
|
-
const exports
|
|
1485
|
+
const exports = categories.sort().map((cat) => `export '${cat}/${cat}.dart';`).join("\n");
|
|
1167
1486
|
return fragmentFromString(
|
|
1168
1487
|
`// Auto-generated. Do not edit.
|
|
1169
1488
|
// ignore_for_file: type=lint
|
|
1170
1489
|
|
|
1171
|
-
${exports
|
|
1490
|
+
${exports}
|
|
1172
1491
|
`
|
|
1173
1492
|
);
|
|
1174
1493
|
}
|
|
@@ -1178,30 +1497,62 @@ function getInstructionPageFragment(node, scope) {
|
|
|
1178
1497
|
const instrFnName = scope.nameApi.instructionFunction(name);
|
|
1179
1498
|
const parseFnName = scope.nameApi.instructionParseFunction(name);
|
|
1180
1499
|
const accounts = node.accounts ?? [];
|
|
1181
|
-
const args = (node.arguments ?? []).filter(
|
|
1182
|
-
(arg) => !isDiscriminatorArg(arg, node)
|
|
1183
|
-
);
|
|
1184
1500
|
const allArgs = node.arguments ?? [];
|
|
1501
|
+
const optionalAccountStrategy = node.optionalAccountStrategy ?? "programId";
|
|
1502
|
+
if (optionalAccountStrategy !== "programId" && optionalAccountStrategy !== "omitted") {
|
|
1503
|
+
throw new Error(
|
|
1504
|
+
`Unsupported optional account strategy on instruction "${node.name}": ${optionalAccountStrategy}`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
const args = allArgs.filter(
|
|
1508
|
+
(arg) => !isDiscriminatorArg(arg, node) && !isOmittedDefaultArgument(arg)
|
|
1509
|
+
);
|
|
1185
1510
|
const dataClassName = `${typeName}InstructionData`;
|
|
1186
|
-
const allArgManifests =
|
|
1511
|
+
const allArgManifests = (node.arguments ?? []).map((arg) => ({
|
|
1187
1512
|
arg,
|
|
1188
1513
|
manifest: visitorsCore.visit(arg.type, scope.typeManifestVisitor)
|
|
1189
1514
|
}));
|
|
1515
|
+
const argDefaultValues = new Map(
|
|
1516
|
+
allArgManifests.flatMap(({ arg, manifest }) => {
|
|
1517
|
+
if (arg.defaultValue == null) return [];
|
|
1518
|
+
const needsRenderedDefault = isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node) || arg.defaultValue.kind !== "accountBumpValueNode";
|
|
1519
|
+
if (!needsRenderedDefault) return [];
|
|
1520
|
+
return [
|
|
1521
|
+
[
|
|
1522
|
+
arg,
|
|
1523
|
+
getDartValueFragment(arg.defaultValue, manifest.type.content)
|
|
1524
|
+
]
|
|
1525
|
+
];
|
|
1526
|
+
})
|
|
1527
|
+
);
|
|
1528
|
+
for (const arg of allArgs.filter(
|
|
1529
|
+
(candidate) => isDiscriminatorArg(candidate, node)
|
|
1530
|
+
)) {
|
|
1531
|
+
if (!argDefaultValues.has(arg)) {
|
|
1532
|
+
throw new Error(
|
|
1533
|
+
`Field discriminator "${arg.name}" on instruction "${node.name}" must reference a field with a default value.`
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1190
1537
|
const dataFieldDecls = allArgManifests.map(({ arg, manifest }) => {
|
|
1191
1538
|
const fieldName = camelCase(arg.name);
|
|
1192
1539
|
return ` final ${manifest.type.content} ${fieldName};`;
|
|
1193
1540
|
}).join("\n");
|
|
1194
1541
|
const dataCtorParams = allArgManifests.map(({ arg, manifest }) => {
|
|
1195
1542
|
const fieldName = camelCase(arg.name);
|
|
1543
|
+
if (isOmittedDefaultArgument(arg)) return "";
|
|
1196
1544
|
if (isDiscriminatorArg(arg, node)) {
|
|
1197
|
-
return isConstDefaultValue(arg.defaultValue) ? ` this.${fieldName} = ${
|
|
1545
|
+
return isConstDefaultValue(arg.defaultValue) ? ` this.${fieldName} = ${argDefaultValues.get(arg).content},` : ` ${manifest.type.content}? ${fieldName},`;
|
|
1198
1546
|
}
|
|
1199
1547
|
return ` required this.${fieldName},`;
|
|
1200
|
-
}).join("\n");
|
|
1548
|
+
}).filter(Boolean).join("\n");
|
|
1201
1549
|
const dataCtorInitializers = allArgManifests.map(({ arg }) => {
|
|
1202
1550
|
const fieldName = camelCase(arg.name);
|
|
1551
|
+
if (isOmittedDefaultArgument(arg)) {
|
|
1552
|
+
return ` ${fieldName} = ${argDefaultValues.get(arg).content}`;
|
|
1553
|
+
}
|
|
1203
1554
|
if (isDiscriminatorArg(arg, node) && !isConstDefaultValue(arg.defaultValue)) {
|
|
1204
|
-
return ` ${fieldName} = ${fieldName} ?? ${
|
|
1555
|
+
return ` ${fieldName} = ${fieldName} ?? ${argDefaultValues.get(arg).content}`;
|
|
1205
1556
|
}
|
|
1206
1557
|
return null;
|
|
1207
1558
|
}).filter((value) => value !== null).join(",\n");
|
|
@@ -1211,16 +1562,26 @@ function getInstructionPageFragment(node, scope) {
|
|
|
1211
1562
|
const decFields = allArgManifests.map(({ arg, manifest }) => {
|
|
1212
1563
|
return ` ('${arg.name}', ${manifest.decoder.content}),`;
|
|
1213
1564
|
}).join("\n");
|
|
1214
|
-
const toMapFields = allArgs.map(
|
|
1215
|
-
(arg)
|
|
1216
|
-
|
|
1217
|
-
|
|
1565
|
+
const toMapFields = allArgs.map((arg) => {
|
|
1566
|
+
const value = isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node) ? argDefaultValues.get(arg).content : `value.${camelCase(arg.name)}`;
|
|
1567
|
+
return ` '${arg.name}': ${value},`;
|
|
1568
|
+
}).join("\n");
|
|
1569
|
+
const fromMapFields = allArgManifests.filter(({ arg }) => !isOmittedDefaultArgument(arg)).map(({ arg, manifest }) => {
|
|
1218
1570
|
const typeStr = manifest.type.content;
|
|
1219
1571
|
const isNullable = typeStr.endsWith("?");
|
|
1220
1572
|
const accessor = isNullable ? `map['${arg.name}']` : `map['${arg.name}']!`;
|
|
1221
1573
|
return ` ${camelCase(arg.name)}: ${accessor} as ${typeStr},`;
|
|
1222
1574
|
}).join("\n");
|
|
1223
|
-
const dataCtorKeyword =
|
|
1575
|
+
const dataCtorKeyword = allArgs.every(
|
|
1576
|
+
(arg) => !isOmittedDefaultArgument(arg) || isConstDartValueNode(arg.defaultValue)
|
|
1577
|
+
) && allArgs.every(
|
|
1578
|
+
(arg) => !isDiscriminatorArg(arg, node) || isConstDefaultValue(arg.defaultValue)
|
|
1579
|
+
) ? "const " : "";
|
|
1580
|
+
const dataCtorSignature = dataCtorParams ? `${dataCtorKeyword}${dataClassName}({
|
|
1581
|
+
${dataCtorParams}
|
|
1582
|
+
})${dataCtorInitializers ? ` :
|
|
1583
|
+
${dataCtorInitializers}` : ""};` : `${dataCtorKeyword}${dataClassName}()${dataCtorInitializers ? ` :
|
|
1584
|
+
${dataCtorInitializers}` : ""};`;
|
|
1224
1585
|
const dataEncoderName = `get${typeName}InstructionDataEncoder`;
|
|
1225
1586
|
const dataDecoderName = `get${typeName}InstructionDataDecoder`;
|
|
1226
1587
|
const dataCodecName = `get${typeName}InstructionDataCodec`;
|
|
@@ -1238,7 +1599,7 @@ function getInstructionPageFragment(node, scope) {
|
|
|
1238
1599
|
const manifest = argManifestMap.get(arg);
|
|
1239
1600
|
const fieldName = camelCase(arg.name);
|
|
1240
1601
|
const typeStr = manifest.type.content;
|
|
1241
|
-
const hasDefault = arg.defaultValue != null;
|
|
1602
|
+
const hasDefault = arg.defaultValue != null && arg.defaultValue.kind !== "accountBumpValueNode";
|
|
1242
1603
|
if (hasDefault) {
|
|
1243
1604
|
const nullableType = typeStr.endsWith("?") ? typeStr : `${typeStr}?`;
|
|
1244
1605
|
return ` ${nullableType} ${fieldName},`;
|
|
@@ -1250,18 +1611,33 @@ function getInstructionPageFragment(node, scope) {
|
|
|
1250
1611
|
const role = getAccountRole(acc);
|
|
1251
1612
|
const isOptional = acc.isOptional ?? false;
|
|
1252
1613
|
if (isOptional) {
|
|
1253
|
-
|
|
1614
|
+
if (optionalAccountStrategy === "omitted") {
|
|
1615
|
+
return ` if (${fieldName} != null) AccountMeta(address: ${fieldName}, role: ${role}),`;
|
|
1616
|
+
}
|
|
1617
|
+
return ` if (${fieldName} != null) AccountMeta(address: ${fieldName}, role: ${role}) else AccountMeta(address: ${instrProgramParam}, role: AccountRole.readonly),`;
|
|
1254
1618
|
}
|
|
1255
1619
|
return ` AccountMeta(address: ${fieldName}, role: ${role}),`;
|
|
1256
1620
|
}).join("\n");
|
|
1257
1621
|
const dataConstruction = allArgs.map((arg) => {
|
|
1258
1622
|
const fieldName = camelCase(arg.name);
|
|
1259
|
-
if (isDiscriminatorArg(arg, node)) {
|
|
1623
|
+
if (isOmittedDefaultArgument(arg) || isDiscriminatorArg(arg, node)) {
|
|
1260
1624
|
return "";
|
|
1261
1625
|
}
|
|
1262
|
-
|
|
1626
|
+
const skipDefault = arg.defaultValue?.kind === "accountBumpValueNode";
|
|
1627
|
+
return ` ${fieldName}: ${fieldName}${arg.defaultValue != null && !skipDefault ? ` ?? ${argDefaultValues.get(arg).content}` : ""},`;
|
|
1263
1628
|
}).filter(Boolean).join("\n");
|
|
1264
1629
|
const discFragment = getDiscriminatorConstantsFragment(node, scope);
|
|
1630
|
+
const discriminatorValidation = getDiscriminatorValidationFragment(
|
|
1631
|
+
node,
|
|
1632
|
+
scope
|
|
1633
|
+
);
|
|
1634
|
+
const topLevelDecoder = getTopLevelDecoderFragment({
|
|
1635
|
+
typeName: dataClassName,
|
|
1636
|
+
description: `${name} instruction decoder`,
|
|
1637
|
+
discriminatorValidation,
|
|
1638
|
+
fromMapFields,
|
|
1639
|
+
requireExactConsumption: true
|
|
1640
|
+
});
|
|
1265
1641
|
const parts = [
|
|
1266
1642
|
fragment`// Auto-generated. Do not edit.
|
|
1267
1643
|
// ignore_for_file: type=lint
|
|
@@ -1285,10 +1661,7 @@ ${use("AccountRole", "solanaInstructions")}`
|
|
|
1285
1661
|
parts.push(fragment`
|
|
1286
1662
|
@immutable
|
|
1287
1663
|
class ${fragmentFromString(dataClassName)} {
|
|
1288
|
-
${fragmentFromString(
|
|
1289
|
-
${fragmentFromString(dataCtorParams)}
|
|
1290
|
-
})${fragmentFromString(dataCtorInitializers ? ` :
|
|
1291
|
-
${dataCtorInitializers}` : "")};
|
|
1664
|
+
${fragmentFromString(dataCtorSignature)}
|
|
1292
1665
|
|
|
1293
1666
|
${fragmentFromString(dataFieldDecls)}
|
|
1294
1667
|
}`);
|
|
@@ -1311,12 +1684,7 @@ Decoder<${fragmentFromString(dataClassName)}> ${fragmentFromString(dataDecoderNa
|
|
|
1311
1684
|
${fragmentFromString(decFields)}
|
|
1312
1685
|
]);
|
|
1313
1686
|
|
|
1314
|
-
|
|
1315
|
-
structDecoder,
|
|
1316
|
-
(Map<String, Object?> map, Uint8List bytes, int offset) => ${fragmentFromString(dataClassName)}(
|
|
1317
|
-
${fragmentFromString(fromMapFields)}
|
|
1318
|
-
),
|
|
1319
|
-
);
|
|
1687
|
+
${topLevelDecoder}
|
|
1320
1688
|
}
|
|
1321
1689
|
|
|
1322
1690
|
Codec<${fragmentFromString(dataClassName)}, ${fragmentFromString(dataClassName)}> ${fragmentFromString(dataCodecName)}() {
|
|
@@ -1352,6 +1720,9 @@ ${fragmentFromString(dataClassName)} ${fragmentFromString(parseFnName)}(Instruct
|
|
|
1352
1720
|
result.imports.mergeWith(manifest.decoder.imports);
|
|
1353
1721
|
result.imports.mergeWith(manifest.type.imports);
|
|
1354
1722
|
}
|
|
1723
|
+
for (const defaultValue of argDefaultValues.values()) {
|
|
1724
|
+
result.imports.mergeWith(defaultValue.imports);
|
|
1725
|
+
}
|
|
1355
1726
|
return result;
|
|
1356
1727
|
}
|
|
1357
1728
|
function getAccountRole(acc) {
|
|
@@ -1368,19 +1739,6 @@ function isDiscriminatorArg(arg, node) {
|
|
|
1368
1739
|
(d) => d.kind === "fieldDiscriminatorNode" && d.name === arg.name
|
|
1369
1740
|
);
|
|
1370
1741
|
}
|
|
1371
|
-
function getDiscriminatorDefault(arg, _node) {
|
|
1372
|
-
if (arg.defaultValue) {
|
|
1373
|
-
if (arg.defaultValue.kind === "numberValueNode") {
|
|
1374
|
-
return String(arg.defaultValue.number);
|
|
1375
|
-
}
|
|
1376
|
-
if (arg.defaultValue.kind === "bytesValueNode") {
|
|
1377
|
-
const data = arg.defaultValue.data;
|
|
1378
|
-
const bytes = data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
|
|
1379
|
-
return `Uint8List.fromList([${bytes.join(", ")}])`;
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
return "0";
|
|
1383
|
-
}
|
|
1384
1742
|
function isConstDefaultValue(defaultValue) {
|
|
1385
1743
|
if (!defaultValue) return false;
|
|
1386
1744
|
switch (defaultValue.kind) {
|
|
@@ -1393,33 +1751,8 @@ function isConstDefaultValue(defaultValue) {
|
|
|
1393
1751
|
return false;
|
|
1394
1752
|
}
|
|
1395
1753
|
}
|
|
1396
|
-
function
|
|
1397
|
-
|
|
1398
|
-
const dv = arg.defaultValue;
|
|
1399
|
-
switch (dv.kind) {
|
|
1400
|
-
case "numberValueNode":
|
|
1401
|
-
return String(dv.number);
|
|
1402
|
-
case "booleanValueNode":
|
|
1403
|
-
return String(dv.boolean);
|
|
1404
|
-
case "stringValueNode":
|
|
1405
|
-
return `'${dv.string}'`;
|
|
1406
|
-
case "publicKeyValueNode": {
|
|
1407
|
-
const wellKnownName = WELL_KNOWN_ADDRESSES.get(dv.publicKey);
|
|
1408
|
-
if (wellKnownName) {
|
|
1409
|
-
use(wellKnownName, "solanaAddresses");
|
|
1410
|
-
return wellKnownName;
|
|
1411
|
-
}
|
|
1412
|
-
return `Address('${dv.publicKey}')`;
|
|
1413
|
-
}
|
|
1414
|
-
case "noneValueNode":
|
|
1415
|
-
return "null";
|
|
1416
|
-
case "bytesValueNode": {
|
|
1417
|
-
const bytes = dv.data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
|
|
1418
|
-
return `Uint8List.fromList([${bytes.join(", ")}])`;
|
|
1419
|
-
}
|
|
1420
|
-
default:
|
|
1421
|
-
return "null";
|
|
1422
|
-
}
|
|
1754
|
+
function isOmittedDefaultArgument(arg) {
|
|
1755
|
+
return arg.defaultValue != null && arg.defaultValueStrategy === "omitted";
|
|
1423
1756
|
}
|
|
1424
1757
|
function getPdaPageFragment(node, scope) {
|
|
1425
1758
|
const name = node.name;
|
|
@@ -1538,8 +1871,6 @@ function bytesValueToDart(hex) {
|
|
|
1538
1871
|
}
|
|
1539
1872
|
return `[${pairs.join(", ")}]`;
|
|
1540
1873
|
}
|
|
1541
|
-
|
|
1542
|
-
// src/fragments/programPage.ts
|
|
1543
1874
|
function getProgramPageFragment(node, scope) {
|
|
1544
1875
|
const name = node.name;
|
|
1545
1876
|
const addressConstName = scope.nameApi.programAddressConstant(name);
|
|
@@ -1571,41 +1902,171 @@ enum ${fragmentFromString(pascalCase(name))}Account {
|
|
|
1571
1902
|
${fragmentFromString(accountVariants)}
|
|
1572
1903
|
}`);
|
|
1573
1904
|
}
|
|
1574
|
-
const instructions = node
|
|
1905
|
+
const instructions = nodes.getAllInstructionsWithSubs(node);
|
|
1575
1906
|
if (instructions.length > 0) {
|
|
1907
|
+
const programName = pascalCase(name);
|
|
1908
|
+
const instructionEnum = `${programName}Instruction`;
|
|
1576
1909
|
const instrVariants = instructions.map((instr) => ` ${camelCase(instr.name)},`).join("\n");
|
|
1577
1910
|
parts.push(fragment`
|
|
1578
|
-
/// Known instructions for the ${fragmentFromString(
|
|
1579
|
-
enum ${fragmentFromString(
|
|
1911
|
+
/// Known instructions for the ${fragmentFromString(programName)} program.
|
|
1912
|
+
enum ${fragmentFromString(instructionEnum)} {
|
|
1580
1913
|
${fragmentFromString(instrVariants)}
|
|
1581
1914
|
}`);
|
|
1915
|
+
const identifiableInstructions = instructions.map((instruction) => ({
|
|
1916
|
+
instruction,
|
|
1917
|
+
condition: getInstructionDiscriminatorCondition(instruction, scope)
|
|
1918
|
+
})).filter(({ condition }) => condition !== null);
|
|
1919
|
+
if (identifiableInstructions.length > 0) {
|
|
1920
|
+
const identifyBranches = identifiableInstructions.map(
|
|
1921
|
+
({ instruction, condition }) => fragment` if (${condition}) {
|
|
1922
|
+
return ${fragmentFromString(instructionEnum)}.${fragmentFromString(camelCase(instruction.name))};
|
|
1923
|
+
}`
|
|
1924
|
+
);
|
|
1925
|
+
const parsedBase = `Parsed${programName}Instruction`;
|
|
1926
|
+
const parsedClasses = instructions.map((instruction) => {
|
|
1927
|
+
const instructionName = pascalCase(instruction.name);
|
|
1928
|
+
const variant = camelCase(instruction.name);
|
|
1929
|
+
const parsedClass = `Parsed${instructionName}`;
|
|
1930
|
+
const dataClass = `${instructionName}InstructionData`;
|
|
1931
|
+
return fragment`/// A parsed ${fragmentFromString(instructionName)} instruction.
|
|
1932
|
+
final class ${fragmentFromString(parsedClass)} extends ${fragmentFromString(parsedBase)} {
|
|
1933
|
+
const ${fragmentFromString(parsedClass)}({required this.data})
|
|
1934
|
+
: super(${fragmentFromString(instructionEnum)}.${fragmentFromString(variant)});
|
|
1935
|
+
|
|
1936
|
+
final ${use(dataClass, "../instructions/instructions.dart")} data;
|
|
1937
|
+
}`;
|
|
1938
|
+
});
|
|
1939
|
+
const parseBranches = instructions.map((instruction) => {
|
|
1940
|
+
const instructionName = pascalCase(instruction.name);
|
|
1941
|
+
const variant = camelCase(instruction.name);
|
|
1942
|
+
const parsedClass = `Parsed${instructionName}`;
|
|
1943
|
+
const parseFunction = scope.nameApi.instructionParseFunction(
|
|
1944
|
+
instruction.name
|
|
1945
|
+
);
|
|
1946
|
+
return fragment` ${fragmentFromString(instructionEnum)}.${fragmentFromString(variant)} => ${fragmentFromString(parsedClass)}(
|
|
1947
|
+
data: ${use(parseFunction, "../instructions/instructions.dart")}(instruction),
|
|
1948
|
+
),`;
|
|
1949
|
+
});
|
|
1950
|
+
parts.push(fragment`
|
|
1951
|
+
/// Identifies the type of a ${fragmentFromString(programName)} instruction.
|
|
1952
|
+
${fragmentFromString(instructionEnum)} identify${fragmentFromString(programName)}Instruction(
|
|
1953
|
+
${use("Uint8List", "dartTypedData")} data,
|
|
1954
|
+
) {
|
|
1955
|
+
${mergeFragments(identifyBranches, (cs) => cs.join("\n"))}
|
|
1956
|
+
|
|
1957
|
+
throw ${use("SolanaError", "solanaErrors")}(
|
|
1958
|
+
${use("SolanaErrorCode", "solanaErrors")}.programClientsFailedToIdentifyInstruction,
|
|
1959
|
+
{
|
|
1960
|
+
'instructionData': data,
|
|
1961
|
+
'programName': '${fragmentFromString(name)}',
|
|
1962
|
+
},
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/// A parsed instruction from the ${fragmentFromString(programName)} program.
|
|
1967
|
+
sealed class ${fragmentFromString(parsedBase)} {
|
|
1968
|
+
const ${fragmentFromString(parsedBase)}(this.instructionType);
|
|
1969
|
+
|
|
1970
|
+
final ${fragmentFromString(instructionEnum)} instructionType;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
${mergeFragments(parsedClasses, (cs) => cs.join("\n\n"))}
|
|
1974
|
+
|
|
1975
|
+
/// Parses a ${fragmentFromString(programName)} instruction.
|
|
1976
|
+
${fragmentFromString(parsedBase)} parse${fragmentFromString(programName)}Instruction(
|
|
1977
|
+
${use("Instruction", "solanaInstructions")} instruction,
|
|
1978
|
+
) {
|
|
1979
|
+
return switch (identify${fragmentFromString(programName)}Instruction(
|
|
1980
|
+
instruction.data ?? Uint8List(0),
|
|
1981
|
+
)) {
|
|
1982
|
+
${mergeFragments(parseBranches, (cs) => cs.join("\n"))}
|
|
1983
|
+
};
|
|
1984
|
+
}`);
|
|
1985
|
+
}
|
|
1582
1986
|
}
|
|
1583
1987
|
return mergeFragments(parts, (cs) => cs.join("\n"));
|
|
1584
1988
|
}
|
|
1989
|
+
function getInstructionDiscriminatorCondition(instruction, scope) {
|
|
1990
|
+
const discriminators = instruction.discriminators ?? [];
|
|
1991
|
+
if (discriminators.length === 0) return null;
|
|
1992
|
+
const conditions = discriminators.map((discriminator) => {
|
|
1993
|
+
switch (discriminator.kind) {
|
|
1994
|
+
case "sizeDiscriminatorNode":
|
|
1995
|
+
return fragment`data.length == ${discriminator.size}`;
|
|
1996
|
+
case "constantDiscriminatorNode": {
|
|
1997
|
+
const manifest = visitorsCore.visit(
|
|
1998
|
+
discriminator.constant.type,
|
|
1999
|
+
scope.typeManifestVisitor
|
|
2000
|
+
);
|
|
2001
|
+
const value = getValueFragment(
|
|
2002
|
+
discriminator.constant.value,
|
|
2003
|
+
manifest.type.content
|
|
2004
|
+
);
|
|
2005
|
+
if (value === null) return null;
|
|
2006
|
+
return fragment`${use("containsBytes", "solanaCodecsCore")}(data, ${manifest.encoder}.encode(${value}), ${discriminator.offset})`;
|
|
2007
|
+
}
|
|
2008
|
+
case "fieldDiscriminatorNode": {
|
|
2009
|
+
const argument = (instruction.arguments ?? []).find(
|
|
2010
|
+
(candidate) => candidate.name === discriminator.name
|
|
2011
|
+
);
|
|
2012
|
+
if (argument?.defaultValue == null) return null;
|
|
2013
|
+
const manifest = visitorsCore.visit(argument.type, scope.typeManifestVisitor);
|
|
2014
|
+
const value = getValueFragment(
|
|
2015
|
+
argument.defaultValue,
|
|
2016
|
+
manifest.type.content
|
|
2017
|
+
);
|
|
2018
|
+
if (value === null) return null;
|
|
2019
|
+
return fragment`${use("containsBytes", "solanaCodecsCore")}(data, ${manifest.encoder}.encode(${value}), ${discriminator.offset})`;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
});
|
|
2023
|
+
if (conditions.some((condition) => condition === null)) return null;
|
|
2024
|
+
return mergeFragments(conditions, (cs) => cs.join(" && "));
|
|
2025
|
+
}
|
|
2026
|
+
function getValueFragment(value, dartType) {
|
|
2027
|
+
switch (value.kind) {
|
|
2028
|
+
case "numberValueNode":
|
|
2029
|
+
return fragmentFromString(
|
|
2030
|
+
dartType === "BigInt" ? `BigInt.from(${value.number})` : String(value.number)
|
|
2031
|
+
);
|
|
2032
|
+
case "booleanValueNode":
|
|
2033
|
+
return fragmentFromString(String(value.boolean));
|
|
2034
|
+
case "stringValueNode":
|
|
2035
|
+
return fragmentFromString(`'${value.string.replaceAll("'", "\\'")}'`);
|
|
2036
|
+
case "bytesValueNode": {
|
|
2037
|
+
const clean = value.data.replace(/^0x/, "");
|
|
2038
|
+
const bytes = clean.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? [];
|
|
2039
|
+
return fragment`${use("Uint8List", "dartTypedData")}.fromList([${fragmentFromString(bytes.join(", "))}])`;
|
|
2040
|
+
}
|
|
2041
|
+
default:
|
|
2042
|
+
return null;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
1585
2045
|
function getTypePageFragment(node, scope) {
|
|
1586
2046
|
const name = node.name;
|
|
1587
2047
|
scope.nameApi.dataType(name);
|
|
1588
2048
|
const typeNode = node.type;
|
|
1589
2049
|
if (typeNode.kind === "enumTypeNode") {
|
|
1590
|
-
const
|
|
2050
|
+
const variants = typeNode.variants ?? [];
|
|
2051
|
+
const isScalar = variants.every(
|
|
1591
2052
|
(v) => v.kind === "enumEmptyVariantTypeNode"
|
|
1592
2053
|
);
|
|
1593
2054
|
if (isScalar) {
|
|
1594
|
-
return getScalarEnumPageFragment(node, scope);
|
|
2055
|
+
return getScalarEnumPageFragment(node, variants, scope);
|
|
1595
2056
|
}
|
|
1596
|
-
return getDataEnumPageFragment(node, scope);
|
|
2057
|
+
return getDataEnumPageFragment(node, variants, scope);
|
|
1597
2058
|
}
|
|
1598
2059
|
if (typeNode.kind === "structTypeNode") {
|
|
1599
2060
|
return getStructPageFragment(node, scope);
|
|
1600
2061
|
}
|
|
1601
2062
|
return getTypeAliasPageFragment(node, scope);
|
|
1602
2063
|
}
|
|
1603
|
-
function getScalarEnumPageFragment(node, scope) {
|
|
2064
|
+
function getScalarEnumPageFragment(node, enumVariants, scope) {
|
|
1604
2065
|
const name = node.name;
|
|
1605
2066
|
const typeName = scope.nameApi.dataType(name);
|
|
1606
2067
|
const enumNode = node.type;
|
|
1607
2068
|
if (enumNode.kind !== "enumTypeNode") return emptyFragment();
|
|
1608
|
-
const variants =
|
|
2069
|
+
const variants = enumVariants.map((v) => {
|
|
1609
2070
|
const variantName = scope.nameApi.enumVariant(v.name);
|
|
1610
2071
|
return variantName;
|
|
1611
2072
|
});
|
|
@@ -1616,6 +2077,14 @@ function getScalarEnumPageFragment(node, scope) {
|
|
|
1616
2077
|
const resolvedSize = nodes.resolveNestedTypeNode(enumNode.size);
|
|
1617
2078
|
const sizeType = resolvedSize.format ?? "u8";
|
|
1618
2079
|
const sizeCodecName = getNumberCodecName2(sizeType);
|
|
2080
|
+
const isU64 = sizeType === "u64";
|
|
2081
|
+
const encodedVariantIndex = isU64 ? "BigInt.from(value.index)" : "value.index";
|
|
2082
|
+
const decodedVariant = isU64 ? `(BigInt value, Uint8List bytes, int offset) {
|
|
2083
|
+
if (value.isNegative || value >= BigInt.from(${typeName}.values.length)) {
|
|
2084
|
+
throw RangeError('Invalid ${typeName} discriminator: ' + value.toString());
|
|
2085
|
+
}
|
|
2086
|
+
return ${typeName}.values[value.toInt()];
|
|
2087
|
+
}` : `(int value, Uint8List bytes, int offset) => ${typeName}.values[value]`;
|
|
1619
2088
|
return fragment`// Auto-generated. Do not edit.
|
|
1620
2089
|
// ignore_for_file: type=lint
|
|
1621
2090
|
|
|
@@ -1636,14 +2105,14 @@ ${fragmentFromString(variantLines)}
|
|
|
1636
2105
|
Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
|
|
1637
2106
|
return transformEncoder(
|
|
1638
2107
|
get${fragmentFromString(sizeCodecName)}Encoder(),
|
|
1639
|
-
(${fragmentFromString(typeName)} value) =>
|
|
2108
|
+
(${fragmentFromString(typeName)} value) => ${fragmentFromString(encodedVariantIndex)},
|
|
1640
2109
|
);
|
|
1641
2110
|
}
|
|
1642
2111
|
|
|
1643
2112
|
Decoder<${fragmentFromString(typeName)}> ${fragmentFromString(decoderName)}() {
|
|
1644
2113
|
return transformDecoder(
|
|
1645
2114
|
get${fragmentFromString(sizeCodecName)}Decoder(),
|
|
1646
|
-
|
|
2115
|
+
${fragmentFromString(decodedVariant)},
|
|
1647
2116
|
);
|
|
1648
2117
|
}
|
|
1649
2118
|
|
|
@@ -1651,7 +2120,7 @@ Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragme
|
|
|
1651
2120
|
return combineCodec(${fragmentFromString(encoderName)}(), ${fragmentFromString(decoderName)}());
|
|
1652
2121
|
}`;
|
|
1653
2122
|
}
|
|
1654
|
-
function getDataEnumPageFragment(node, scope) {
|
|
2123
|
+
function getDataEnumPageFragment(node, variants, scope) {
|
|
1655
2124
|
const name = node.name;
|
|
1656
2125
|
const typeName = scope.nameApi.dataType(name);
|
|
1657
2126
|
const enumNode = node.type;
|
|
@@ -1662,8 +2131,9 @@ function getDataEnumPageFragment(node, scope) {
|
|
|
1662
2131
|
const encodeCases = [];
|
|
1663
2132
|
const decodeCases = [];
|
|
1664
2133
|
const allVariantManifests = [];
|
|
1665
|
-
for (let i = 0; i <
|
|
1666
|
-
const variant =
|
|
2134
|
+
for (let i = 0; i < variants.length; i++) {
|
|
2135
|
+
const variant = variants[i];
|
|
2136
|
+
const variantName = pascalCase(variant.name);
|
|
1667
2137
|
const variantClassName = scope.nameApi.sealedClassVariant(
|
|
1668
2138
|
name,
|
|
1669
2139
|
variant.name
|
|
@@ -1680,7 +2150,7 @@ function getDataEnumPageFragment(node, scope) {
|
|
|
1680
2150
|
int get hashCode => runtimeType.hashCode;
|
|
1681
2151
|
|
|
1682
2152
|
@override
|
|
1683
|
-
String toString() => '${typeName}.${
|
|
2153
|
+
String toString() => '${typeName}.${variantName}()';
|
|
1684
2154
|
}`);
|
|
1685
2155
|
encoderVariants.push(
|
|
1686
2156
|
`(${i}, getStructEncoder(<(String, Encoder<Object?>)>[]))`
|
|
@@ -1692,7 +2162,7 @@ function getDataEnumPageFragment(node, scope) {
|
|
|
1692
2162
|
decodeCases.push(`case ${i}: return const ${variantClassName}();`);
|
|
1693
2163
|
} else if (variant.kind === "enumStructVariantTypeNode") {
|
|
1694
2164
|
const resolvedStruct = nodes.resolveNestedTypeNode(variant.struct);
|
|
1695
|
-
const fields = resolvedStruct.fields;
|
|
2165
|
+
const fields = resolvedStruct.fields ?? [];
|
|
1696
2166
|
const fieldManifests = fields.map((f) => ({
|
|
1697
2167
|
field: f,
|
|
1698
2168
|
manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
|
|
@@ -1727,7 +2197,7 @@ ${fieldDecls}
|
|
|
1727
2197
|
int get hashCode => ${hashExpression};
|
|
1728
2198
|
|
|
1729
2199
|
@override
|
|
1730
|
-
String toString() => '${typeName}.${
|
|
2200
|
+
String toString() => '${typeName}.${variantName}(${toStringFields})';
|
|
1731
2201
|
}`);
|
|
1732
2202
|
const encFields = fieldManifests.map(({ field: f, manifest }) => {
|
|
1733
2203
|
return `('${f.name}', ${manifest.encoder.content})`;
|
|
@@ -1758,7 +2228,7 @@ ${fieldDecls}
|
|
|
1758
2228
|
decodeCases.push(`case ${i}: return ${variantClassName}(${fromMapFields.replace(/\n/g, " ").replace(/,$/, "")});`);
|
|
1759
2229
|
} else if (variant.kind === "enumTupleVariantTypeNode") {
|
|
1760
2230
|
const resolvedTuple = nodes.resolveNestedTypeNode(variant.tuple);
|
|
1761
|
-
const items = resolvedTuple.items;
|
|
2231
|
+
const items = resolvedTuple.items ?? [];
|
|
1762
2232
|
if (items.length === 1) {
|
|
1763
2233
|
const manifest = visitorsCore.visit(items[0], scope.typeManifestVisitor);
|
|
1764
2234
|
allVariantManifests.push(manifest);
|
|
@@ -1776,7 +2246,7 @@ ${fieldDecls}
|
|
|
1776
2246
|
int get hashCode => value.hashCode;
|
|
1777
2247
|
|
|
1778
2248
|
@override
|
|
1779
|
-
String toString() => '${typeName}.${
|
|
2249
|
+
String toString() => '${typeName}.${variantName}($value)';
|
|
1780
2250
|
}`);
|
|
1781
2251
|
encoderVariants.push(
|
|
1782
2252
|
`(${i}, transformEncoder<${manifest.type.content}, Map<String, Object?>>(${manifest.encoder.content}, (Map<String, Object?> map) => map['value']! as ${manifest.type.content}))`
|
|
@@ -1858,7 +2328,7 @@ function getStructPageFragment(node, scope) {
|
|
|
1858
2328
|
const typeName = scope.nameApi.dataType(name);
|
|
1859
2329
|
const structNode = node.type;
|
|
1860
2330
|
if (structNode.kind !== "structTypeNode") return emptyFragment();
|
|
1861
|
-
const fields = structNode.fields;
|
|
2331
|
+
const fields = structNode.fields ?? [];
|
|
1862
2332
|
const fieldManifests = fields.map((f) => ({
|
|
1863
2333
|
field: f,
|
|
1864
2334
|
manifest: visitorsCore.visit(f.type, scope.typeManifestVisitor)
|
|
@@ -2065,7 +2535,7 @@ function getRenderMapVisitor(options = {}) {
|
|
|
2065
2535
|
visitRoot(node, { self }) {
|
|
2066
2536
|
const programMaps = [
|
|
2067
2537
|
visitorsCore.visit(node.program, self),
|
|
2068
|
-
...node.additionalPrograms.map((p) => visitorsCore.visit(p, self))
|
|
2538
|
+
...(node.additionalPrograms ?? []).map((p) => visitorsCore.visit(p, self))
|
|
2069
2539
|
];
|
|
2070
2540
|
const mergedProgramMap = renderersCore.mergeRenderMaps(programMaps);
|
|
2071
2541
|
const categoryMaps = getSharedCategoryIndexMaps(mergedProgramMap);
|
|
@@ -2211,16 +2681,17 @@ function renderVisitor(outputDir, options = {}) {
|
|
|
2211
2681
|
dependencyMap
|
|
2212
2682
|
} = options;
|
|
2213
2683
|
return visitorsCore.rootNodeVisitor((root) => {
|
|
2684
|
+
const normalizedRoot = normalizeRootNode(root);
|
|
2214
2685
|
if (deleteFolderBeforeRendering && fs.existsSync(outputDir)) {
|
|
2215
2686
|
renderersCore.deleteDirectory(outputDir);
|
|
2216
2687
|
}
|
|
2217
2688
|
const renderMap = visitorsCore.visit(
|
|
2218
|
-
|
|
2689
|
+
normalizedRoot,
|
|
2219
2690
|
getRenderMapVisitor({ nameApi, dependencyMap })
|
|
2220
2691
|
);
|
|
2221
2692
|
const typePathMap = {};
|
|
2222
2693
|
for (const renderPath of renderMap.keys()) {
|
|
2223
|
-
const match = renderPath.match(/^(?:.*\/)?types\/([a-
|
|
2694
|
+
const match = renderPath.match(/^(?:.*\/)?types\/([a-z0-9_]+)\.dart$/);
|
|
2224
2695
|
if (match) {
|
|
2225
2696
|
typePathMap[`definedType:${match[1]}`] = renderPath;
|
|
2226
2697
|
}
|
|
@@ -2234,7 +2705,10 @@ function renderVisitor(outputDir, options = {}) {
|
|
|
2234
2705
|
const fileDir = path.dirname(filePath);
|
|
2235
2706
|
const internalMap = {};
|
|
2236
2707
|
for (const [key, typePath] of Object.entries(typePathMap)) {
|
|
2237
|
-
if (typePath === filePath)
|
|
2708
|
+
if (typePath === filePath) {
|
|
2709
|
+
internalMap[key] = "";
|
|
2710
|
+
continue;
|
|
2711
|
+
}
|
|
2238
2712
|
let rel = path.posix.relative(fileDir, typePath);
|
|
2239
2713
|
if (!rel.startsWith(".")) {
|
|
2240
2714
|
rel = `./${rel}`;
|
|
@@ -2300,6 +2774,7 @@ exports.createDartNameApi = createDartNameApi;
|
|
|
2300
2774
|
exports.default = src_default;
|
|
2301
2775
|
exports.getRenderMapVisitor = getRenderMapVisitor;
|
|
2302
2776
|
exports.getTypeManifestVisitor = getTypeManifestVisitor;
|
|
2777
|
+
exports.normalizeRootNode = normalizeRootNode;
|
|
2303
2778
|
exports.renderVisitor = renderVisitor;
|
|
2304
2779
|
//# sourceMappingURL=index.browser.cjs.map
|
|
2305
2780
|
//# sourceMappingURL=index.browser.cjs.map
|