codama-renderers-dart 0.3.0 → 0.4.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codama-renderers-dart",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Codama renderer for generating Dart code targeting the solana_kit SDK",
|
|
5
5
|
"exports": {
|
|
6
6
|
"node": {
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
"code-generator"
|
|
31
31
|
],
|
|
32
32
|
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/openbudgetfun/solana_kit.git",
|
|
36
|
+
"directory": "packages/codama-renderers-dart"
|
|
37
|
+
},
|
|
33
38
|
"dependencies": {
|
|
34
39
|
"@codama/errors": "^1.4.4",
|
|
35
40
|
"@codama/nodes": "^1.4.4",
|
|
@@ -38,7 +43,8 @@
|
|
|
38
43
|
},
|
|
39
44
|
"devDependencies": {
|
|
40
45
|
"@codama/nodes-from-anchor": "^1.3.9",
|
|
41
|
-
"@codama/renderers-js": "^2.0.2"
|
|
46
|
+
"@codama/renderers-js": "^2.0.2",
|
|
47
|
+
"@vitest/coverage-v8": "3.2.4"
|
|
42
48
|
},
|
|
43
49
|
"engines": {
|
|
44
50
|
"node": ">=18"
|
|
@@ -50,6 +56,7 @@
|
|
|
50
56
|
"build": "pnpm exec rimraf dist && pnpm exec tsup && pnpm exec tsc -p tsconfig.declarations.json",
|
|
51
57
|
"lint": "eslint --ext .ts src",
|
|
52
58
|
"test": "pnpm exec vitest run",
|
|
59
|
+
"test:coverage": "pnpm exec vitest run --coverage.enabled --coverage.reporter=lcov",
|
|
53
60
|
"test:watch": "pnpm exec vitest",
|
|
54
61
|
"typecheck": "pnpm exec tsc --noEmit"
|
|
55
62
|
}
|
package/readme.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# codama-renderers-dart
|
|
2
2
|
|
|
3
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
4
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
6
|
+
|
|
3
7
|
A [Codama](https://github.com/codama-idl/codama) renderer that generates Dart code targeting the [solana_kit](https://github.com/openbudgetfun/solana_kit) SDK.
|
|
4
8
|
|
|
5
9
|
Given a Codama IDL (Interface Description Language) describing a Solana program, this renderer produces a complete Dart package with typed account classes, instruction builders, codec functions, error definitions, PDA helpers, and barrel exports.
|
|
@@ -9,6 +13,10 @@ Given a Codama IDL (Interface Description Language) describing a Solana program,
|
|
|
9
13
|
```bash
|
|
10
14
|
pnpm add codama-renderers-dart
|
|
11
15
|
# or
|
|
16
|
+
|
|
17
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
18
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
19
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
12
20
|
npm install codama-renderers-dart
|
|
13
21
|
```
|
|
14
22
|
|
|
@@ -277,18 +285,38 @@ Key source files:
|
|
|
277
285
|
|
|
278
286
|
```bash
|
|
279
287
|
# Install dependencies
|
|
288
|
+
|
|
289
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
290
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
291
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
280
292
|
pnpm install
|
|
281
293
|
|
|
282
294
|
# Type check
|
|
295
|
+
|
|
296
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
297
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
298
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
283
299
|
npx tsc --noEmit
|
|
284
300
|
|
|
285
301
|
# Run tests
|
|
302
|
+
|
|
303
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
304
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
305
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
286
306
|
pnpm test
|
|
287
307
|
|
|
288
308
|
# Watch mode
|
|
309
|
+
|
|
310
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
311
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
312
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
289
313
|
pnpm test:watch
|
|
290
314
|
|
|
291
315
|
# Build
|
|
316
|
+
|
|
317
|
+
[](https://pub.dev/packages/codama-renderers-dart)
|
|
318
|
+
[](https://github.com/openbudgetfun/solana_kit/actions/workflows/ci.yml)
|
|
319
|
+
[](https://codecov.io/gh/openbudgetfun/solana_kit?flag=codama-renderers-dart)
|
|
292
320
|
pnpm build
|
|
293
321
|
```
|
|
294
322
|
|
|
@@ -53,15 +53,28 @@ export function getInstructionPageFragment(
|
|
|
53
53
|
.join("\n");
|
|
54
54
|
|
|
55
55
|
const dataCtorParams = allArgManifests
|
|
56
|
-
.map(({ arg }) => {
|
|
56
|
+
.map(({ arg, manifest }) => {
|
|
57
57
|
const fieldName = camelCase(arg.name as string);
|
|
58
58
|
if (isDiscriminatorArg(arg, node)) {
|
|
59
|
-
return
|
|
59
|
+
return isConstDefaultValue(arg.defaultValue)
|
|
60
|
+
? ` this.${fieldName} = ${getDiscriminatorDefault(arg, node)},`
|
|
61
|
+
: ` ${manifest.type.content}? ${fieldName},`;
|
|
60
62
|
}
|
|
61
63
|
return ` required this.${fieldName},`;
|
|
62
64
|
})
|
|
63
65
|
.join("\n");
|
|
64
66
|
|
|
67
|
+
const dataCtorInitializers = allArgManifests
|
|
68
|
+
.map(({ arg }) => {
|
|
69
|
+
const fieldName = camelCase(arg.name as string);
|
|
70
|
+
if (isDiscriminatorArg(arg, node) && !isConstDefaultValue(arg.defaultValue)) {
|
|
71
|
+
return ` ${fieldName} = ${fieldName} ?? ${getDiscriminatorDefault(arg, node)}`;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
})
|
|
75
|
+
.filter((value): value is string => value !== null)
|
|
76
|
+
.join(",\n");
|
|
77
|
+
|
|
65
78
|
// Encoder/decoder for instruction data
|
|
66
79
|
const encFields = allArgManifests
|
|
67
80
|
.map(({ arg, manifest }) => {
|
|
@@ -91,10 +104,17 @@ export function getInstructionPageFragment(
|
|
|
91
104
|
})
|
|
92
105
|
.join("\n");
|
|
93
106
|
|
|
107
|
+
const dataCtorKeyword = dataCtorInitializers ? "" : "const ";
|
|
94
108
|
const dataEncoderName = `get${typeName}InstructionDataEncoder`;
|
|
95
109
|
const dataDecoderName = `get${typeName}InstructionDataDecoder`;
|
|
96
110
|
const dataCodecName = `get${typeName}InstructionDataCodec`;
|
|
97
111
|
|
|
112
|
+
// Determine whether any arg or account name collides with 'programAddress'
|
|
113
|
+
const argNames = new Set(args.map((a) => camelCase(a.name as string)));
|
|
114
|
+
const accountNames = new Set(accounts.map((a) => camelCase(a.name as string)));
|
|
115
|
+
const hasProgramAddressCollision = argNames.has('programAddress') || accountNames.has('programAddress');
|
|
116
|
+
const instrProgramParam = hasProgramAddressCollision ? 'instructionProgramAddress' : 'programAddress';
|
|
117
|
+
|
|
98
118
|
// Build the instruction builder function
|
|
99
119
|
const accountParams = accounts
|
|
100
120
|
.map((acc) => {
|
|
@@ -112,11 +132,14 @@ export function getInstructionPageFragment(
|
|
|
112
132
|
.map((arg) => {
|
|
113
133
|
const manifest = argManifestMap.get(arg)!;
|
|
114
134
|
const fieldName = camelCase(arg.name as string);
|
|
135
|
+
const typeStr = manifest.type.content;
|
|
115
136
|
const hasDefault = arg.defaultValue != null;
|
|
116
137
|
if (hasDefault) {
|
|
117
|
-
|
|
138
|
+
// Don't add `?` if the type is already nullable.
|
|
139
|
+
const nullableType = typeStr.endsWith("?") ? typeStr : `${typeStr}?`;
|
|
140
|
+
return ` ${nullableType} ${fieldName},`;
|
|
118
141
|
}
|
|
119
|
-
return ` required ${
|
|
142
|
+
return ` required ${typeStr} ${fieldName},`;
|
|
120
143
|
})
|
|
121
144
|
.join("\n");
|
|
122
145
|
|
|
@@ -140,6 +163,7 @@ export function getInstructionPageFragment(
|
|
|
140
163
|
if (isDiscriminatorArg(arg, node)) {
|
|
141
164
|
return ""; // Use default
|
|
142
165
|
}
|
|
166
|
+
// Use 'arg_<name>' prefix to reference builder params without shadowing.
|
|
143
167
|
return ` ${fieldName}: ${fieldName}${arg.defaultValue != null ? ` ?? ${getDefaultValue(arg)}` : ""},`;
|
|
144
168
|
})
|
|
145
169
|
.filter(Boolean)
|
|
@@ -174,9 +198,9 @@ ${use("AccountRole", "solanaInstructions")}`,
|
|
|
174
198
|
parts.push(fragment`
|
|
175
199
|
@immutable
|
|
176
200
|
class ${fragmentFromString(dataClassName)} {
|
|
177
|
-
|
|
201
|
+
${fragmentFromString(dataCtorKeyword)}${fragmentFromString(dataClassName)}({
|
|
178
202
|
${fragmentFromString(dataCtorParams)}
|
|
179
|
-
});
|
|
203
|
+
})${fragmentFromString(dataCtorInitializers ? ` :\n${dataCtorInitializers}` : "")};
|
|
180
204
|
|
|
181
205
|
${fragmentFromString(dataFieldDecls)}
|
|
182
206
|
}`);
|
|
@@ -217,20 +241,20 @@ Codec<${fragmentFromString(dataClassName)}, ${fragmentFromString(dataClassName)}
|
|
|
217
241
|
parts.push(fragment`
|
|
218
242
|
/// Creates a [${fragmentFromString(typeName)}] instruction.
|
|
219
243
|
Instruction ${fragmentFromString(instrFnName)}({
|
|
220
|
-
required Address
|
|
244
|
+
required Address ${fragmentFromString(instrProgramParam)},
|
|
221
245
|
${fragmentFromString(accountParams)}
|
|
222
246
|
${fragmentFromString(argParams)}
|
|
223
247
|
}) {
|
|
224
|
-
final
|
|
248
|
+
final instructionData = ${fragmentFromString(dataClassName)}(
|
|
225
249
|
${fragmentFromString(dataConstruction)}
|
|
226
250
|
);
|
|
227
251
|
|
|
228
252
|
return Instruction(
|
|
229
|
-
programAddress:
|
|
253
|
+
programAddress: ${fragmentFromString(instrProgramParam)},
|
|
230
254
|
accounts: [
|
|
231
255
|
${fragmentFromString(accountMetas)}
|
|
232
256
|
],
|
|
233
|
-
data: ${fragmentFromString(dataEncoderName)}().encode(
|
|
257
|
+
data: ${fragmentFromString(dataEncoderName)}().encode(instructionData),
|
|
234
258
|
);
|
|
235
259
|
}`);
|
|
236
260
|
|
|
@@ -282,10 +306,28 @@ function getDiscriminatorDefault(
|
|
|
282
306
|
if (arg.defaultValue.kind === "numberValueNode") {
|
|
283
307
|
return String(arg.defaultValue.number);
|
|
284
308
|
}
|
|
309
|
+
if (arg.defaultValue.kind === "bytesValueNode") {
|
|
310
|
+
const data = arg.defaultValue.data as string;
|
|
311
|
+
const bytes = data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
|
|
312
|
+
return `Uint8List.fromList([${bytes.join(", ")}])`;
|
|
313
|
+
}
|
|
285
314
|
}
|
|
286
315
|
return "0";
|
|
287
316
|
}
|
|
288
317
|
|
|
318
|
+
function isConstDefaultValue(defaultValue: InstructionArgumentNode["defaultValue"]): boolean {
|
|
319
|
+
if (!defaultValue) return false;
|
|
320
|
+
switch (defaultValue.kind) {
|
|
321
|
+
case "numberValueNode":
|
|
322
|
+
case "booleanValueNode":
|
|
323
|
+
case "stringValueNode":
|
|
324
|
+
case "noneValueNode":
|
|
325
|
+
return true;
|
|
326
|
+
default:
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
289
331
|
function getDefaultValue(arg: InstructionArgumentNode): string {
|
|
290
332
|
if (!arg.defaultValue) return "null";
|
|
291
333
|
const dv = arg.defaultValue;
|
|
@@ -300,6 +342,10 @@ function getDefaultValue(arg: InstructionArgumentNode): string {
|
|
|
300
342
|
return `Address('${dv.publicKey}')`;
|
|
301
343
|
case "noneValueNode":
|
|
302
344
|
return "null";
|
|
345
|
+
case "bytesValueNode": {
|
|
346
|
+
const bytes = dv.data.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [];
|
|
347
|
+
return `Uint8List.fromList([${bytes.join(", ")}])`;
|
|
348
|
+
}
|
|
303
349
|
default:
|
|
304
350
|
return "null";
|
|
305
351
|
}
|
package/src/fragments/pdaPage.ts
CHANGED
|
@@ -23,6 +23,11 @@ export function getPdaPageFragment(
|
|
|
23
23
|
const seedsClassName = `${pascalCase(name)}Seeds`;
|
|
24
24
|
|
|
25
25
|
const seeds = node.seeds ?? [];
|
|
26
|
+
const hasByteSeeds = seeds.some(
|
|
27
|
+
(seed) =>
|
|
28
|
+
seed.kind === "constantPdaSeedNode" &&
|
|
29
|
+
seed.value.kind === "bytesValueNode",
|
|
30
|
+
);
|
|
26
31
|
|
|
27
32
|
// Separate variable seeds from constant seeds
|
|
28
33
|
const variableSeeds = seeds.filter(
|
|
@@ -79,11 +84,15 @@ export function getPdaPageFragment(
|
|
|
79
84
|
? `Address programAddress = const Address('${node.programId}')`
|
|
80
85
|
: "required Address programAddress";
|
|
81
86
|
|
|
87
|
+
const typedDataImport = hasByteSeeds
|
|
88
|
+
? use("Uint8List", "dartTypedData")
|
|
89
|
+
: fragmentFromString("");
|
|
90
|
+
|
|
82
91
|
const parts: Fragment[] = [
|
|
83
92
|
fragment`// Auto-generated. Do not edit.
|
|
84
93
|
// ignore_for_file: type=lint
|
|
85
94
|
|
|
86
|
-
${
|
|
95
|
+
${typedDataImport}
|
|
87
96
|
${use("immutable", "meta")}
|
|
88
97
|
${use("Address", "solanaAddresses")}
|
|
89
98
|
${use("getAddressEncoder", "solanaAddresses")}
|
|
@@ -110,13 +119,13 @@ Future<(Address, int)> ${fragmentFromString(findFnName)}({
|
|
|
110
119
|
${fragmentFromString(seedsParam)}
|
|
111
120
|
${fragmentFromString(programIdParam)},
|
|
112
121
|
}) async {
|
|
113
|
-
final
|
|
122
|
+
final seedValues = <Object>[
|
|
114
123
|
${fragmentFromString(seedValues.join("\n"))}
|
|
115
124
|
];
|
|
116
125
|
|
|
117
126
|
return getProgramDerivedAddress(
|
|
118
127
|
programAddress: programAddress,
|
|
119
|
-
seeds:
|
|
128
|
+
seeds: seedValues,
|
|
120
129
|
);
|
|
121
130
|
}`);
|
|
122
131
|
|
|
@@ -125,6 +125,8 @@ function getDataEnumPageFragment(
|
|
|
125
125
|
const variantClasses: string[] = [];
|
|
126
126
|
const encoderVariants: string[] = [];
|
|
127
127
|
const decoderVariants: string[] = [];
|
|
128
|
+
const encodeCases: string[] = [];
|
|
129
|
+
const decodeCases: string[] = [];
|
|
128
130
|
// Collect all field type manifests from variants so we can merge their imports
|
|
129
131
|
const allVariantManifests: { encoder: Fragment; decoder: Fragment; type: Fragment }[] = [];
|
|
130
132
|
|
|
@@ -154,8 +156,10 @@ function getDataEnumPageFragment(
|
|
|
154
156
|
`(${i}, getStructEncoder(<(String, Encoder<Object?>)>[]))`,
|
|
155
157
|
);
|
|
156
158
|
decoderVariants.push(
|
|
157
|
-
`(${i}, getStructDecoder(<(String, Decoder<Object?>)>[])
|
|
159
|
+
`(${i}, transformDecoder<Map<String, Object?>, Map<String, Object?>>(getStructDecoder(<(String, Decoder<Object?>)>[]), (Map<String, Object?> map, Uint8List bytes, int offset) => <String, Object?>{}))`,
|
|
158
160
|
);
|
|
161
|
+
encodeCases.push(`${variantClassName}() => <String, Object?>{'__kind': ${i}},`);
|
|
162
|
+
decodeCases.push(`case ${i}: return const ${variantClassName}();`);
|
|
159
163
|
} else if (variant.kind === "enumStructVariantTypeNode") {
|
|
160
164
|
const resolvedStruct = resolveNestedTypeNode(variant.struct);
|
|
161
165
|
const fields = resolvedStruct.fields;
|
|
@@ -178,23 +182,28 @@ function getDataEnumPageFragment(
|
|
|
178
182
|
const ctorParams = fields
|
|
179
183
|
.map((f: StructFieldTypeNode) => ` required this.${camelCase(f.name as string)},`)
|
|
180
184
|
.join("\n");
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
.
|
|
188
|
-
|
|
185
|
+
const ctorSignature =
|
|
186
|
+
fields.length === 0
|
|
187
|
+
? ` const ${variantClassName}();`
|
|
188
|
+
: ` const ${variantClassName}({\n${ctorParams}\n });`;
|
|
189
|
+
|
|
190
|
+
const eqChecks =
|
|
191
|
+
fields.length === 0
|
|
192
|
+
? "true"
|
|
193
|
+
: fields
|
|
194
|
+
.map((f: StructFieldTypeNode) => `${camelCase(f.name as string)} == other.${camelCase(f.name as string)}`)
|
|
195
|
+
.join(" &&\n ");
|
|
196
|
+
|
|
197
|
+
const hashExpression = getHashExpression(
|
|
198
|
+
fields.map((f: StructFieldTypeNode) => camelCase(f.name as string)),
|
|
199
|
+
);
|
|
189
200
|
|
|
190
201
|
const toStringFields = fields
|
|
191
202
|
.map((f: StructFieldTypeNode) => `${camelCase(f.name as string)}: $${camelCase(f.name as string)}`)
|
|
192
203
|
.join(", ");
|
|
193
204
|
|
|
194
205
|
variantClasses.push(`final class ${variantClassName} extends ${typeName} {
|
|
195
|
-
|
|
196
|
-
${ctorParams}
|
|
197
|
-
});
|
|
206
|
+
${ctorSignature}
|
|
198
207
|
|
|
199
208
|
${fieldDecls}
|
|
200
209
|
|
|
@@ -205,7 +214,7 @@ ${fieldDecls}
|
|
|
205
214
|
${eqChecks};
|
|
206
215
|
|
|
207
216
|
@override
|
|
208
|
-
int get hashCode =>
|
|
217
|
+
int get hashCode => ${hashExpression};
|
|
209
218
|
|
|
210
219
|
@override
|
|
211
220
|
String toString() => '${typeName}.${variantClassName}(${toStringFields})';
|
|
@@ -242,11 +251,23 @@ ${fieldDecls}
|
|
|
242
251
|
.join(", ");
|
|
243
252
|
|
|
244
253
|
encoderVariants.push(
|
|
245
|
-
`(${i},
|
|
254
|
+
`(${i}, getStructEncoder([${encFields}]))`,
|
|
246
255
|
);
|
|
247
256
|
decoderVariants.push(
|
|
248
|
-
`(${i}, transformDecoder(getStructDecoder([${decFields}]), (Map<String, Object?> map, Uint8List bytes, int offset) =>
|
|
257
|
+
`(${i}, transformDecoder<Map<String, Object?>, Map<String, Object?>>(getStructDecoder([${decFields}]), (Map<String, Object?> map, Uint8List bytes, int offset) => map))`,
|
|
249
258
|
);
|
|
259
|
+
const structPattern =
|
|
260
|
+
fields.length === 0
|
|
261
|
+
? ''
|
|
262
|
+
: fields
|
|
263
|
+
.map((f: StructFieldTypeNode) => `${camelCase(f.name as string)}: final ${camelCase(f.name as string)}`)
|
|
264
|
+
.join(', ');
|
|
265
|
+
const structMapEntries =
|
|
266
|
+
fields.length === 0
|
|
267
|
+
? ''
|
|
268
|
+
: `, ${fields.map((f: StructFieldTypeNode)=>`'${f.name as string}': ${camelCase(f.name as string)}`).join(', ')}`;
|
|
269
|
+
encodeCases.push(`${variantClassName}(${structPattern}) => <String, Object?>{'__kind': ${i}${structMapEntries}},`);
|
|
270
|
+
decodeCases.push(`case ${i}: return ${variantClassName}(${fromMapFields.replace(/\n/g, ' ').replace(/,$/, '')});`);
|
|
250
271
|
} else if (variant.kind === "enumTupleVariantTypeNode") {
|
|
251
272
|
const resolvedTuple = resolveNestedTypeNode(variant.tuple);
|
|
252
273
|
const items = resolvedTuple.items;
|
|
@@ -270,11 +291,13 @@ ${fieldDecls}
|
|
|
270
291
|
String toString() => '${typeName}.${variantClassName}(\$value)';
|
|
271
292
|
}`);
|
|
272
293
|
encoderVariants.push(
|
|
273
|
-
`(${i}, transformEncoder
|
|
294
|
+
`(${i}, transformEncoder<${manifest.type.content}, Map<String, Object?>>(${manifest.encoder.content}, (Map<String, Object?> map) => map['value']! as ${manifest.type.content}))`,
|
|
274
295
|
);
|
|
275
296
|
decoderVariants.push(
|
|
276
|
-
`(${i}, transformDecoder(${manifest.decoder.content}, (${manifest.type.content} value, Uint8List bytes, int offset) =>
|
|
297
|
+
`(${i}, transformDecoder<${manifest.type.content}, Map<String, Object?>>(${manifest.decoder.content}, (${manifest.type.content} value, Uint8List bytes, int offset) => <String, Object?>{'value': value}))`,
|
|
277
298
|
);
|
|
299
|
+
encodeCases.push(`${variantClassName}(value: final value) => <String, Object?>{'__kind': ${i}, 'value': value},`);
|
|
300
|
+
decodeCases.push(`case ${i}: return ${variantClassName}(map['value']! as ${manifest.type.content});`);
|
|
278
301
|
}
|
|
279
302
|
}
|
|
280
303
|
}
|
|
@@ -290,7 +313,6 @@ ${fieldDecls}
|
|
|
290
313
|
// ignore_for_file: type=lint
|
|
291
314
|
|
|
292
315
|
${use("Uint8List", "dartTypedData")}
|
|
293
|
-
${use("immutable", "meta")}
|
|
294
316
|
${use("Encoder", "solanaCodecsCore")}
|
|
295
317
|
${use("Decoder", "solanaCodecsCore")}
|
|
296
318
|
${use("Codec", "solanaCodecsCore")}
|
|
@@ -311,15 +333,28 @@ sealed class ${fragmentFromString(typeName)} {
|
|
|
311
333
|
${fragmentFromString(variantClasses.join("\n\n"))}
|
|
312
334
|
|
|
313
335
|
Encoder<${fragmentFromString(typeName)}> ${fragmentFromString(encoderName)}() {
|
|
314
|
-
return
|
|
315
|
-
|
|
316
|
-
|
|
336
|
+
return transformEncoder<Map<String, Object?>, ${fragmentFromString(typeName)}>(
|
|
337
|
+
getDiscriminatedUnionEncoder([
|
|
338
|
+
${fragmentFromString(encoderVariants.join(",\n "))},
|
|
339
|
+
], size: get${fragmentFromString(sizeCodecName)}Encoder()),
|
|
340
|
+
(${fragmentFromString(typeName)} value) => switch (value) {
|
|
341
|
+
${fragmentFromString(encodeCases.join("\n "))}
|
|
342
|
+
},
|
|
343
|
+
);
|
|
317
344
|
}
|
|
318
345
|
|
|
319
346
|
Decoder<${fragmentFromString(typeName)}> ${fragmentFromString(decoderName)}() {
|
|
320
|
-
return
|
|
321
|
-
|
|
322
|
-
|
|
347
|
+
return transformDecoder<Map<String, Object?>, ${fragmentFromString(typeName)}>(
|
|
348
|
+
getDiscriminatedUnionDecoder([
|
|
349
|
+
${fragmentFromString(decoderVariants.join(",\n "))},
|
|
350
|
+
], size: get${fragmentFromString(sizeCodecName)}Decoder()),
|
|
351
|
+
(Map<String, Object?> map, Uint8List bytes, int offset) {
|
|
352
|
+
switch (map['__kind']) {
|
|
353
|
+
${fragmentFromString(decodeCases.join("\n "))}
|
|
354
|
+
}
|
|
355
|
+
throw StateError('Unsupported ${typeName} discriminator: \${map['__kind']}');
|
|
356
|
+
},
|
|
357
|
+
);
|
|
323
358
|
}
|
|
324
359
|
|
|
325
360
|
Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragmentFromString(codecName)}() {
|
|
@@ -365,6 +400,10 @@ function getStructPageFragment(
|
|
|
365
400
|
const ctorParams = fields
|
|
366
401
|
.map((f: StructFieldTypeNode) => ` required this.${camelCase(f.name as string)},`)
|
|
367
402
|
.join("\n");
|
|
403
|
+
const ctorSignature =
|
|
404
|
+
fields.length === 0
|
|
405
|
+
? ` const ${typeName}();`
|
|
406
|
+
: ` const ${typeName}({\n${ctorParams}\n });`;
|
|
368
407
|
|
|
369
408
|
const eqChecks =
|
|
370
409
|
fields.length === 0
|
|
@@ -376,9 +415,12 @@ function getStructPageFragment(
|
|
|
376
415
|
)
|
|
377
416
|
.join(" &&\n ");
|
|
378
417
|
|
|
379
|
-
const hashFields =
|
|
380
|
-
.
|
|
381
|
-
|
|
418
|
+
const hashFields =
|
|
419
|
+
fields.length === 0
|
|
420
|
+
? "runtimeType"
|
|
421
|
+
: fields
|
|
422
|
+
.map((f: StructFieldTypeNode) => camelCase(f.name as string))
|
|
423
|
+
.join(", ");
|
|
382
424
|
|
|
383
425
|
const toStringFields = fields
|
|
384
426
|
.map(
|
|
@@ -436,9 +478,7 @@ ${use("getStructDecoder", "solanaCodecsDataStructures")}
|
|
|
436
478
|
|
|
437
479
|
@immutable
|
|
438
480
|
class ${fragmentFromString(typeName)} {
|
|
439
|
-
|
|
440
|
-
${fragmentFromString(ctorParams)}
|
|
441
|
-
});
|
|
481
|
+
${fragmentFromString(ctorSignature)}
|
|
442
482
|
|
|
443
483
|
${fragmentFromString(fieldDecls)}
|
|
444
484
|
|
|
@@ -450,7 +490,7 @@ ${fragmentFromString(fieldDecls)}
|
|
|
450
490
|
${fragmentFromString(eqChecks)};
|
|
451
491
|
|
|
452
492
|
@override
|
|
453
|
-
int get hashCode =>
|
|
493
|
+
int get hashCode => ${fragmentFromString(getHashExpression(fields.map((f: StructFieldTypeNode) => camelCase(f.name as string))))};
|
|
454
494
|
|
|
455
495
|
@override
|
|
456
496
|
String toString() => '${fragmentFromString(typeName)}(${fragmentFromString(toStringFields)})';
|
|
@@ -534,6 +574,12 @@ Codec<${fragmentFromString(typeName)}, ${fragmentFromString(typeName)}> ${fragme
|
|
|
534
574
|
}`;
|
|
535
575
|
}
|
|
536
576
|
|
|
577
|
+
function getHashExpression(fields: string[]): string {
|
|
578
|
+
if (fields.length === 0) return "runtimeType.hashCode";
|
|
579
|
+
if (fields.length === 1) return `${fields[0]}.hashCode`;
|
|
580
|
+
return `Object.hash(${fields.join(", ")})`;
|
|
581
|
+
}
|
|
582
|
+
|
|
537
583
|
function getNumberCodecName(format: string): string {
|
|
538
584
|
switch (format) {
|
|
539
585
|
case "u8": return "U8";
|
|
@@ -89,7 +89,10 @@ export function getRenderMapVisitor(
|
|
|
89
89
|
...node.additionalPrograms.map((p) => visit(p, self)),
|
|
90
90
|
];
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
const mergedProgramMap = mergeRenderMaps(programMaps);
|
|
93
|
+
const categoryMaps = getSharedCategoryIndexMaps(mergedProgramMap);
|
|
94
|
+
|
|
95
|
+
return mergeRenderMaps([mergedProgramMap, ...categoryMaps]);
|
|
93
96
|
},
|
|
94
97
|
|
|
95
98
|
visitProgram(node: ProgramNode, { self }) {
|
|
@@ -151,76 +154,15 @@ export function getRenderMapVisitor(
|
|
|
151
154
|
maps.push(errorMap);
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
//
|
|
157
|
+
// Root barrel
|
|
155
158
|
const categories: string[] = [];
|
|
159
|
+
if (accountFiles.length > 0) categories.push("accounts");
|
|
160
|
+
if (instructionFiles.length > 0) categories.push("instructions");
|
|
161
|
+
if (typeFiles.length > 0) categories.push("types");
|
|
162
|
+
if (pdaFiles.length > 0) categories.push("pdas");
|
|
163
|
+
if (errorFiles.length > 0) categories.push("errors");
|
|
164
|
+
if (programFiles.length > 0) categories.push("programs");
|
|
156
165
|
|
|
157
|
-
if (accountFiles.length > 0) {
|
|
158
|
-
categories.push("accounts");
|
|
159
|
-
let indexMap = createRenderMap<Fragment>();
|
|
160
|
-
indexMap = addToRenderMap(
|
|
161
|
-
indexMap,
|
|
162
|
-
"accounts/accounts.dart",
|
|
163
|
-
getIndexPageFragment(accountFiles),
|
|
164
|
-
);
|
|
165
|
-
maps.push(indexMap);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (instructionFiles.length > 0) {
|
|
169
|
-
categories.push("instructions");
|
|
170
|
-
let indexMap = createRenderMap<Fragment>();
|
|
171
|
-
indexMap = addToRenderMap(
|
|
172
|
-
indexMap,
|
|
173
|
-
"instructions/instructions.dart",
|
|
174
|
-
getIndexPageFragment(instructionFiles),
|
|
175
|
-
);
|
|
176
|
-
maps.push(indexMap);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (typeFiles.length > 0) {
|
|
180
|
-
categories.push("types");
|
|
181
|
-
let indexMap = createRenderMap<Fragment>();
|
|
182
|
-
indexMap = addToRenderMap(
|
|
183
|
-
indexMap,
|
|
184
|
-
"types/types.dart",
|
|
185
|
-
getIndexPageFragment(typeFiles),
|
|
186
|
-
);
|
|
187
|
-
maps.push(indexMap);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (pdaFiles.length > 0) {
|
|
191
|
-
categories.push("pdas");
|
|
192
|
-
let indexMap = createRenderMap<Fragment>();
|
|
193
|
-
indexMap = addToRenderMap(
|
|
194
|
-
indexMap,
|
|
195
|
-
"pdas/pdas.dart",
|
|
196
|
-
getIndexPageFragment(pdaFiles),
|
|
197
|
-
);
|
|
198
|
-
maps.push(indexMap);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (errorFiles.length > 0) {
|
|
202
|
-
categories.push("errors");
|
|
203
|
-
let indexMap = createRenderMap<Fragment>();
|
|
204
|
-
indexMap = addToRenderMap(
|
|
205
|
-
indexMap,
|
|
206
|
-
"errors/errors.dart",
|
|
207
|
-
getIndexPageFragment(errorFiles),
|
|
208
|
-
);
|
|
209
|
-
maps.push(indexMap);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (programFiles.length > 0) {
|
|
213
|
-
categories.push("programs");
|
|
214
|
-
let indexMap = createRenderMap<Fragment>();
|
|
215
|
-
indexMap = addToRenderMap(
|
|
216
|
-
indexMap,
|
|
217
|
-
"programs/programs.dart",
|
|
218
|
-
getIndexPageFragment(programFiles),
|
|
219
|
-
);
|
|
220
|
-
maps.push(indexMap);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Root barrel
|
|
224
166
|
if (categories.length > 0) {
|
|
225
167
|
let rootMap = createRenderMap<Fragment>();
|
|
226
168
|
rootMap = addToRenderMap(
|
|
@@ -270,3 +212,46 @@ export function getRenderMapVisitor(
|
|
|
270
212
|
(v) => recordLinkablesOnFirstVisitVisitor(v, linkables),
|
|
271
213
|
);
|
|
272
214
|
}
|
|
215
|
+
|
|
216
|
+
function getSharedCategoryIndexMaps(
|
|
217
|
+
renderMap: RenderMap<Fragment>,
|
|
218
|
+
): RenderMap<Fragment>[] {
|
|
219
|
+
const categories = new Map<string, Set<string>>();
|
|
220
|
+
const categoryIndexNames: Record<string, string> = {
|
|
221
|
+
accounts: "accounts.dart",
|
|
222
|
+
instructions: "instructions.dart",
|
|
223
|
+
types: "types.dart",
|
|
224
|
+
pdas: "pdas.dart",
|
|
225
|
+
errors: "errors.dart",
|
|
226
|
+
programs: "programs.dart",
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
for (const renderPath of renderMap.keys()) {
|
|
230
|
+
const match = renderPath.match(
|
|
231
|
+
/^(accounts|instructions|types|pdas|errors|programs)\/([^/]+\.dart)$/,
|
|
232
|
+
);
|
|
233
|
+
if (!match) continue;
|
|
234
|
+
|
|
235
|
+
const [, category, fileName] = match;
|
|
236
|
+
if (fileName === categoryIndexNames[category]) continue;
|
|
237
|
+
|
|
238
|
+
if (!categories.has(category)) {
|
|
239
|
+
categories.set(category, new Set());
|
|
240
|
+
}
|
|
241
|
+
categories.get(category)!.add(fileName);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const maps: RenderMap<Fragment>[] = [];
|
|
245
|
+
for (const [category, files] of categories.entries()) {
|
|
246
|
+
const sortedFiles = [...files].sort();
|
|
247
|
+
let map = createRenderMap<Fragment>();
|
|
248
|
+
map = addToRenderMap(
|
|
249
|
+
map,
|
|
250
|
+
`${category}/${categoryIndexNames[category]}`,
|
|
251
|
+
getIndexPageFragment(sortedFiles),
|
|
252
|
+
);
|
|
253
|
+
maps.push(map);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return maps;
|
|
257
|
+
}
|
|
@@ -417,6 +417,7 @@ export function getTypeManifestVisitor(input: {
|
|
|
417
417
|
|
|
418
418
|
visitOptionType(node: OptionTypeNode, { self }) {
|
|
419
419
|
const itemManifest = visit(node.item, self);
|
|
420
|
+
const itemTypeStr = itemManifest.type.content;
|
|
420
421
|
const resolvedPrefix = resolveNestedTypeNode(node.prefix);
|
|
421
422
|
const prefixExpr = resolvedPrefix.format !== "u8"
|
|
422
423
|
? `, prefix: ${getNumberCodecExpression(resolvedPrefix.format, "Encoder")}`
|
|
@@ -424,17 +425,20 @@ export function getTypeManifestVisitor(input: {
|
|
|
424
425
|
const prefixDecoderExpr = resolvedPrefix.format !== "u8"
|
|
425
426
|
? `, prefix: ${getNumberCodecExpression(resolvedPrefix.format, "Decoder")}`
|
|
426
427
|
: "";
|
|
428
|
+
const noneValueExpr = node.fixed
|
|
429
|
+
? ", noneValue: const ZeroesNoneValue()"
|
|
430
|
+
: "";
|
|
427
431
|
|
|
428
432
|
return {
|
|
429
433
|
type: fragment`${itemManifest.type}?`,
|
|
430
434
|
encoder: fragment`${use(
|
|
431
435
|
"getNullableEncoder",
|
|
432
436
|
"solanaCodecsDataStructures",
|
|
433
|
-
)}(${itemManifest.encoder}${fragmentFromString(prefixExpr)})`,
|
|
437
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.encoder}${fragmentFromString(prefixExpr)}${fragmentFromString(noneValueExpr)})`,
|
|
434
438
|
decoder: fragment`${use(
|
|
435
439
|
"getNullableDecoder",
|
|
436
440
|
"solanaCodecsDataStructures",
|
|
437
|
-
)}(${itemManifest.decoder}${fragmentFromString(prefixDecoderExpr)})`,
|
|
441
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.decoder}${fragmentFromString(prefixDecoderExpr)}${fragmentFromString(noneValueExpr)})`,
|
|
438
442
|
value: emptyTypeManifest().value,
|
|
439
443
|
isEnum: false,
|
|
440
444
|
};
|
|
@@ -445,17 +449,18 @@ export function getTypeManifestVisitor(input: {
|
|
|
445
449
|
{ self },
|
|
446
450
|
) {
|
|
447
451
|
const itemManifest = visit(node.item, self);
|
|
452
|
+
const itemTypeStr = itemManifest.type.content;
|
|
448
453
|
|
|
449
454
|
return {
|
|
450
455
|
type: fragment`${itemManifest.type}?`,
|
|
451
456
|
encoder: fragment`${use(
|
|
452
457
|
"getNullableEncoder",
|
|
453
458
|
"solanaCodecsDataStructures",
|
|
454
|
-
)}(${itemManifest.encoder}, hasPrefix: false)`,
|
|
459
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.encoder}, hasPrefix: false)`,
|
|
455
460
|
decoder: fragment`${use(
|
|
456
461
|
"getNullableDecoder",
|
|
457
462
|
"solanaCodecsDataStructures",
|
|
458
|
-
)}(${itemManifest.decoder}, hasPrefix: false)`,
|
|
463
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.decoder}, hasPrefix: false)`,
|
|
459
464
|
value: emptyTypeManifest().value,
|
|
460
465
|
isEnum: false,
|
|
461
466
|
};
|
|
@@ -466,17 +471,18 @@ export function getTypeManifestVisitor(input: {
|
|
|
466
471
|
{ self },
|
|
467
472
|
) {
|
|
468
473
|
const itemManifest = visit(node.item, self);
|
|
474
|
+
const itemTypeStr = itemManifest.type.content;
|
|
469
475
|
|
|
470
476
|
return {
|
|
471
477
|
type: fragment`${itemManifest.type}?`,
|
|
472
478
|
encoder: fragment`${use(
|
|
473
479
|
"getNullableEncoder",
|
|
474
480
|
"solanaCodecsDataStructures",
|
|
475
|
-
)}(${itemManifest.encoder}, hasPrefix: false, noneValue: const ZeroesNoneValue())`,
|
|
481
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.encoder}, hasPrefix: false, noneValue: const ZeroesNoneValue())`,
|
|
476
482
|
decoder: fragment`${use(
|
|
477
483
|
"getNullableDecoder",
|
|
478
484
|
"solanaCodecsDataStructures",
|
|
479
|
-
)}(${itemManifest.decoder}, hasPrefix: false, noneValue: const ZeroesNoneValue())`,
|
|
485
|
+
)}<${fragmentFromString(itemTypeStr)}>(${itemManifest.decoder}, hasPrefix: false, noneValue: const ZeroesNoneValue())`,
|
|
480
486
|
value: emptyTypeManifest().value,
|
|
481
487
|
isEnum: false,
|
|
482
488
|
};
|
|
@@ -502,7 +508,26 @@ export function getTypeManifestVisitor(input: {
|
|
|
502
508
|
|
|
503
509
|
visitSizePrefixType(node: SizePrefixTypeNode, { self }) {
|
|
504
510
|
const innerManifest = visit(node.type, self);
|
|
505
|
-
|
|
511
|
+
|
|
512
|
+
// The Dart addEncoderSizePrefix / addDecoderSizePrefix APIs require
|
|
513
|
+
// Encoder<num> / Decoder<num> for the prefix. BigInt-width number types
|
|
514
|
+
// (u64, u128, i64, i128) return Encoder<BigInt> which is incompatible.
|
|
515
|
+
// When the IDL specifies such a prefix, substitute u32 which is wide
|
|
516
|
+
// enough for any realistic size prefix and satisfies the num constraint.
|
|
517
|
+
const bigIntFormats = new Set(["u64", "u128", "i64", "i128"]);
|
|
518
|
+
let prefixManifest;
|
|
519
|
+
if (
|
|
520
|
+
node.prefix.kind === "numberTypeNode" &&
|
|
521
|
+
bigIntFormats.has((node.prefix as any).format)
|
|
522
|
+
) {
|
|
523
|
+
// Use u32 encoder/decoder instead of the oversized type.
|
|
524
|
+
prefixManifest = {
|
|
525
|
+
encoder: fragment`${use("getU32Encoder", "solanaCodecsNumbers")}()`,
|
|
526
|
+
decoder: fragment`${use("getU32Decoder", "solanaCodecsNumbers")}()`,
|
|
527
|
+
};
|
|
528
|
+
} else {
|
|
529
|
+
prefixManifest = visit(node.prefix, self);
|
|
530
|
+
}
|
|
506
531
|
|
|
507
532
|
return {
|
|
508
533
|
type: innerManifest.type,
|
|
@@ -521,7 +546,7 @@ export function getTypeManifestVisitor(input: {
|
|
|
521
546
|
|
|
522
547
|
visitHiddenPrefixType(node: HiddenPrefixTypeNode, { self }) {
|
|
523
548
|
const innerManifest = visit(node.type, self);
|
|
524
|
-
const prefixes = node.prefix.map((p) =>
|
|
549
|
+
const prefixes = node.prefix.map((p) => getHiddenAffixManifest(p, self));
|
|
525
550
|
const prefixEncoders = prefixes
|
|
526
551
|
.map((p) => p.encoder.content)
|
|
527
552
|
.join(", ");
|
|
@@ -556,7 +581,7 @@ export function getTypeManifestVisitor(input: {
|
|
|
556
581
|
|
|
557
582
|
visitHiddenSuffixType(node: HiddenSuffixTypeNode, { self }) {
|
|
558
583
|
const innerManifest = visit(node.type, self);
|
|
559
|
-
const suffixes = node.suffix.map((s) =>
|
|
584
|
+
const suffixes = node.suffix.map((s) => getHiddenAffixManifest(s, self));
|
|
560
585
|
const suffixEncoders = suffixes
|
|
561
586
|
.map((s) => s.encoder.content)
|
|
562
587
|
.join(", ");
|
|
@@ -792,3 +817,55 @@ function getSetSizeExpression(node: SetTypeNode): string {
|
|
|
792
817
|
return "";
|
|
793
818
|
}
|
|
794
819
|
}
|
|
820
|
+
|
|
821
|
+
type HiddenAffixManifest = {
|
|
822
|
+
encoder: Fragment;
|
|
823
|
+
decoder: Fragment;
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
function getHiddenAffixManifest(
|
|
827
|
+
node: any,
|
|
828
|
+
self: Visitor<TypeManifest>,
|
|
829
|
+
): HiddenAffixManifest {
|
|
830
|
+
if (node?.kind !== "constantValueNode") {
|
|
831
|
+
const manifest = visit(node, self);
|
|
832
|
+
return { encoder: manifest.encoder, decoder: manifest.decoder };
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
const constantBytes = getConstantBytesExpression(node);
|
|
836
|
+
return {
|
|
837
|
+
encoder: fragment`${use("getConstantEncoder", "solanaCodecsDataStructures")}(${constantBytes})`,
|
|
838
|
+
decoder: fragment`${use("getConstantDecoder", "solanaCodecsDataStructures")}(${constantBytes})`,
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function getConstantBytesExpression(node: any): Fragment {
|
|
843
|
+
const valueNode = node.value;
|
|
844
|
+
const typeNode = node.type;
|
|
845
|
+
|
|
846
|
+
if (valueNode?.kind !== "numberValueNode") {
|
|
847
|
+
throw new Error(
|
|
848
|
+
`Unsupported hidden affix constant value kind: ${valueNode?.kind}`,
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const value = Number(valueNode.number);
|
|
853
|
+
|
|
854
|
+
if (typeNode?.kind === "numberTypeNode") {
|
|
855
|
+
return fragment`${use(`get${getNumberCodecName(typeNode.format)}Encoder`, "solanaCodecsNumbers")}().encode(${value})`;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (typeNode?.kind === "preOffsetTypeNode") {
|
|
859
|
+
const inner = typeNode.type;
|
|
860
|
+
if (inner?.kind !== "numberTypeNode") {
|
|
861
|
+
throw new Error(
|
|
862
|
+
`Unsupported hidden affix pre-offset inner type kind: ${inner?.kind}`,
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
return fragment`${use("padLeftEncoder", "solanaCodecsCore")}(${use(`get${getNumberCodecName(inner.format)}Encoder`, "solanaCodecsNumbers")}(), ${typeNode.offset}).encode(${value})`;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
throw new Error(
|
|
869
|
+
`Unsupported hidden affix constant type kind: ${typeNode?.kind}`,
|
|
870
|
+
);
|
|
871
|
+
}
|