@codama/renderers-js 1.0.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/LICENSE +23 -0
- package/README.md +54 -0
- package/dist/index.node.cjs +2733 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.mjs +2700 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/templates/fragments/accountFetchHelpers.njk +43 -0
- package/dist/templates/fragments/accountPdaHelpers.njk +25 -0
- package/dist/templates/fragments/accountSizeHelpers.njk +3 -0
- package/dist/templates/fragments/instructionExtraArgs.njk +4 -0
- package/dist/templates/fragments/instructionFunction.njk +62 -0
- package/dist/templates/fragments/instructionInputType.njk +16 -0
- package/dist/templates/fragments/instructionParseFunction.njk +81 -0
- package/dist/templates/fragments/instructionType.njk +18 -0
- package/dist/templates/fragments/pdaFunction.njk +32 -0
- package/dist/templates/fragments/program.njk +3 -0
- package/dist/templates/fragments/programErrors.njk +36 -0
- package/dist/templates/fragments/type.njk +12 -0
- package/dist/templates/fragments/typeCodec.njk +6 -0
- package/dist/templates/fragments/typeDecoder.njk +6 -0
- package/dist/templates/fragments/typeDiscriminatedUnionHelpers.njk +23 -0
- package/dist/templates/fragments/typeEncoder.njk +6 -0
- package/dist/templates/layout.njk +9 -0
- package/dist/templates/macros.njk +12 -0
- package/dist/templates/pages/accountsIndex.njk +9 -0
- package/dist/templates/pages/accountsPage.njk +12 -0
- package/dist/templates/pages/definedTypesIndex.njk +9 -0
- package/dist/templates/pages/definedTypesPage.njk +9 -0
- package/dist/templates/pages/errorsIndex.njk +9 -0
- package/dist/templates/pages/errorsPage.njk +8 -0
- package/dist/templates/pages/instructionsIndex.njk +9 -0
- package/dist/templates/pages/instructionsPage.njk +14 -0
- package/dist/templates/pages/pdasIndex.njk +9 -0
- package/dist/templates/pages/pdasPage.njk +8 -0
- package/dist/templates/pages/programsIndex.njk +9 -0
- package/dist/templates/pages/programsPage.njk +10 -0
- package/dist/templates/pages/rootIndex.njk +26 -0
- package/dist/templates/pages/sharedPage.njk +106 -0
- package/dist/types/ImportMap.d.ts +15 -0
- package/dist/types/ImportMap.d.ts.map +1 -0
- package/dist/types/TypeManifest.d.ts +16 -0
- package/dist/types/TypeManifest.d.ts.map +1 -0
- package/dist/types/fragments/accountFetchHelpers.d.ts +9 -0
- package/dist/types/fragments/accountFetchHelpers.d.ts.map +1 -0
- package/dist/types/fragments/accountPdaHelpers.d.ts +10 -0
- package/dist/types/fragments/accountPdaHelpers.d.ts.map +1 -0
- package/dist/types/fragments/accountSizeHelpers.d.ts +7 -0
- package/dist/types/fragments/accountSizeHelpers.d.ts.map +1 -0
- package/dist/types/fragments/accountType.d.ts +9 -0
- package/dist/types/fragments/accountType.d.ts.map +1 -0
- package/dist/types/fragments/common.d.ts +25 -0
- package/dist/types/fragments/common.d.ts.map +1 -0
- package/dist/types/fragments/discriminatorCondition.d.ts +26 -0
- package/dist/types/fragments/discriminatorCondition.d.ts.map +1 -0
- package/dist/types/fragments/discriminatorConstants.d.ts +22 -0
- package/dist/types/fragments/discriminatorConstants.d.ts.map +1 -0
- package/dist/types/fragments/index.d.ts +31 -0
- package/dist/types/fragments/index.d.ts.map +1 -0
- package/dist/types/fragments/instructionAccountMeta.d.ts +4 -0
- package/dist/types/fragments/instructionAccountMeta.d.ts.map +1 -0
- package/dist/types/fragments/instructionAccountTypeParam.d.ts +10 -0
- package/dist/types/fragments/instructionAccountTypeParam.d.ts.map +1 -0
- package/dist/types/fragments/instructionByteDelta.d.ts +8 -0
- package/dist/types/fragments/instructionByteDelta.d.ts.map +1 -0
- package/dist/types/fragments/instructionData.d.ts +9 -0
- package/dist/types/fragments/instructionData.d.ts.map +1 -0
- package/dist/types/fragments/instructionExtraArgs.d.ts +9 -0
- package/dist/types/fragments/instructionExtraArgs.d.ts.map +1 -0
- package/dist/types/fragments/instructionFunction.d.ts +15 -0
- package/dist/types/fragments/instructionFunction.d.ts.map +1 -0
- package/dist/types/fragments/instructionInputDefault.d.ts +9 -0
- package/dist/types/fragments/instructionInputDefault.d.ts.map +1 -0
- package/dist/types/fragments/instructionInputResolved.d.ts +10 -0
- package/dist/types/fragments/instructionInputResolved.d.ts.map +1 -0
- package/dist/types/fragments/instructionInputType.d.ts +13 -0
- package/dist/types/fragments/instructionInputType.d.ts.map +1 -0
- package/dist/types/fragments/instructionParseFunction.d.ts +10 -0
- package/dist/types/fragments/instructionParseFunction.d.ts.map +1 -0
- package/dist/types/fragments/instructionRemainingAccounts.d.ts +8 -0
- package/dist/types/fragments/instructionRemainingAccounts.d.ts.map +1 -0
- package/dist/types/fragments/instructionType.d.ts +8 -0
- package/dist/types/fragments/instructionType.d.ts.map +1 -0
- package/dist/types/fragments/pdaFunction.d.ts +8 -0
- package/dist/types/fragments/pdaFunction.d.ts.map +1 -0
- package/dist/types/fragments/program.d.ts +7 -0
- package/dist/types/fragments/program.d.ts.map +1 -0
- package/dist/types/fragments/programAccounts.d.ts +7 -0
- package/dist/types/fragments/programAccounts.d.ts.map +1 -0
- package/dist/types/fragments/programErrors.d.ts +7 -0
- package/dist/types/fragments/programErrors.d.ts.map +1 -0
- package/dist/types/fragments/programInstructions.d.ts +7 -0
- package/dist/types/fragments/programInstructions.d.ts.map +1 -0
- package/dist/types/fragments/type.d.ts +9 -0
- package/dist/types/fragments/type.d.ts.map +1 -0
- package/dist/types/fragments/typeCodec.d.ts +11 -0
- package/dist/types/fragments/typeCodec.d.ts.map +1 -0
- package/dist/types/fragments/typeDecoder.d.ts +9 -0
- package/dist/types/fragments/typeDecoder.d.ts.map +1 -0
- package/dist/types/fragments/typeDiscriminatedUnionHelpers.d.ts +8 -0
- package/dist/types/fragments/typeDiscriminatedUnionHelpers.d.ts.map +1 -0
- package/dist/types/fragments/typeEncoder.d.ts +9 -0
- package/dist/types/fragments/typeEncoder.d.ts.map +1 -0
- package/dist/types/fragments/typeWithCodec.d.ts +12 -0
- package/dist/types/fragments/typeWithCodec.d.ts.map +1 -0
- package/dist/types/getRenderMapVisitor.d.ts +31 -0
- package/dist/types/getRenderMapVisitor.d.ts.map +1 -0
- package/dist/types/getTypeManifestVisitor.d.ts +19 -0
- package/dist/types/getTypeManifestVisitor.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/nameTransformers.d.ts +15 -0
- package/dist/types/nameTransformers.d.ts.map +1 -0
- package/dist/types/renderVisitor.d.ts +11 -0
- package/dist/types/renderVisitor.d.ts.map +1 -0
- package/dist/types/utils/async.d.ts +7 -0
- package/dist/types/utils/async.d.ts.map +1 -0
- package/dist/types/utils/codecs.d.ts +3 -0
- package/dist/types/utils/codecs.d.ts.map +1 -0
- package/dist/types/utils/customData.d.ts +18 -0
- package/dist/types/utils/customData.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +6 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/linkOverrides.d.ts +15 -0
- package/dist/types/utils/linkOverrides.d.ts.map +1 -0
- package/dist/types/utils/render.d.ts +4 -0
- package/dist/types/utils/render.d.ts.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,2700 @@
|
|
|
1
|
+
import { join, dirname } from 'node:path';
|
|
2
|
+
import { REGISTERED_TYPE_NODE_KINDS, REGISTERED_VALUE_NODE_KINDS, resolveNestedTypeNode, isNode, camelCase, structTypeNode, structFieldTypeNode, isScalarEnum, structTypeNodeFromInstructionArgumentNodes, isNodeFilter, pascalCase, snakeCase, getAllInstructionsWithSubs, getAllPrograms, getAllPdas, getAllAccounts, getAllDefinedTypes, definedTypeLinkNode, definedTypeNode, isDataEnum, capitalize, kebabCase, titleCase, constantDiscriminatorNode, constantValueNodeFromBytes, constantValueNode, VALUE_NODES, accountValueNode, argumentValueNode, assertIsNode, getAllInstructionArguments } from '@codama/nodes';
|
|
3
|
+
import { NodeStack, pipe, staticVisitor, extendVisitor, visit, recordNodeStackVisitor, LinkableDictionary, getResolvedInstructionInputsVisitor, recordLinkablesVisitor, rootNodeVisitor, deduplicateInstructionDependencies } from '@codama/visitors-core';
|
|
4
|
+
import { getBase64Encoder, getBase58Encoder, getBase16Encoder, getUtf8Encoder, getBase64Decoder } from '@solana/codecs-strings';
|
|
5
|
+
import { CodamaError, CODAMA_ERROR__UNEXPECTED_NODE_KIND, logWarn } from '@codama/errors';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import nunjucks from 'nunjucks';
|
|
8
|
+
import { RenderMap, deleteDirectory } from '@codama/renderers-core';
|
|
9
|
+
import * as estreePlugin from 'prettier/plugins/estree';
|
|
10
|
+
import * as typeScriptPlugin from 'prettier/plugins/typescript';
|
|
11
|
+
import { format } from 'prettier/standalone';
|
|
12
|
+
|
|
13
|
+
// src/ImportMap.ts
|
|
14
|
+
var DEFAULT_EXTERNAL_MODULE_MAP = {
|
|
15
|
+
solanaAccounts: "@solana/web3.js",
|
|
16
|
+
solanaAddresses: "@solana/web3.js",
|
|
17
|
+
solanaCodecsCore: "@solana/web3.js",
|
|
18
|
+
solanaCodecsDataStructures: "@solana/web3.js",
|
|
19
|
+
solanaCodecsNumbers: "@solana/web3.js",
|
|
20
|
+
solanaCodecsStrings: "@solana/web3.js",
|
|
21
|
+
solanaErrors: "@solana/web3.js",
|
|
22
|
+
solanaInstructions: "@solana/web3.js",
|
|
23
|
+
solanaOptions: "@solana/web3.js",
|
|
24
|
+
solanaPrograms: "@solana/web3.js",
|
|
25
|
+
solanaRpcTypes: "@solana/web3.js",
|
|
26
|
+
solanaSigners: "@solana/web3.js"
|
|
27
|
+
};
|
|
28
|
+
var DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP = {
|
|
29
|
+
solanaAccounts: "@solana/accounts",
|
|
30
|
+
solanaAddresses: "@solana/addresses",
|
|
31
|
+
solanaCodecsCore: "@solana/codecs",
|
|
32
|
+
solanaCodecsDataStructures: "@solana/codecs",
|
|
33
|
+
solanaCodecsNumbers: "@solana/codecs",
|
|
34
|
+
solanaCodecsStrings: "@solana/codecs",
|
|
35
|
+
solanaErrors: "@solana/errors",
|
|
36
|
+
solanaInstructions: "@solana/instructions",
|
|
37
|
+
solanaOptions: "@solana/codecs",
|
|
38
|
+
solanaPrograms: "@solana/programs",
|
|
39
|
+
solanaRpcTypes: "@solana/rpc-types",
|
|
40
|
+
solanaSigners: "@solana/signers"
|
|
41
|
+
};
|
|
42
|
+
var DEFAULT_INTERNAL_MODULE_MAP = {
|
|
43
|
+
errors: "../errors",
|
|
44
|
+
generated: "..",
|
|
45
|
+
generatedAccounts: "../accounts",
|
|
46
|
+
generatedErrors: "../errors",
|
|
47
|
+
generatedInstructions: "../instructions",
|
|
48
|
+
generatedPdas: "../pdas",
|
|
49
|
+
generatedPrograms: "../programs",
|
|
50
|
+
generatedTypes: "../types",
|
|
51
|
+
hooked: "../../hooked",
|
|
52
|
+
shared: "../shared",
|
|
53
|
+
types: "../types"
|
|
54
|
+
};
|
|
55
|
+
var ImportMap = class {
|
|
56
|
+
_imports = /* @__PURE__ */ new Map();
|
|
57
|
+
_aliases = /* @__PURE__ */ new Map();
|
|
58
|
+
add(module, imports) {
|
|
59
|
+
const newImports = new Set(typeof imports === "string" ? [imports] : imports);
|
|
60
|
+
if (newImports.size === 0) return this;
|
|
61
|
+
const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set();
|
|
62
|
+
newImports.forEach((i) => currentImports.add(i));
|
|
63
|
+
this._imports.set(module, currentImports);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
remove(module, imports) {
|
|
67
|
+
const importsToRemove = new Set(typeof imports === "string" ? [imports] : imports);
|
|
68
|
+
if (importsToRemove.size === 0) return this;
|
|
69
|
+
const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set();
|
|
70
|
+
importsToRemove.forEach((i) => currentImports.delete(i));
|
|
71
|
+
if (currentImports.size === 0) {
|
|
72
|
+
this._imports.delete(module);
|
|
73
|
+
} else {
|
|
74
|
+
this._imports.set(module, currentImports);
|
|
75
|
+
}
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
mergeWith(...others) {
|
|
79
|
+
others.forEach((rawOther) => {
|
|
80
|
+
const other = "imports" in rawOther ? rawOther.imports : rawOther;
|
|
81
|
+
other._imports.forEach((imports, module) => {
|
|
82
|
+
this.add(module, imports);
|
|
83
|
+
});
|
|
84
|
+
other._aliases.forEach((aliases, module) => {
|
|
85
|
+
Object.entries(aliases).forEach(([name, alias]) => {
|
|
86
|
+
this.addAlias(module, name, alias);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
mergeWithManifest(manifest) {
|
|
93
|
+
return this.mergeWith(manifest.strictType, manifest.looseType, manifest.encoder, manifest.decoder);
|
|
94
|
+
}
|
|
95
|
+
addAlias(module, name, alias) {
|
|
96
|
+
const currentAliases = this._aliases.get(module) ?? {};
|
|
97
|
+
currentAliases[name] = alias;
|
|
98
|
+
this._aliases.set(module, currentAliases);
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
isEmpty() {
|
|
102
|
+
return this._imports.size === 0;
|
|
103
|
+
}
|
|
104
|
+
resolve(dependencies = {}, useGranularImports = false) {
|
|
105
|
+
const aliasedMap = new Map(
|
|
106
|
+
[...this._imports.entries()].map(([module, imports]) => {
|
|
107
|
+
const aliasMap = this._aliases.get(module) ?? {};
|
|
108
|
+
const joinedImports = [...imports].map((i) => aliasMap[i] ? `${i} as ${aliasMap[i]}` : i);
|
|
109
|
+
return [module, new Set(joinedImports)];
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
const dependencyMap = {
|
|
113
|
+
...useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP,
|
|
114
|
+
...DEFAULT_INTERNAL_MODULE_MAP,
|
|
115
|
+
...dependencies
|
|
116
|
+
};
|
|
117
|
+
const resolvedMap = /* @__PURE__ */ new Map();
|
|
118
|
+
aliasedMap.forEach((imports, module) => {
|
|
119
|
+
const resolvedModule = dependencyMap[module] ?? module;
|
|
120
|
+
const currentImports = resolvedMap.get(resolvedModule) ?? /* @__PURE__ */ new Set();
|
|
121
|
+
imports.forEach((i) => currentImports.add(i));
|
|
122
|
+
resolvedMap.set(resolvedModule, currentImports);
|
|
123
|
+
});
|
|
124
|
+
return resolvedMap;
|
|
125
|
+
}
|
|
126
|
+
toString(dependencies = {}, useGranularImports = false) {
|
|
127
|
+
return [...this.resolve(dependencies, useGranularImports).entries()].sort(([a], [b]) => {
|
|
128
|
+
const aIsRelative = a.startsWith(".");
|
|
129
|
+
const bIsRelative = b.startsWith(".");
|
|
130
|
+
if (aIsRelative && !bIsRelative) return 1;
|
|
131
|
+
if (!aIsRelative && bIsRelative) return -1;
|
|
132
|
+
return a.localeCompare(b);
|
|
133
|
+
}).map(([module, imports]) => {
|
|
134
|
+
const joinedImports = [...imports].sort().filter((i) => {
|
|
135
|
+
const name = i.split(" ");
|
|
136
|
+
if (name.length > 1) {
|
|
137
|
+
return !imports.has(name[1]);
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}).join(", ");
|
|
141
|
+
return `import { ${joinedImports} } from '${module}';`;
|
|
142
|
+
}).join("\n");
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers) {
|
|
146
|
+
const hasByteDeltasAsync = (instructionNode.byteDeltas ?? []).some(
|
|
147
|
+
({ value }) => isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name)
|
|
148
|
+
);
|
|
149
|
+
const hasRemainingAccountsAsync = (instructionNode.remainingAccounts ?? []).some(
|
|
150
|
+
({ value }) => isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name)
|
|
151
|
+
);
|
|
152
|
+
return hasAsyncDefaultValues(resolvedInputs, asyncResolvers) || hasByteDeltasAsync || hasRemainingAccountsAsync;
|
|
153
|
+
}
|
|
154
|
+
function hasAsyncDefaultValues(resolvedInputs, asyncResolvers) {
|
|
155
|
+
return resolvedInputs.some(
|
|
156
|
+
(input) => !!input.defaultValue && isAsyncDefaultValue(input.defaultValue, asyncResolvers)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
function isAsyncDefaultValue(defaultValue, asyncResolvers) {
|
|
160
|
+
switch (defaultValue.kind) {
|
|
161
|
+
case "pdaValueNode":
|
|
162
|
+
return true;
|
|
163
|
+
case "resolverValueNode":
|
|
164
|
+
return asyncResolvers.includes(defaultValue.name);
|
|
165
|
+
case "conditionalValueNode":
|
|
166
|
+
return isAsyncDefaultValue(defaultValue.condition, asyncResolvers) || (defaultValue.ifFalse == null ? false : isAsyncDefaultValue(defaultValue.ifFalse, asyncResolvers)) || (defaultValue.ifTrue == null ? false : isAsyncDefaultValue(defaultValue.ifTrue, asyncResolvers));
|
|
167
|
+
default:
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function getInstructionDependencies(input, asyncResolvers, useAsync) {
|
|
172
|
+
if (isNode(input, "instructionNode")) {
|
|
173
|
+
return deduplicateInstructionDependencies([
|
|
174
|
+
...input.accounts.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)),
|
|
175
|
+
...input.arguments.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)),
|
|
176
|
+
...(input.extraArguments ?? []).flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync))
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
if (!input.defaultValue) return [];
|
|
180
|
+
const getNestedDependencies = (defaultValue) => {
|
|
181
|
+
if (!defaultValue) return [];
|
|
182
|
+
return getInstructionDependencies({ ...input, defaultValue }, asyncResolvers, useAsync);
|
|
183
|
+
};
|
|
184
|
+
if (isNode(input.defaultValue, ["accountValueNode", "accountBumpValueNode"])) {
|
|
185
|
+
return [accountValueNode(input.defaultValue.name)];
|
|
186
|
+
}
|
|
187
|
+
if (isNode(input.defaultValue, ["argumentValueNode"])) {
|
|
188
|
+
return [argumentValueNode(input.defaultValue.name)];
|
|
189
|
+
}
|
|
190
|
+
if (isNode(input.defaultValue, "pdaValueNode")) {
|
|
191
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
192
|
+
input.defaultValue.seeds.forEach((seed) => {
|
|
193
|
+
if (isNode(seed.value, ["accountValueNode", "argumentValueNode"])) {
|
|
194
|
+
dependencies.set(seed.value.name, { ...seed.value });
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return [...dependencies.values()];
|
|
198
|
+
}
|
|
199
|
+
if (isNode(input.defaultValue, "resolverValueNode")) {
|
|
200
|
+
const isSynchronousResolver = !asyncResolvers.includes(input.defaultValue.name);
|
|
201
|
+
if (useAsync || isSynchronousResolver) {
|
|
202
|
+
return input.defaultValue.dependsOn ?? [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (isNode(input.defaultValue, "conditionalValueNode")) {
|
|
206
|
+
return deduplicateInstructionDependencies([
|
|
207
|
+
...getNestedDependencies(input.defaultValue.condition),
|
|
208
|
+
...getNestedDependencies(input.defaultValue.ifTrue),
|
|
209
|
+
...getNestedDependencies(input.defaultValue.ifFalse)
|
|
210
|
+
]);
|
|
211
|
+
}
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
function getBytesFromBytesValueNode(node) {
|
|
215
|
+
switch (node.encoding) {
|
|
216
|
+
case "utf8":
|
|
217
|
+
return getUtf8Encoder().encode(node.data);
|
|
218
|
+
case "base16":
|
|
219
|
+
return getBase16Encoder().encode(node.data);
|
|
220
|
+
case "base58":
|
|
221
|
+
return getBase58Encoder().encode(node.data);
|
|
222
|
+
case "base64":
|
|
223
|
+
default:
|
|
224
|
+
return getBase64Encoder().encode(node.data);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
var parseCustomDataOptions = (customDataOptions, defaultSuffix) => new Map(
|
|
228
|
+
customDataOptions.map((o) => {
|
|
229
|
+
const options = typeof o === "string" ? { name: o } : o;
|
|
230
|
+
const importAs = camelCase(options.importAs ?? `${options.name}${defaultSuffix}`);
|
|
231
|
+
const importFrom = options.importFrom ?? "hooked";
|
|
232
|
+
return [
|
|
233
|
+
camelCase(options.name),
|
|
234
|
+
{
|
|
235
|
+
extract: options.extract ?? false,
|
|
236
|
+
extractAs: options.extractAs ? camelCase(options.extractAs) : importAs,
|
|
237
|
+
importAs,
|
|
238
|
+
importFrom,
|
|
239
|
+
linkNode: definedTypeLinkNode(importAs)
|
|
240
|
+
}
|
|
241
|
+
];
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
var getDefinedTypeNodesToExtract = (nodes, parsedCustomDataOptions) => nodes.flatMap((node) => {
|
|
245
|
+
const options = parsedCustomDataOptions.get(node.name);
|
|
246
|
+
if (!options || !options.extract) return [];
|
|
247
|
+
if (isNode(node, "accountNode")) {
|
|
248
|
+
return [definedTypeNode({ name: options.extractAs, type: { ...node.data } })];
|
|
249
|
+
}
|
|
250
|
+
return [
|
|
251
|
+
definedTypeNode({
|
|
252
|
+
name: options.extractAs,
|
|
253
|
+
type: structTypeNodeFromInstructionArgumentNodes(node.arguments)
|
|
254
|
+
})
|
|
255
|
+
];
|
|
256
|
+
});
|
|
257
|
+
function getImportFromFactory(overrides, customAccountData, customInstructionData) {
|
|
258
|
+
const customDataOverrides = Object.fromEntries(
|
|
259
|
+
[...customAccountData.values(), ...customInstructionData.values()].map(({ importFrom, importAs }) => [
|
|
260
|
+
importAs,
|
|
261
|
+
importFrom
|
|
262
|
+
])
|
|
263
|
+
);
|
|
264
|
+
const linkOverrides = {
|
|
265
|
+
accounts: overrides.accounts ?? {},
|
|
266
|
+
definedTypes: { ...customDataOverrides, ...overrides.definedTypes },
|
|
267
|
+
instructions: overrides.instructions ?? {},
|
|
268
|
+
pdas: overrides.pdas ?? {},
|
|
269
|
+
programs: overrides.programs ?? {},
|
|
270
|
+
resolvers: overrides.resolvers ?? {}
|
|
271
|
+
};
|
|
272
|
+
return (node) => {
|
|
273
|
+
const kind = node.kind;
|
|
274
|
+
switch (kind) {
|
|
275
|
+
case "accountLinkNode":
|
|
276
|
+
return linkOverrides.accounts[node.name] ?? "generatedAccounts";
|
|
277
|
+
case "definedTypeLinkNode":
|
|
278
|
+
return linkOverrides.definedTypes[node.name] ?? "generatedTypes";
|
|
279
|
+
case "instructionLinkNode":
|
|
280
|
+
return linkOverrides.instructions[node.name] ?? "generatedInstructions";
|
|
281
|
+
case "pdaLinkNode":
|
|
282
|
+
return linkOverrides.pdas[node.name] ?? "generatedPdas";
|
|
283
|
+
case "programLinkNode":
|
|
284
|
+
return linkOverrides.programs[node.name] ?? "generatedPrograms";
|
|
285
|
+
case "resolverValueNode":
|
|
286
|
+
return linkOverrides.resolvers[node.name] ?? "hooked";
|
|
287
|
+
default:
|
|
288
|
+
throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {
|
|
289
|
+
expectedKinds: [
|
|
290
|
+
"AccountLinkNode",
|
|
291
|
+
"DefinedTypeLinkNode",
|
|
292
|
+
"InstructionLinkNode",
|
|
293
|
+
"PdaLinkNode",
|
|
294
|
+
"ProgramLinkNode",
|
|
295
|
+
"resolverValueNode"
|
|
296
|
+
],
|
|
297
|
+
kind,
|
|
298
|
+
node
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function jsDocblock(docs) {
|
|
304
|
+
if (docs.length <= 0) return "";
|
|
305
|
+
if (docs.length === 1) return `/** ${docs[0]} */
|
|
306
|
+
`;
|
|
307
|
+
const lines = docs.map((doc) => ` * ${doc}`);
|
|
308
|
+
return `/**
|
|
309
|
+
${lines.join("\n")}
|
|
310
|
+
*/
|
|
311
|
+
`;
|
|
312
|
+
}
|
|
313
|
+
var render = (template, context, options) => {
|
|
314
|
+
const dirname$1 = dirname(fileURLToPath(import.meta.url)) ;
|
|
315
|
+
const templates = join(dirname$1, "templates");
|
|
316
|
+
const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options });
|
|
317
|
+
env.addFilter("pascalCase", pascalCase);
|
|
318
|
+
env.addFilter("camelCase", camelCase);
|
|
319
|
+
env.addFilter("snakeCase", snakeCase);
|
|
320
|
+
env.addFilter("kebabCase", kebabCase);
|
|
321
|
+
env.addFilter("titleCase", titleCase);
|
|
322
|
+
env.addFilter("jsDocblock", jsDocblock);
|
|
323
|
+
return env.render(template, context);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// src/fragments/common.ts
|
|
327
|
+
function fragment(render2, imports) {
|
|
328
|
+
return new Fragment(render2, imports);
|
|
329
|
+
}
|
|
330
|
+
function fragmentFromTemplate(fragmentFile, context, options) {
|
|
331
|
+
return fragment(render(join("fragments", fragmentFile), context, options));
|
|
332
|
+
}
|
|
333
|
+
function mergeFragments(fragments, mergeRenders) {
|
|
334
|
+
return new Fragment(
|
|
335
|
+
mergeRenders(fragments.map((f) => f.render)),
|
|
336
|
+
new ImportMap().mergeWith(...fragments),
|
|
337
|
+
new Set(fragments.flatMap((f) => [...f.features]))
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
var Fragment = class _Fragment {
|
|
341
|
+
render;
|
|
342
|
+
imports;
|
|
343
|
+
features;
|
|
344
|
+
constructor(render2, imports, features) {
|
|
345
|
+
this.render = render2;
|
|
346
|
+
this.imports = imports ? new ImportMap().mergeWith(imports) : new ImportMap();
|
|
347
|
+
this.features = /* @__PURE__ */ new Set([...features ?? []]);
|
|
348
|
+
}
|
|
349
|
+
setRender(render2) {
|
|
350
|
+
this.render = render2;
|
|
351
|
+
return this;
|
|
352
|
+
}
|
|
353
|
+
mapRender(fn) {
|
|
354
|
+
this.render = fn(this.render);
|
|
355
|
+
return this;
|
|
356
|
+
}
|
|
357
|
+
addImports(module, imports) {
|
|
358
|
+
this.imports.add(module, imports);
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
removeImports(module, imports) {
|
|
362
|
+
this.imports.remove(module, imports);
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
mergeImportsWith(...others) {
|
|
366
|
+
this.imports.mergeWith(...others);
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
369
|
+
addImportAlias(module, name, alias) {
|
|
370
|
+
this.imports.addAlias(module, name, alias);
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
addFeatures(features) {
|
|
374
|
+
const featureArray = typeof features === "string" ? [features] : features;
|
|
375
|
+
featureArray.forEach((f) => this.features.add(f));
|
|
376
|
+
return this;
|
|
377
|
+
}
|
|
378
|
+
removeFeatures(features) {
|
|
379
|
+
const featureArray = typeof features === "string" ? [features] : features;
|
|
380
|
+
featureArray.forEach((f) => this.features.delete(f));
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
hasFeatures(features) {
|
|
384
|
+
const featureArray = typeof features === "string" ? [features] : features;
|
|
385
|
+
return featureArray.every((f) => this.features.has(f));
|
|
386
|
+
}
|
|
387
|
+
mergeFeaturesWith(...others) {
|
|
388
|
+
others.forEach((f) => this.addFeatures([...f.features]));
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
clone() {
|
|
392
|
+
return new _Fragment(this.render).mergeImportsWith(this.imports);
|
|
393
|
+
}
|
|
394
|
+
toString() {
|
|
395
|
+
return this.render;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// src/fragments/accountFetchHelpers.ts
|
|
400
|
+
function getAccountFetchHelpersFragment(scope) {
|
|
401
|
+
const { accountNode, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
|
|
402
|
+
const hasCustomData = customAccountData.has(accountNode.name);
|
|
403
|
+
const accountTypeFragment = hasCustomData ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name));
|
|
404
|
+
const decoderFunctionFragment = hasCustomData ? typeManifest2.decoder.clone() : fragment(`${nameApi.decoderFunction(accountNode.name)}()`);
|
|
405
|
+
return fragmentFromTemplate("accountFetchHelpers.njk", {
|
|
406
|
+
accountType: accountTypeFragment.render,
|
|
407
|
+
decodeFunction: nameApi.accountDecodeFunction(accountNode.name),
|
|
408
|
+
decoderFunction: decoderFunctionFragment.render,
|
|
409
|
+
fetchAllFunction: nameApi.accountFetchAllFunction(accountNode.name),
|
|
410
|
+
fetchAllMaybeFunction: nameApi.accountFetchAllMaybeFunction(accountNode.name),
|
|
411
|
+
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
|
|
412
|
+
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name)
|
|
413
|
+
}).mergeImportsWith(accountTypeFragment, decoderFunctionFragment).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [
|
|
414
|
+
"type Account",
|
|
415
|
+
"assertAccountExists",
|
|
416
|
+
"assertAccountsExist",
|
|
417
|
+
"decodeAccount",
|
|
418
|
+
"type EncodedAccount",
|
|
419
|
+
"fetchEncodedAccount",
|
|
420
|
+
"fetchEncodedAccounts",
|
|
421
|
+
"type FetchAccountConfig",
|
|
422
|
+
"type FetchAccountsConfig",
|
|
423
|
+
"type MaybeAccount",
|
|
424
|
+
"type MaybeEncodedAccount"
|
|
425
|
+
]);
|
|
426
|
+
}
|
|
427
|
+
function getAccountPdaHelpersFragment(scope) {
|
|
428
|
+
const { accountNode, programNode, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope;
|
|
429
|
+
const pdaNode = accountNode.pda ? linkables.get(accountNode.pda) : void 0;
|
|
430
|
+
if (!pdaNode) {
|
|
431
|
+
return fragment("");
|
|
432
|
+
}
|
|
433
|
+
const accountTypeFragment = customAccountData.has(accountNode.name) ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name));
|
|
434
|
+
const importFrom = "generatedPdas";
|
|
435
|
+
const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name);
|
|
436
|
+
const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name);
|
|
437
|
+
const hasVariableSeeds = pdaNode.seeds.filter(isNodeFilter("variablePdaSeedNode")).length > 0;
|
|
438
|
+
return fragmentFromTemplate("accountPdaHelpers.njk", {
|
|
439
|
+
accountType: accountTypeFragment.render,
|
|
440
|
+
fetchFromSeedsFunction: nameApi.accountFetchFromSeedsFunction(accountNode.name),
|
|
441
|
+
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
|
|
442
|
+
fetchMaybeFromSeedsFunction: nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name),
|
|
443
|
+
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),
|
|
444
|
+
findPdaFunction,
|
|
445
|
+
hasVariableSeeds,
|
|
446
|
+
pdaSeedsType,
|
|
447
|
+
program: programNode
|
|
448
|
+
}).mergeImportsWith(accountTypeFragment).addImports(importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [
|
|
449
|
+
"type Account",
|
|
450
|
+
"assertAccountExists",
|
|
451
|
+
"type FetchAccountConfig",
|
|
452
|
+
"type MaybeAccount"
|
|
453
|
+
]);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// src/fragments/accountSizeHelpers.ts
|
|
457
|
+
function getAccountSizeHelpersFragment(scope) {
|
|
458
|
+
const { accountNode, nameApi } = scope;
|
|
459
|
+
if (accountNode.size == null) {
|
|
460
|
+
return fragment("");
|
|
461
|
+
}
|
|
462
|
+
return fragmentFromTemplate("accountSizeHelpers.njk", {
|
|
463
|
+
account: accountNode,
|
|
464
|
+
getSizeFunction: nameApi.accountGetSizeFunction(accountNode.name)
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/fragments/type.ts
|
|
469
|
+
function getTypeFragment(scope) {
|
|
470
|
+
const { name, manifest, nameApi, docs = [] } = scope;
|
|
471
|
+
const typeFragment = fragmentFromTemplate("type.njk", {
|
|
472
|
+
docs,
|
|
473
|
+
looseName: nameApi.dataArgsType(name),
|
|
474
|
+
manifest,
|
|
475
|
+
strictName: nameApi.dataType(name)
|
|
476
|
+
});
|
|
477
|
+
if (!manifest.isEnum) {
|
|
478
|
+
typeFragment.mergeImportsWith(manifest.strictType, manifest.looseType);
|
|
479
|
+
}
|
|
480
|
+
return typeFragment;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/fragments/typeDecoder.ts
|
|
484
|
+
function getTypeDecoderFragment(scope) {
|
|
485
|
+
const { name, manifest, nameApi, docs = [] } = scope;
|
|
486
|
+
return fragmentFromTemplate("typeDecoder.njk", {
|
|
487
|
+
decoderFunction: nameApi.decoderFunction(name),
|
|
488
|
+
docs,
|
|
489
|
+
looseName: nameApi.dataArgsType(name),
|
|
490
|
+
manifest,
|
|
491
|
+
strictName: nameApi.dataType(name)
|
|
492
|
+
}).mergeImportsWith(manifest.decoder).addImports("solanaCodecsCore", "type Decoder");
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/fragments/typeEncoder.ts
|
|
496
|
+
function getTypeEncoderFragment(scope) {
|
|
497
|
+
const { name, manifest, nameApi, docs = [] } = scope;
|
|
498
|
+
return fragmentFromTemplate("typeEncoder.njk", {
|
|
499
|
+
docs,
|
|
500
|
+
encoderFunction: nameApi.encoderFunction(name),
|
|
501
|
+
looseName: nameApi.dataArgsType(name),
|
|
502
|
+
manifest,
|
|
503
|
+
strictName: nameApi.dataType(name)
|
|
504
|
+
}).mergeImportsWith(manifest.encoder).addImports("solanaCodecsCore", "type Encoder");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/fragments/typeCodec.ts
|
|
508
|
+
function getTypeCodecFragment(scope) {
|
|
509
|
+
const { name, manifest, nameApi } = scope;
|
|
510
|
+
return mergeFragments(
|
|
511
|
+
[
|
|
512
|
+
getTypeEncoderFragment({ ...scope, docs: scope.encoderDocs }),
|
|
513
|
+
getTypeDecoderFragment({ ...scope, docs: scope.decoderDocs }),
|
|
514
|
+
fragmentFromTemplate("typeCodec.njk", {
|
|
515
|
+
codecFunction: nameApi.codecFunction(name),
|
|
516
|
+
decoderFunction: nameApi.decoderFunction(name),
|
|
517
|
+
docs: scope.codecDocs,
|
|
518
|
+
encoderFunction: nameApi.encoderFunction(name),
|
|
519
|
+
looseName: nameApi.dataArgsType(name),
|
|
520
|
+
manifest,
|
|
521
|
+
strictName: nameApi.dataType(name)
|
|
522
|
+
}).addImports("solanaCodecsCore", ["type Codec", "combineCodec"])
|
|
523
|
+
],
|
|
524
|
+
(renders) => renders.join("\n\n")
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/fragments/typeWithCodec.ts
|
|
529
|
+
function getTypeWithCodecFragment(scope) {
|
|
530
|
+
return mergeFragments(
|
|
531
|
+
[getTypeFragment({ ...scope, docs: scope.typeDocs }), getTypeCodecFragment(scope)],
|
|
532
|
+
(renders) => renders.join("\n\n")
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/fragments/accountType.ts
|
|
537
|
+
function getAccountTypeFragment(scope) {
|
|
538
|
+
const { accountNode, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
|
|
539
|
+
if (customAccountData.has(accountNode.name)) {
|
|
540
|
+
return fragment("");
|
|
541
|
+
}
|
|
542
|
+
return getTypeWithCodecFragment({
|
|
543
|
+
manifest: typeManifest2,
|
|
544
|
+
name: accountNode.name,
|
|
545
|
+
nameApi
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
function getDiscriminatorConditionFragment(scope) {
|
|
549
|
+
return mergeFragments(
|
|
550
|
+
scope.discriminators.flatMap((discriminator) => {
|
|
551
|
+
if (isNode(discriminator, "sizeDiscriminatorNode")) {
|
|
552
|
+
return [getSizeConditionFragment(discriminator, scope)];
|
|
553
|
+
}
|
|
554
|
+
if (isNode(discriminator, "constantDiscriminatorNode")) {
|
|
555
|
+
return [getByteConditionFragment(discriminator, scope)];
|
|
556
|
+
}
|
|
557
|
+
if (isNode(discriminator, "fieldDiscriminatorNode")) {
|
|
558
|
+
return [getFieldConditionFragment(discriminator, scope)];
|
|
559
|
+
}
|
|
560
|
+
return [];
|
|
561
|
+
}),
|
|
562
|
+
(r) => r.join(" && ")
|
|
563
|
+
).mapRender((r) => `if (${r}) { ${scope.ifTrue}; }`);
|
|
564
|
+
}
|
|
565
|
+
function getSizeConditionFragment(discriminator, scope) {
|
|
566
|
+
const { dataName } = scope;
|
|
567
|
+
return fragment(`${dataName}.length === ${discriminator.size}`);
|
|
568
|
+
}
|
|
569
|
+
function getByteConditionFragment(discriminator, scope) {
|
|
570
|
+
const { dataName, typeManifestVisitor } = scope;
|
|
571
|
+
const constant = visit(discriminator.constant, typeManifestVisitor).value;
|
|
572
|
+
return constant.mapRender((r) => `containsBytes(${dataName}, ${r}, ${discriminator.offset})`).addImports("solanaCodecsCore", "containsBytes");
|
|
573
|
+
}
|
|
574
|
+
function getFieldConditionFragment(discriminator, scope) {
|
|
575
|
+
const field = scope.struct.fields.find((f) => f.name === discriminator.name);
|
|
576
|
+
if (!field || !field.defaultValue) {
|
|
577
|
+
throw new Error(
|
|
578
|
+
`Field discriminator "${discriminator.name}" does not have a matching argument with default value.`
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
if (isNode(field.type, "arrayTypeNode") && isNode(field.type.item, "numberTypeNode") && field.type.item.format === "u8" && isNode(field.type.count, "fixedCountNode") && isNode(field.defaultValue, "arrayValueNode") && field.defaultValue.items.every(isNodeFilter("numberValueNode"))) {
|
|
582
|
+
const base64Bytes = getBase64Decoder().decode(
|
|
583
|
+
new Uint8Array(field.defaultValue.items.map((node) => node.number))
|
|
584
|
+
);
|
|
585
|
+
return getByteConditionFragment(
|
|
586
|
+
constantDiscriminatorNode(constantValueNodeFromBytes("base64", base64Bytes), discriminator.offset),
|
|
587
|
+
scope
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
return getByteConditionFragment(
|
|
591
|
+
constantDiscriminatorNode(constantValueNode(field.type, field.defaultValue), discriminator.offset),
|
|
592
|
+
scope
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
function getInstructionAccountMetaFragment(instructionAccountNode) {
|
|
596
|
+
const typeParam = `TAccount${pascalCase(instructionAccountNode.name)}`;
|
|
597
|
+
if (instructionAccountNode.isSigner === true && instructionAccountNode.isWritable) {
|
|
598
|
+
return fragment(`WritableSignerAccount<${typeParam}> & IAccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type WritableSignerAccount"]).addImports("solanaSigners", ["type IAccountSignerMeta"]);
|
|
599
|
+
}
|
|
600
|
+
if (instructionAccountNode.isSigner === true) {
|
|
601
|
+
return fragment(`ReadonlySignerAccount<${typeParam}> & IAccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type ReadonlySignerAccount"]).addImports("solanaSigners", ["type IAccountSignerMeta"]);
|
|
602
|
+
}
|
|
603
|
+
if (instructionAccountNode.isWritable) {
|
|
604
|
+
return fragment(`WritableAccount<${typeParam}>`).addImports("solanaInstructions", "type WritableAccount");
|
|
605
|
+
}
|
|
606
|
+
return fragment(`ReadonlyAccount<${typeParam}>`).addImports("solanaInstructions", "type ReadonlyAccount");
|
|
607
|
+
}
|
|
608
|
+
function getInstructionAccountTypeParamFragment(scope) {
|
|
609
|
+
const { instructionNode, instructionAccountNode, programNode, allowAccountMeta, linkables } = scope;
|
|
610
|
+
const typeParam = `TAccount${pascalCase(instructionAccountNode.name)}`;
|
|
611
|
+
const accountMeta = allowAccountMeta ? " | IAccountMeta<string>" : "";
|
|
612
|
+
const imports = new ImportMap();
|
|
613
|
+
if (allowAccountMeta) {
|
|
614
|
+
imports.add("solanaInstructions", "type IAccountMeta");
|
|
615
|
+
}
|
|
616
|
+
if (instructionNode.optionalAccountStrategy === "omitted" && instructionAccountNode.isOptional) {
|
|
617
|
+
return fragment(`${typeParam} extends string${accountMeta} | undefined = undefined`, imports);
|
|
618
|
+
}
|
|
619
|
+
const defaultAddress = getDefaultAddress(instructionAccountNode.defaultValue, programNode.publicKey, linkables);
|
|
620
|
+
return fragment(`${typeParam} extends string${accountMeta} = ${defaultAddress}`, imports);
|
|
621
|
+
}
|
|
622
|
+
function getDefaultAddress(defaultValue, programId, linkables) {
|
|
623
|
+
switch (defaultValue?.kind) {
|
|
624
|
+
case "publicKeyValueNode":
|
|
625
|
+
return `"${defaultValue.publicKey}"`;
|
|
626
|
+
case "programLinkNode":
|
|
627
|
+
const programNode = linkables.get(defaultValue);
|
|
628
|
+
return programNode ? `"${programNode.publicKey}"` : "string";
|
|
629
|
+
case "programIdValueNode":
|
|
630
|
+
return `"${programId}"`;
|
|
631
|
+
default:
|
|
632
|
+
return "string";
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function getInstructionByteDeltaFragment(scope) {
|
|
636
|
+
const { byteDeltas } = scope.instructionNode;
|
|
637
|
+
const fragments = (byteDeltas ?? []).flatMap((r) => getByteDeltaFragment(r, scope));
|
|
638
|
+
if (fragments.length === 0) return fragment("");
|
|
639
|
+
return mergeFragments(
|
|
640
|
+
fragments,
|
|
641
|
+
(r) => `// Bytes created or reallocated by the instruction.
|
|
642
|
+
const byteDelta: number = [${r.join(",")}].reduce((a, b) => a + b, 0);`
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
function getByteDeltaFragment(byteDelta, scope) {
|
|
646
|
+
const bytesFragment = (() => {
|
|
647
|
+
if (isNode(byteDelta.value, "numberValueNode")) {
|
|
648
|
+
return getNumberValueNodeFragment(byteDelta);
|
|
649
|
+
}
|
|
650
|
+
if (isNode(byteDelta.value, "argumentValueNode")) {
|
|
651
|
+
return getArgumentValueNodeFragment(byteDelta);
|
|
652
|
+
}
|
|
653
|
+
if (isNode(byteDelta.value, "accountLinkNode")) {
|
|
654
|
+
return getAccountLinkNodeFragment(byteDelta, scope);
|
|
655
|
+
}
|
|
656
|
+
if (isNode(byteDelta.value, "resolverValueNode")) {
|
|
657
|
+
return getResolverValueNodeFragment(byteDelta, scope);
|
|
658
|
+
}
|
|
659
|
+
return null;
|
|
660
|
+
})();
|
|
661
|
+
if (bytesFragment === null) return [];
|
|
662
|
+
if (byteDelta.withHeader) {
|
|
663
|
+
bytesFragment.mapRender((r) => `${r} + BASE_ACCOUNT_SIZE`).addImports("solanaAccounts", "BASE_ACCOUNT_SIZE");
|
|
664
|
+
}
|
|
665
|
+
if (byteDelta.subtract) {
|
|
666
|
+
bytesFragment.mapRender((r) => `- (${r})`);
|
|
667
|
+
}
|
|
668
|
+
return [bytesFragment];
|
|
669
|
+
}
|
|
670
|
+
function getNumberValueNodeFragment(byteDelta) {
|
|
671
|
+
assertIsNode(byteDelta.value, "numberValueNode");
|
|
672
|
+
return fragment(byteDelta.value.number.toString());
|
|
673
|
+
}
|
|
674
|
+
function getArgumentValueNodeFragment(byteDelta) {
|
|
675
|
+
assertIsNode(byteDelta.value, "argumentValueNode");
|
|
676
|
+
const argumentName = camelCase(byteDelta.value.name);
|
|
677
|
+
return fragment(`Number(args.${argumentName})`);
|
|
678
|
+
}
|
|
679
|
+
function getAccountLinkNodeFragment(byteDelta, scope) {
|
|
680
|
+
assertIsNode(byteDelta.value, "accountLinkNode");
|
|
681
|
+
const functionName = scope.nameApi.accountGetSizeFunction(byteDelta.value.name);
|
|
682
|
+
return fragment(`${functionName}()`).addImports(scope.getImportFrom(byteDelta.value), functionName);
|
|
683
|
+
}
|
|
684
|
+
function getResolverValueNodeFragment(byteDelta, scope) {
|
|
685
|
+
assertIsNode(byteDelta.value, "resolverValueNode");
|
|
686
|
+
const isAsync = scope.asyncResolvers.includes(byteDelta.value.name);
|
|
687
|
+
if (!scope.useAsync && isAsync) return null;
|
|
688
|
+
const awaitKeyword = scope.useAsync && isAsync ? "await " : "";
|
|
689
|
+
const functionName = scope.nameApi.resolverFunction(byteDelta.value.name);
|
|
690
|
+
return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(byteDelta.value), functionName).addFeatures(["instruction:resolverScopeVariable"]);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// src/fragments/instructionData.ts
|
|
694
|
+
function getInstructionDataFragment(scope) {
|
|
695
|
+
const { instructionNode, dataArgsManifest, nameApi, customInstructionData } = scope;
|
|
696
|
+
if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) {
|
|
697
|
+
return fragment("");
|
|
698
|
+
}
|
|
699
|
+
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
|
|
700
|
+
return getTypeWithCodecFragment({
|
|
701
|
+
manifest: dataArgsManifest,
|
|
702
|
+
name: instructionDataName,
|
|
703
|
+
nameApi
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
function getDiscriminatorConstantsFragment(scope) {
|
|
707
|
+
const fragments = scope.discriminatorNodes.map((node) => getDiscriminatorConstantFragment(node, scope)).filter(Boolean);
|
|
708
|
+
return mergeFragments(fragments, (r) => r.join("\n\n"));
|
|
709
|
+
}
|
|
710
|
+
function getDiscriminatorConstantFragment(discriminatorNode, scope) {
|
|
711
|
+
switch (discriminatorNode.kind) {
|
|
712
|
+
case "constantDiscriminatorNode":
|
|
713
|
+
return getConstantDiscriminatorConstantFragment(discriminatorNode, scope);
|
|
714
|
+
case "fieldDiscriminatorNode":
|
|
715
|
+
return getFieldDiscriminatorConstantFragment(discriminatorNode, scope);
|
|
716
|
+
default:
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
function getConstantDiscriminatorConstantFragment(discriminatorNode, scope) {
|
|
721
|
+
const { discriminatorNodes, typeManifestVisitor, prefix } = scope;
|
|
722
|
+
const index = discriminatorNodes.filter(isNodeFilter("constantDiscriminatorNode")).indexOf(discriminatorNode);
|
|
723
|
+
const suffix = index <= 0 ? "" : `_${index + 1}`;
|
|
724
|
+
const name = camelCase(`${prefix}_discriminator${suffix}`);
|
|
725
|
+
const encoder = visit(discriminatorNode.constant.type, typeManifestVisitor).encoder;
|
|
726
|
+
const value = visit(discriminatorNode.constant.value, typeManifestVisitor).value;
|
|
727
|
+
return getConstantFragment({ ...scope, encoder, name, value });
|
|
728
|
+
}
|
|
729
|
+
function getFieldDiscriminatorConstantFragment(discriminatorNode, scope) {
|
|
730
|
+
const { fields, prefix, typeManifestVisitor } = scope;
|
|
731
|
+
const field = fields.find((f) => f.name === discriminatorNode.name);
|
|
732
|
+
if (!field || !field.defaultValue || !isNode(field.defaultValue, VALUE_NODES)) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
const name = camelCase(`${prefix}_${discriminatorNode.name}`);
|
|
736
|
+
const encoder = visit(field.type, typeManifestVisitor).encoder;
|
|
737
|
+
const value = visit(field.defaultValue, typeManifestVisitor).value;
|
|
738
|
+
return getConstantFragment({ ...scope, encoder, name, value });
|
|
739
|
+
}
|
|
740
|
+
function getConstantFragment(scope) {
|
|
741
|
+
const { encoder, name, nameApi, value } = scope;
|
|
742
|
+
const constantName = nameApi.constant(name);
|
|
743
|
+
const constantFunction = nameApi.constantFunction(name);
|
|
744
|
+
return mergeFragments(
|
|
745
|
+
[
|
|
746
|
+
value.mapRender((r) => `export const ${constantName} = ${r};`),
|
|
747
|
+
encoder.mapRender((r) => `export function ${constantFunction}() { return ${r}.encode(${constantName}); }`)
|
|
748
|
+
],
|
|
749
|
+
(r) => r.join("\n\n")
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// src/fragments/instructionExtraArgs.ts
|
|
754
|
+
function getInstructionExtraArgsFragment(scope) {
|
|
755
|
+
const { instructionNode, extraArgsManifest, nameApi } = scope;
|
|
756
|
+
if ((instructionNode.extraArguments ?? []).length === 0) {
|
|
757
|
+
return fragment("");
|
|
758
|
+
}
|
|
759
|
+
const instructionExtraName = nameApi.instructionExtraType(instructionNode.name);
|
|
760
|
+
return fragmentFromTemplate("instructionExtraArgs.njk", {
|
|
761
|
+
looseName: nameApi.dataArgsType(instructionExtraName),
|
|
762
|
+
manifest: extraArgsManifest,
|
|
763
|
+
strictName: nameApi.dataType(instructionExtraName)
|
|
764
|
+
}).mergeImportsWith(extraArgsManifest.looseType);
|
|
765
|
+
}
|
|
766
|
+
function getInstructionInputDefaultFragment(scope) {
|
|
767
|
+
const { input, optionalAccountStrategy, asyncResolvers, useAsync, nameApi, typeManifestVisitor, getImportFrom } = scope;
|
|
768
|
+
if (!input.defaultValue) {
|
|
769
|
+
return fragment("");
|
|
770
|
+
}
|
|
771
|
+
if (!useAsync && isAsyncDefaultValue(input.defaultValue, asyncResolvers)) {
|
|
772
|
+
return fragment("");
|
|
773
|
+
}
|
|
774
|
+
const { defaultValue } = input;
|
|
775
|
+
const defaultFragment = (renderedValue, isWritable) => {
|
|
776
|
+
const inputName = camelCase(input.name);
|
|
777
|
+
if (input.kind === "instructionAccountNode" && isNode(defaultValue, "resolverValueNode")) {
|
|
778
|
+
return fragment(`accounts.${inputName} = { ...accounts.${inputName}, ...${renderedValue} };`);
|
|
779
|
+
}
|
|
780
|
+
if (input.kind === "instructionAccountNode" && isWritable === void 0) {
|
|
781
|
+
return fragment(`accounts.${inputName}.value = ${renderedValue};`);
|
|
782
|
+
}
|
|
783
|
+
if (input.kind === "instructionAccountNode") {
|
|
784
|
+
return fragment(
|
|
785
|
+
`accounts.${inputName}.value = ${renderedValue};
|
|
786
|
+
accounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}`
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
return fragment(`args.${inputName} = ${renderedValue};`);
|
|
790
|
+
};
|
|
791
|
+
switch (defaultValue.kind) {
|
|
792
|
+
case "accountValueNode":
|
|
793
|
+
const name = camelCase(defaultValue.name);
|
|
794
|
+
if (input.kind === "instructionAccountNode" && input.resolvedIsSigner && !input.isSigner) {
|
|
795
|
+
return defaultFragment(`expectTransactionSigner(accounts.${name}.value).address`).addImports(
|
|
796
|
+
"shared",
|
|
797
|
+
"expectTransactionSigner"
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
if (input.kind === "instructionAccountNode") {
|
|
801
|
+
return defaultFragment(`expectSome(accounts.${name}.value)`).addImports("shared", "expectSome");
|
|
802
|
+
}
|
|
803
|
+
return defaultFragment(`expectAddress(accounts.${name}.value)`).addImports("shared", "expectAddress");
|
|
804
|
+
case "pdaValueNode":
|
|
805
|
+
if (isNode(defaultValue.pda, "pdaNode")) {
|
|
806
|
+
const pdaProgram = defaultValue.pda.programId ? fragment(
|
|
807
|
+
`'${defaultValue.pda.programId}' as Address<'${defaultValue.pda.programId}'>`
|
|
808
|
+
).addImports("solanaAddresses", "type Address") : fragment("programAddress");
|
|
809
|
+
const pdaSeeds2 = defaultValue.pda.seeds.flatMap((seed) => {
|
|
810
|
+
if (isNode(seed, "constantPdaSeedNode") && isNode(seed.value, "programIdValueNode")) {
|
|
811
|
+
return [
|
|
812
|
+
fragment(`getAddressEncoder().encode(${pdaProgram})`).mergeImportsWith(pdaProgram).addImports("solanaAddresses", "getAddressEncoder")
|
|
813
|
+
];
|
|
814
|
+
}
|
|
815
|
+
if (isNode(seed, "constantPdaSeedNode") && !isNode(seed.value, "programIdValueNode")) {
|
|
816
|
+
const typeManifest2 = visit(seed.type, typeManifestVisitor);
|
|
817
|
+
const valueManifest2 = visit(seed.value, typeManifestVisitor);
|
|
818
|
+
return [
|
|
819
|
+
fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith(
|
|
820
|
+
typeManifest2.encoder,
|
|
821
|
+
valueManifest2.value
|
|
822
|
+
)
|
|
823
|
+
];
|
|
824
|
+
}
|
|
825
|
+
if (isNode(seed, "variablePdaSeedNode")) {
|
|
826
|
+
const typeManifest2 = visit(seed.type, typeManifestVisitor);
|
|
827
|
+
const valueSeed = defaultValue.seeds.find((s) => s.name === seed.name)?.value;
|
|
828
|
+
if (!valueSeed) return [];
|
|
829
|
+
if (isNode(valueSeed, "accountValueNode")) {
|
|
830
|
+
return [
|
|
831
|
+
fragment(
|
|
832
|
+
`${typeManifest2.encoder}.encode(expectAddress(accounts.${camelCase(valueSeed.name)}.value))`
|
|
833
|
+
).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectAddress")
|
|
834
|
+
];
|
|
835
|
+
}
|
|
836
|
+
if (isNode(valueSeed, "argumentValueNode")) {
|
|
837
|
+
return [
|
|
838
|
+
fragment(
|
|
839
|
+
`${typeManifest2.encoder}.encode(expectSome(args.${camelCase(valueSeed.name)}))`
|
|
840
|
+
).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectSome")
|
|
841
|
+
];
|
|
842
|
+
}
|
|
843
|
+
const valueManifest2 = visit(valueSeed, typeManifestVisitor);
|
|
844
|
+
return [
|
|
845
|
+
fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith(
|
|
846
|
+
typeManifest2.encoder,
|
|
847
|
+
valueManifest2.value
|
|
848
|
+
)
|
|
849
|
+
];
|
|
850
|
+
}
|
|
851
|
+
return [];
|
|
852
|
+
});
|
|
853
|
+
const pdaStatement = mergeFragments([pdaProgram, ...pdaSeeds2], ([p, ...s]) => {
|
|
854
|
+
const programAddress2 = p === "programAddress" ? p : `programAddress: ${p}`;
|
|
855
|
+
return `await getProgramDerivedAddress({ ${programAddress2}, seeds: [${s.join(", ")}] })`;
|
|
856
|
+
}).addImports("solanaAddresses", "getProgramDerivedAddress");
|
|
857
|
+
return defaultFragment(pdaStatement.render).mergeImportsWith(pdaStatement);
|
|
858
|
+
}
|
|
859
|
+
const pdaFunction = nameApi.pdaFindFunction(defaultValue.pda.name);
|
|
860
|
+
const pdaArgs = [];
|
|
861
|
+
const pdaSeeds = defaultValue.seeds.map((seed) => {
|
|
862
|
+
if (isNode(seed.value, "accountValueNode")) {
|
|
863
|
+
return fragment(
|
|
864
|
+
`${seed.name}: expectAddress(accounts.${camelCase(seed.value.name)}.value)`
|
|
865
|
+
).addImports("shared", "expectAddress");
|
|
866
|
+
}
|
|
867
|
+
if (isNode(seed.value, "argumentValueNode")) {
|
|
868
|
+
return fragment(`${seed.name}: expectSome(args.${camelCase(seed.value.name)})`).addImports(
|
|
869
|
+
"shared",
|
|
870
|
+
"expectSome"
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
return visit(seed.value, typeManifestVisitor).value.mapRender((r) => `${seed.name}: ${r}`);
|
|
874
|
+
});
|
|
875
|
+
const pdaSeedsFragment = mergeFragments(pdaSeeds, (renders) => renders.join(", ")).mapRender((r) => `{ ${r} }`);
|
|
876
|
+
if (pdaSeeds.length > 0) {
|
|
877
|
+
pdaArgs.push(pdaSeedsFragment.render);
|
|
878
|
+
}
|
|
879
|
+
return defaultFragment(`await ${pdaFunction}(${pdaArgs.join(", ")})`).mergeImportsWith(pdaSeedsFragment).addImports(getImportFrom(defaultValue.pda), pdaFunction);
|
|
880
|
+
case "publicKeyValueNode":
|
|
881
|
+
return defaultFragment(`'${defaultValue.publicKey}' as Address<'${defaultValue.publicKey}'>`).addImports(
|
|
882
|
+
"solanaAddresses",
|
|
883
|
+
"type Address"
|
|
884
|
+
);
|
|
885
|
+
case "programLinkNode":
|
|
886
|
+
const programAddress = nameApi.programAddressConstant(defaultValue.name);
|
|
887
|
+
return defaultFragment(programAddress, false).addImports(getImportFrom(defaultValue), programAddress);
|
|
888
|
+
case "programIdValueNode":
|
|
889
|
+
if (optionalAccountStrategy === "programId" && input.kind === "instructionAccountNode" && input.isOptional) {
|
|
890
|
+
return fragment("");
|
|
891
|
+
}
|
|
892
|
+
return defaultFragment("programAddress", false);
|
|
893
|
+
case "identityValueNode":
|
|
894
|
+
case "payerValueNode":
|
|
895
|
+
return fragment("");
|
|
896
|
+
case "accountBumpValueNode":
|
|
897
|
+
return defaultFragment(
|
|
898
|
+
`expectProgramDerivedAddress(accounts.${camelCase(defaultValue.name)}.value)[1]`
|
|
899
|
+
).addImports("shared", "expectProgramDerivedAddress");
|
|
900
|
+
case "argumentValueNode":
|
|
901
|
+
return defaultFragment(`expectSome(args.${camelCase(defaultValue.name)})`).addImports(
|
|
902
|
+
"shared",
|
|
903
|
+
"expectSome"
|
|
904
|
+
);
|
|
905
|
+
case "resolverValueNode":
|
|
906
|
+
const resolverFunction = nameApi.resolverFunction(defaultValue.name);
|
|
907
|
+
const resolverAwait = useAsync && asyncResolvers.includes(defaultValue.name) ? "await " : "";
|
|
908
|
+
return defaultFragment(`${resolverAwait}${resolverFunction}(resolverScope)`).addImports(getImportFrom(defaultValue), resolverFunction).addFeatures(["instruction:resolverScopeVariable"]);
|
|
909
|
+
case "conditionalValueNode":
|
|
910
|
+
const ifTrueRenderer = renderNestedInstructionDefault({
|
|
911
|
+
...scope,
|
|
912
|
+
defaultValue: defaultValue.ifTrue
|
|
913
|
+
});
|
|
914
|
+
const ifFalseRenderer = renderNestedInstructionDefault({
|
|
915
|
+
...scope,
|
|
916
|
+
defaultValue: defaultValue.ifFalse
|
|
917
|
+
});
|
|
918
|
+
if (!ifTrueRenderer && !ifFalseRenderer) {
|
|
919
|
+
return fragment("");
|
|
920
|
+
}
|
|
921
|
+
const conditionalFragment = fragment("");
|
|
922
|
+
if (ifTrueRenderer) {
|
|
923
|
+
conditionalFragment.mergeImportsWith(ifTrueRenderer).mergeFeaturesWith(ifTrueRenderer);
|
|
924
|
+
}
|
|
925
|
+
if (ifFalseRenderer) {
|
|
926
|
+
conditionalFragment.mergeImportsWith(ifFalseRenderer).mergeFeaturesWith(ifFalseRenderer);
|
|
927
|
+
}
|
|
928
|
+
const negatedCondition = !ifTrueRenderer;
|
|
929
|
+
let condition = "true";
|
|
930
|
+
if (isNode(defaultValue.condition, "resolverValueNode")) {
|
|
931
|
+
const conditionalResolverFunction = nameApi.resolverFunction(defaultValue.condition.name);
|
|
932
|
+
conditionalFragment.addImports(getImportFrom(defaultValue.condition), conditionalResolverFunction).addFeatures(["instruction:resolverScopeVariable"]);
|
|
933
|
+
const conditionalResolverAwait = useAsync && asyncResolvers.includes(defaultValue.condition.name) ? "await " : "";
|
|
934
|
+
condition = `${conditionalResolverAwait}${conditionalResolverFunction}(resolverScope)`;
|
|
935
|
+
condition = negatedCondition ? `!${condition}` : condition;
|
|
936
|
+
} else {
|
|
937
|
+
const comparedInputName = isNode(defaultValue.condition, "accountValueNode") ? `accounts.${camelCase(defaultValue.condition.name)}.value` : `args.${camelCase(defaultValue.condition.name)}`;
|
|
938
|
+
if (defaultValue.value) {
|
|
939
|
+
const comparedValue = visit(defaultValue.value, typeManifestVisitor).value;
|
|
940
|
+
conditionalFragment.mergeImportsWith(comparedValue).mergeFeaturesWith(comparedValue);
|
|
941
|
+
const operator = negatedCondition ? "!==" : "===";
|
|
942
|
+
condition = `${comparedInputName} ${operator} ${comparedValue.render}`;
|
|
943
|
+
} else {
|
|
944
|
+
condition = negatedCondition ? `!${comparedInputName}` : comparedInputName;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (ifTrueRenderer && ifFalseRenderer) {
|
|
948
|
+
return conditionalFragment.setRender(
|
|
949
|
+
`if (${condition}) {
|
|
950
|
+
${ifTrueRenderer.render}
|
|
951
|
+
} else {
|
|
952
|
+
${ifFalseRenderer.render}
|
|
953
|
+
}`
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
return conditionalFragment.setRender(
|
|
957
|
+
`if (${condition}) {
|
|
958
|
+
${ifTrueRenderer ? ifTrueRenderer.render : ifFalseRenderer?.render}
|
|
959
|
+
}`
|
|
960
|
+
);
|
|
961
|
+
default:
|
|
962
|
+
const valueManifest = visit(defaultValue, typeManifestVisitor).value;
|
|
963
|
+
return defaultFragment(valueManifest.render).mergeImportsWith(valueManifest);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
function renderNestedInstructionDefault(scope) {
|
|
967
|
+
const { input, defaultValue } = scope;
|
|
968
|
+
if (!defaultValue) return void 0;
|
|
969
|
+
return getInstructionInputDefaultFragment({
|
|
970
|
+
...scope,
|
|
971
|
+
input: { ...input, defaultValue }
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// src/fragments/instructionInputResolved.ts
|
|
976
|
+
function getInstructionInputResolvedFragment(scope) {
|
|
977
|
+
const resolvedInputFragments = scope.resolvedInputs.flatMap((input) => {
|
|
978
|
+
const inputFragment = getInstructionInputDefaultFragment({
|
|
979
|
+
...scope,
|
|
980
|
+
input,
|
|
981
|
+
optionalAccountStrategy: scope.instructionNode.optionalAccountStrategy
|
|
982
|
+
});
|
|
983
|
+
if (!inputFragment.render) return [];
|
|
984
|
+
const camelName = camelCase(input.name);
|
|
985
|
+
return [
|
|
986
|
+
inputFragment.mapRender(
|
|
987
|
+
(r) => isNode(input, "instructionArgumentNode") ? `if (!args.${camelName}) {
|
|
988
|
+
${r}
|
|
989
|
+
}` : `if (!accounts.${camelName}.value) {
|
|
990
|
+
${r}
|
|
991
|
+
}`
|
|
992
|
+
)
|
|
993
|
+
];
|
|
994
|
+
});
|
|
995
|
+
if (resolvedInputFragments.length === 0) {
|
|
996
|
+
return fragment("");
|
|
997
|
+
}
|
|
998
|
+
return mergeFragments(
|
|
999
|
+
[fragment("// Resolve default values."), ...resolvedInputFragments],
|
|
1000
|
+
(renders) => renders.join("\n")
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
function getInstructionInputTypeFragment(scope) {
|
|
1004
|
+
const { instructionNode, useAsync, nameApi } = scope;
|
|
1005
|
+
const instructionInputType = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
|
|
1006
|
+
const accountsFragment = getAccountsFragment(scope);
|
|
1007
|
+
const [dataArgumentsFragment, customDataArgumentsFragment] = getDataArgumentsFragments(scope);
|
|
1008
|
+
const extraArgumentsFragment = getExtraArgumentsFragment(scope);
|
|
1009
|
+
const remainingAccountsFragment = getRemainingAccountsFragment(instructionNode);
|
|
1010
|
+
return fragmentFromTemplate("instructionInputType.njk", {
|
|
1011
|
+
accountsFragment,
|
|
1012
|
+
customDataArgumentsFragment,
|
|
1013
|
+
dataArgumentsFragment,
|
|
1014
|
+
extraArgumentsFragment,
|
|
1015
|
+
instruction: instructionNode,
|
|
1016
|
+
instructionInputType,
|
|
1017
|
+
remainingAccountsFragment
|
|
1018
|
+
}).mergeImportsWith(
|
|
1019
|
+
accountsFragment,
|
|
1020
|
+
dataArgumentsFragment,
|
|
1021
|
+
customDataArgumentsFragment,
|
|
1022
|
+
extraArgumentsFragment,
|
|
1023
|
+
remainingAccountsFragment
|
|
1024
|
+
).addImports("solanaAddresses", ["type Address"]);
|
|
1025
|
+
}
|
|
1026
|
+
function getAccountsFragment(scope) {
|
|
1027
|
+
const { instructionNode, resolvedInputs, useAsync, asyncResolvers } = scope;
|
|
1028
|
+
const fragments = instructionNode.accounts.map((account) => {
|
|
1029
|
+
const resolvedAccount = resolvedInputs.find(
|
|
1030
|
+
(input) => input.kind === "instructionAccountNode" && input.name === account.name
|
|
1031
|
+
);
|
|
1032
|
+
const hasDefaultValue = !!resolvedAccount.defaultValue && !isNode(resolvedAccount.defaultValue, ["identityValueNode", "payerValueNode"]) && (useAsync || !isAsyncDefaultValue(resolvedAccount.defaultValue, asyncResolvers));
|
|
1033
|
+
const docblock = account.docs.length > 0 ? jsDocblock(account.docs) : "";
|
|
1034
|
+
const optionalSign = hasDefaultValue || resolvedAccount.isOptional ? "?" : "";
|
|
1035
|
+
return getAccountTypeFragment2(resolvedAccount).mapRender(
|
|
1036
|
+
(r) => `${docblock}${camelCase(account.name)}${optionalSign}: ${r};`
|
|
1037
|
+
);
|
|
1038
|
+
});
|
|
1039
|
+
return mergeFragments(fragments, (r) => r.join("\n"));
|
|
1040
|
+
}
|
|
1041
|
+
function getAccountTypeFragment2(account) {
|
|
1042
|
+
const typeParam = `TAccount${pascalCase(account.name)}`;
|
|
1043
|
+
if (account.isPda && account.isSigner === false) {
|
|
1044
|
+
return fragment(`ProgramDerivedAddress<${typeParam}>`).addImports("solanaAddresses", [
|
|
1045
|
+
"type ProgramDerivedAddress"
|
|
1046
|
+
]);
|
|
1047
|
+
}
|
|
1048
|
+
if (account.isPda && account.isSigner === "either") {
|
|
1049
|
+
return fragment(`ProgramDerivedAddress<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type ProgramDerivedAddress"]).addImports("solanaSigners", ["type TransactionSigner"]);
|
|
1050
|
+
}
|
|
1051
|
+
if (account.isSigner === "either") {
|
|
1052
|
+
return fragment(`Address<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type Address"]).addImports("solanaSigners", ["type TransactionSigner"]);
|
|
1053
|
+
}
|
|
1054
|
+
if (account.isSigner) {
|
|
1055
|
+
return fragment(`TransactionSigner<${typeParam}>`).addImports("solanaSigners", ["type TransactionSigner"]);
|
|
1056
|
+
}
|
|
1057
|
+
return fragment(`Address<${typeParam}>`).addImports("solanaAddresses", ["type Address"]);
|
|
1058
|
+
}
|
|
1059
|
+
function getDataArgumentsFragments(scope) {
|
|
1060
|
+
const { instructionNode, nameApi } = scope;
|
|
1061
|
+
const customData = scope.customInstructionData.get(instructionNode.name);
|
|
1062
|
+
if (customData) {
|
|
1063
|
+
return [
|
|
1064
|
+
fragment(""),
|
|
1065
|
+
fragment(nameApi.dataArgsType(customData.importAs)).mergeImportsWith(scope.dataArgsManifest.looseType).mapRender((r) => `${r} & `)
|
|
1066
|
+
];
|
|
1067
|
+
}
|
|
1068
|
+
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
|
|
1069
|
+
const dataArgsType = nameApi.dataArgsType(instructionDataName);
|
|
1070
|
+
const fragments = instructionNode.arguments.flatMap((arg) => {
|
|
1071
|
+
const argFragment = getArgumentFragment(arg, fragment(dataArgsType), scope.resolvedInputs, scope.renamedArgs);
|
|
1072
|
+
return argFragment ? [argFragment] : [];
|
|
1073
|
+
});
|
|
1074
|
+
return [mergeFragments(fragments, (r) => r.join("\n")), fragment("")];
|
|
1075
|
+
}
|
|
1076
|
+
function getExtraArgumentsFragment(scope) {
|
|
1077
|
+
const { instructionNode, nameApi } = scope;
|
|
1078
|
+
const instructionExtraName = nameApi.instructionExtraType(instructionNode.name);
|
|
1079
|
+
const extraArgsType = nameApi.dataArgsType(instructionExtraName);
|
|
1080
|
+
const fragments = (instructionNode.extraArguments ?? []).flatMap((arg) => {
|
|
1081
|
+
const argFragment = getArgumentFragment(arg, fragment(extraArgsType), scope.resolvedInputs, scope.renamedArgs);
|
|
1082
|
+
return argFragment ? [argFragment] : [];
|
|
1083
|
+
});
|
|
1084
|
+
return mergeFragments(fragments, (r) => r.join("\n"));
|
|
1085
|
+
}
|
|
1086
|
+
function getArgumentFragment(arg, argsType, resolvedInputs, renamedArgs) {
|
|
1087
|
+
const resolvedArg = resolvedInputs.find(
|
|
1088
|
+
(input) => isNode(input, "instructionArgumentNode") && input.name === arg.name
|
|
1089
|
+
);
|
|
1090
|
+
if (arg.defaultValue && arg.defaultValueStrategy === "omitted") return null;
|
|
1091
|
+
const renamedName = renamedArgs.get(arg.name) ?? arg.name;
|
|
1092
|
+
const optionalSign = arg.defaultValue || resolvedArg?.defaultValue ? "?" : "";
|
|
1093
|
+
return argsType.mapRender((r) => `${camelCase(renamedName)}${optionalSign}: ${r}["${camelCase(arg.name)}"];`);
|
|
1094
|
+
}
|
|
1095
|
+
function getRemainingAccountsFragment(instructionNode) {
|
|
1096
|
+
const fragments = (instructionNode.remainingAccounts ?? []).flatMap((remainingAccountsNode) => {
|
|
1097
|
+
if (isNode(remainingAccountsNode.value, "resolverValueNode")) return [];
|
|
1098
|
+
const { name } = remainingAccountsNode.value;
|
|
1099
|
+
const allArguments = getAllInstructionArguments(instructionNode);
|
|
1100
|
+
const argumentExists = allArguments.some((arg) => arg.name === name);
|
|
1101
|
+
if (argumentExists) return [];
|
|
1102
|
+
const isSigner = remainingAccountsNode.isSigner ?? false;
|
|
1103
|
+
const optionalSign = remainingAccountsNode.isOptional ?? false ? "?" : "";
|
|
1104
|
+
const signerFragment = fragment(`TransactionSigner`).addImports("solanaSigners", ["type TransactionSigner"]);
|
|
1105
|
+
const addressFragment = fragment(`Address`).addImports("solanaAddresses", ["type Address"]);
|
|
1106
|
+
return (() => {
|
|
1107
|
+
if (isSigner === "either") {
|
|
1108
|
+
return mergeFragments([signerFragment, addressFragment], (r) => r.join(" | "));
|
|
1109
|
+
}
|
|
1110
|
+
return isSigner ? signerFragment : addressFragment;
|
|
1111
|
+
})().mapRender((r) => `${camelCase(name)}${optionalSign}: Array<${r}>;`);
|
|
1112
|
+
});
|
|
1113
|
+
return mergeFragments(fragments, (r) => r.join("\n"));
|
|
1114
|
+
}
|
|
1115
|
+
function getInstructionRemainingAccountsFragment(scope) {
|
|
1116
|
+
const { remainingAccounts } = scope.instructionNode;
|
|
1117
|
+
const fragments = (remainingAccounts ?? []).flatMap((r) => getRemainingAccountsFragment2(r, scope));
|
|
1118
|
+
if (fragments.length === 0) return fragment("");
|
|
1119
|
+
return mergeFragments(
|
|
1120
|
+
fragments,
|
|
1121
|
+
(r) => `// Remaining accounts.
|
|
1122
|
+
const remainingAccounts: IAccountMeta[] = ${r.length === 1 ? r[0] : `[...${r.join(", ...")}]`}`
|
|
1123
|
+
).addImports("solanaInstructions", ["type IAccountMeta"]);
|
|
1124
|
+
}
|
|
1125
|
+
function getRemainingAccountsFragment2(remainingAccounts, scope) {
|
|
1126
|
+
const remainingAccountsFragment = (() => {
|
|
1127
|
+
if (isNode(remainingAccounts.value, "argumentValueNode")) {
|
|
1128
|
+
return getArgumentValueNodeFragment2(remainingAccounts, scope);
|
|
1129
|
+
}
|
|
1130
|
+
if (isNode(remainingAccounts.value, "resolverValueNode")) {
|
|
1131
|
+
return getResolverValueNodeFragment2(remainingAccounts, scope);
|
|
1132
|
+
}
|
|
1133
|
+
return null;
|
|
1134
|
+
})();
|
|
1135
|
+
if (remainingAccountsFragment === null) return [];
|
|
1136
|
+
return [remainingAccountsFragment];
|
|
1137
|
+
}
|
|
1138
|
+
function getArgumentValueNodeFragment2(remainingAccounts, scope) {
|
|
1139
|
+
const { instructionNode } = scope;
|
|
1140
|
+
assertIsNode(remainingAccounts.value, "argumentValueNode");
|
|
1141
|
+
const argumentName = camelCase(remainingAccounts.value.name);
|
|
1142
|
+
const isOptional = remainingAccounts.isOptional ?? false;
|
|
1143
|
+
const isSigner = remainingAccounts.isSigner ?? false;
|
|
1144
|
+
const isWritable = remainingAccounts.isWritable ?? false;
|
|
1145
|
+
const nonSignerRole = isWritable ? "AccountRole.WRITABLE" : "AccountRole.READONLY";
|
|
1146
|
+
const signerRole = isWritable ? "AccountRole.WRITABLE_SIGNER" : "AccountRole.READONLY_SIGNER";
|
|
1147
|
+
const role = isSigner === true ? signerRole : nonSignerRole;
|
|
1148
|
+
const argumentArray = isOptional ? `(args.${argumentName} ?? [])` : `args.${argumentName}`;
|
|
1149
|
+
const allArguments = getAllInstructionArguments(instructionNode);
|
|
1150
|
+
const argumentExists = allArguments.some((arg) => arg.name === remainingAccounts.value.name);
|
|
1151
|
+
if (argumentExists || isSigner === false) {
|
|
1152
|
+
return fragment(`${argumentArray}.map((address) => ({ address, role: ${role} }))`).addImports(
|
|
1153
|
+
"solanaInstructions",
|
|
1154
|
+
["AccountRole"]
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
if (isSigner === "either") {
|
|
1158
|
+
return fragment(
|
|
1159
|
+
`${argumentArray}.map((addressOrSigner) => (isTransactionSigner(addressOrSigner)
|
|
1160
|
+
? { address: addressOrSigner.address, role: ${role}, signer: addressOrSigner }
|
|
1161
|
+
: { address: addressOrSigner, role: ${role} }
|
|
1162
|
+
))`
|
|
1163
|
+
).addImports("solanaInstructions", ["AccountRole"]).addImports("shared", ["isTransactionSigner"]);
|
|
1164
|
+
}
|
|
1165
|
+
return fragment(
|
|
1166
|
+
`${argumentArray}.map((signer) => ({ address: signer.address, role: ${signerRole}, signer }))`
|
|
1167
|
+
).addImports("solanaInstructions", ["AccountRole"]);
|
|
1168
|
+
}
|
|
1169
|
+
function getResolverValueNodeFragment2(remainingAccounts, scope) {
|
|
1170
|
+
assertIsNode(remainingAccounts.value, "resolverValueNode");
|
|
1171
|
+
const isAsync = scope.asyncResolvers.includes(remainingAccounts.value.name);
|
|
1172
|
+
if (!scope.useAsync && isAsync) return null;
|
|
1173
|
+
const awaitKeyword = scope.useAsync && isAsync ? "await " : "";
|
|
1174
|
+
const functionName = scope.nameApi.resolverFunction(remainingAccounts.value.name);
|
|
1175
|
+
return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(remainingAccounts.value), functionName).addFeatures(["instruction:resolverScopeVariable"]);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/fragments/instructionFunction.ts
|
|
1179
|
+
function getInstructionFunctionFragment(scope) {
|
|
1180
|
+
const {
|
|
1181
|
+
useAsync,
|
|
1182
|
+
instructionNode,
|
|
1183
|
+
programNode,
|
|
1184
|
+
resolvedInputs,
|
|
1185
|
+
renamedArgs,
|
|
1186
|
+
dataArgsManifest,
|
|
1187
|
+
asyncResolvers,
|
|
1188
|
+
nameApi,
|
|
1189
|
+
customInstructionData
|
|
1190
|
+
} = scope;
|
|
1191
|
+
if (useAsync && !hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers)) {
|
|
1192
|
+
return fragment("");
|
|
1193
|
+
}
|
|
1194
|
+
const customData = customInstructionData.get(instructionNode.name);
|
|
1195
|
+
const hasAccounts = instructionNode.accounts.length > 0;
|
|
1196
|
+
const hasLegacyOptionalAccounts = instructionNode.optionalAccountStrategy === "omitted" && instructionNode.accounts.some((account) => account.isOptional);
|
|
1197
|
+
const instructionDependencies = getInstructionDependencies(instructionNode, asyncResolvers, useAsync);
|
|
1198
|
+
const argDependencies = instructionDependencies.filter(isNodeFilter("argumentValueNode")).map((node) => node.name);
|
|
1199
|
+
const hasData = !!customData || instructionNode.arguments.length > 0;
|
|
1200
|
+
const argIsNotOmitted = (arg) => !(arg.defaultValue && arg.defaultValueStrategy === "omitted");
|
|
1201
|
+
const argIsDependent = (arg) => argDependencies.includes(arg.name);
|
|
1202
|
+
const argHasDefaultValue = (arg) => {
|
|
1203
|
+
if (!arg.defaultValue) return false;
|
|
1204
|
+
if (useAsync) return true;
|
|
1205
|
+
return !isAsyncDefaultValue(arg.defaultValue, asyncResolvers);
|
|
1206
|
+
};
|
|
1207
|
+
const hasDataArgs = !!customData || instructionNode.arguments.filter(argIsNotOmitted).length > 0;
|
|
1208
|
+
const hasExtraArgs = (instructionNode.extraArguments ?? []).filter(
|
|
1209
|
+
(field) => argIsNotOmitted(field) && (argIsDependent(field) || argHasDefaultValue(field))
|
|
1210
|
+
).length > 0;
|
|
1211
|
+
const hasRemainingAccountArgs = (instructionNode.remainingAccounts ?? []).filter(({ value }) => isNode(value, "argumentValueNode")).length > 0;
|
|
1212
|
+
const hasAnyArgs = hasDataArgs || hasExtraArgs || hasRemainingAccountArgs;
|
|
1213
|
+
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
|
|
1214
|
+
const programAddressConstant = nameApi.programAddressConstant(programNode.name);
|
|
1215
|
+
const encoderFunction = customData ? dataArgsManifest.encoder.render : `${nameApi.encoderFunction(instructionDataName)}()`;
|
|
1216
|
+
const argsTypeFragment = fragment(
|
|
1217
|
+
customData ? dataArgsManifest.looseType.render : nameApi.dataArgsType(instructionDataName)
|
|
1218
|
+
);
|
|
1219
|
+
if (customData) {
|
|
1220
|
+
argsTypeFragment.mergeImportsWith(dataArgsManifest.looseType, dataArgsManifest.encoder);
|
|
1221
|
+
}
|
|
1222
|
+
const functionName = useAsync ? nameApi.instructionAsyncFunction(instructionNode.name) : nameApi.instructionSyncFunction(instructionNode.name);
|
|
1223
|
+
const typeParamsFragment = getTypeParams(instructionNode, programAddressConstant);
|
|
1224
|
+
const instructionTypeFragment = getInstructionType(scope);
|
|
1225
|
+
const inputTypeFragment = getInstructionInputTypeFragment(scope);
|
|
1226
|
+
const inputTypeCallFragment = getInputTypeCall(scope);
|
|
1227
|
+
const renamedArgsText = [...renamedArgs.entries()].map(([k, v]) => `${k}: input.${v}`).join(", ");
|
|
1228
|
+
const resolvedInputsFragment = getInstructionInputResolvedFragment(scope);
|
|
1229
|
+
const remainingAccountsFragment = getInstructionRemainingAccountsFragment(scope);
|
|
1230
|
+
const byteDeltaFragment = getInstructionByteDeltaFragment(scope);
|
|
1231
|
+
const resolvedFragment = mergeFragments(
|
|
1232
|
+
[resolvedInputsFragment, remainingAccountsFragment, byteDeltaFragment],
|
|
1233
|
+
(renders) => renders.join("\n\n")
|
|
1234
|
+
);
|
|
1235
|
+
const hasRemainingAccounts = remainingAccountsFragment.render !== "";
|
|
1236
|
+
const hasByteDeltas = byteDeltaFragment.render !== "";
|
|
1237
|
+
const hasResolver = resolvedFragment.hasFeatures("instruction:resolverScopeVariable");
|
|
1238
|
+
const getReturnType = (instructionType) => {
|
|
1239
|
+
let returnType = instructionType;
|
|
1240
|
+
if (hasByteDeltas) {
|
|
1241
|
+
returnType = `${returnType} & IInstructionWithByteDelta`;
|
|
1242
|
+
}
|
|
1243
|
+
return useAsync ? `Promise<${returnType}>` : returnType;
|
|
1244
|
+
};
|
|
1245
|
+
const functionFragment = fragmentFromTemplate("instructionFunction.njk", {
|
|
1246
|
+
argsTypeFragment,
|
|
1247
|
+
encoderFunction,
|
|
1248
|
+
functionName,
|
|
1249
|
+
getReturnType,
|
|
1250
|
+
hasAccounts,
|
|
1251
|
+
hasAnyArgs,
|
|
1252
|
+
hasByteDeltas,
|
|
1253
|
+
hasData,
|
|
1254
|
+
hasDataArgs,
|
|
1255
|
+
hasExtraArgs,
|
|
1256
|
+
hasLegacyOptionalAccounts,
|
|
1257
|
+
hasRemainingAccounts,
|
|
1258
|
+
hasResolver,
|
|
1259
|
+
inputTypeCallFragment,
|
|
1260
|
+
inputTypeFragment,
|
|
1261
|
+
instruction: instructionNode,
|
|
1262
|
+
instructionTypeFragment,
|
|
1263
|
+
programAddressConstant,
|
|
1264
|
+
renamedArgs: renamedArgsText,
|
|
1265
|
+
resolvedFragment,
|
|
1266
|
+
typeParamsFragment,
|
|
1267
|
+
useAsync
|
|
1268
|
+
}).mergeImportsWith(
|
|
1269
|
+
typeParamsFragment,
|
|
1270
|
+
instructionTypeFragment,
|
|
1271
|
+
inputTypeFragment,
|
|
1272
|
+
inputTypeCallFragment,
|
|
1273
|
+
resolvedFragment,
|
|
1274
|
+
argsTypeFragment
|
|
1275
|
+
).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaAddresses", ["type Address"]);
|
|
1276
|
+
if (hasAccounts) {
|
|
1277
|
+
functionFragment.addImports("solanaInstructions", ["type IAccountMeta"]).addImports("shared", ["getAccountMetaFactory", "type ResolvedAccount"]);
|
|
1278
|
+
}
|
|
1279
|
+
if (hasByteDeltas) {
|
|
1280
|
+
functionFragment.addImports("shared", ["type IInstructionWithByteDelta"]);
|
|
1281
|
+
}
|
|
1282
|
+
return functionFragment;
|
|
1283
|
+
}
|
|
1284
|
+
function getTypeParams(instructionNode, programAddressConstant) {
|
|
1285
|
+
const typeParams = instructionNode.accounts.map((account) => `TAccount${pascalCase(account.name)} extends string`);
|
|
1286
|
+
typeParams.push(`TProgramAddress extends Address = typeof ${programAddressConstant}`);
|
|
1287
|
+
return fragment(typeParams.filter((x) => !!x).join(", ")).mapRender((r) => `<${r}>`).addImports("generatedPrograms", [programAddressConstant]);
|
|
1288
|
+
}
|
|
1289
|
+
function getInstructionType(scope) {
|
|
1290
|
+
const { instructionNode, nameApi } = scope;
|
|
1291
|
+
const instructionTypeName = nameApi.instructionType(instructionNode.name);
|
|
1292
|
+
const programAddressFragment = fragment("TProgramAddress");
|
|
1293
|
+
const accountTypeParamsFragments = instructionNode.accounts.map((account) => {
|
|
1294
|
+
const typeParam = `TAccount${pascalCase(account.name)}`;
|
|
1295
|
+
const camelName = camelCase(account.name);
|
|
1296
|
+
if (account.isSigner === "either") {
|
|
1297
|
+
const signerRole = account.isWritable ? "WritableSignerAccount" : "ReadonlySignerAccount";
|
|
1298
|
+
return fragment(
|
|
1299
|
+
`typeof input["${camelName}"] extends TransactionSigner<${typeParam}> ? ${signerRole}<${typeParam}> & IAccountSignerMeta<${typeParam}> : ${typeParam}`
|
|
1300
|
+
).addImports("solanaInstructions", [`type ${signerRole}`]).addImports("solanaSigners", ["type IAccountSignerMeta"]);
|
|
1301
|
+
}
|
|
1302
|
+
return fragment(typeParam);
|
|
1303
|
+
});
|
|
1304
|
+
return mergeFragments(
|
|
1305
|
+
[programAddressFragment, ...accountTypeParamsFragments],
|
|
1306
|
+
(renders) => renders.join(", ")
|
|
1307
|
+
).mapRender((r) => `${instructionTypeName}<${r}>`);
|
|
1308
|
+
}
|
|
1309
|
+
function getInputTypeCall(scope) {
|
|
1310
|
+
const { instructionNode, useAsync, nameApi } = scope;
|
|
1311
|
+
const inputTypeName = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
|
|
1312
|
+
if (instructionNode.accounts.length === 0) return fragment(inputTypeName);
|
|
1313
|
+
const accountTypeParams = instructionNode.accounts.map((account) => `TAccount${pascalCase(account.name)}`).join(", ");
|
|
1314
|
+
return fragment(`${inputTypeName}<${accountTypeParams}>`);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// src/fragments/instructionParseFunction.ts
|
|
1318
|
+
function getInstructionParseFunctionFragment(scope) {
|
|
1319
|
+
const { instructionNode, programNode, dataArgsManifest, nameApi, customInstructionData } = scope;
|
|
1320
|
+
const customData = customInstructionData.get(instructionNode.name);
|
|
1321
|
+
const hasAccounts = instructionNode.accounts.length > 0;
|
|
1322
|
+
const hasOptionalAccounts = instructionNode.accounts.some((account) => account.isOptional);
|
|
1323
|
+
const minimumNumberOfAccounts = instructionNode.optionalAccountStrategy === "omitted" ? instructionNode.accounts.filter((account) => !account.isOptional).length : instructionNode.accounts.length;
|
|
1324
|
+
const hasData = !!customData || instructionNode.arguments.length > 0;
|
|
1325
|
+
if (!hasAccounts && !hasData) {
|
|
1326
|
+
return fragment("");
|
|
1327
|
+
}
|
|
1328
|
+
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
|
|
1329
|
+
const programAddressConstant = nameApi.programAddressConstant(programNode.name);
|
|
1330
|
+
const dataTypeFragment = fragment(
|
|
1331
|
+
customData ? dataArgsManifest.strictType.render : nameApi.dataType(instructionDataName)
|
|
1332
|
+
);
|
|
1333
|
+
const decoderFunction = customData ? dataArgsManifest.decoder.render : `${nameApi.decoderFunction(instructionDataName)}()`;
|
|
1334
|
+
if (customData) {
|
|
1335
|
+
dataTypeFragment.mergeImportsWith(dataArgsManifest.strictType, dataArgsManifest.decoder);
|
|
1336
|
+
}
|
|
1337
|
+
return fragmentFromTemplate("instructionParseFunction.njk", {
|
|
1338
|
+
dataTypeFragment,
|
|
1339
|
+
decoderFunction,
|
|
1340
|
+
hasAccounts,
|
|
1341
|
+
hasData,
|
|
1342
|
+
hasOptionalAccounts,
|
|
1343
|
+
instruction: instructionNode,
|
|
1344
|
+
instructionParseFunction: nameApi.instructionParseFunction(instructionNode.name),
|
|
1345
|
+
instructionParsedType: nameApi.instructionParsedType(instructionNode.name),
|
|
1346
|
+
minimumNumberOfAccounts,
|
|
1347
|
+
programAddressConstant
|
|
1348
|
+
}).mergeImportsWith(dataTypeFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", ["type IInstruction"]).addImports("solanaInstructions", hasAccounts ? ["type IInstructionWithAccounts", "type IAccountMeta"] : []).addImports("solanaInstructions", hasData ? ["type IInstructionWithData"] : []);
|
|
1349
|
+
}
|
|
1350
|
+
function getInstructionTypeFragment(scope) {
|
|
1351
|
+
const { instructionNode, programNode, nameApi, customInstructionData } = scope;
|
|
1352
|
+
const hasAccounts = instructionNode.accounts.length > 0;
|
|
1353
|
+
const customData = customInstructionData.get(instructionNode.name);
|
|
1354
|
+
const hasData = !!customData || instructionNode.arguments.length > 0;
|
|
1355
|
+
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
|
|
1356
|
+
const programAddressConstant = nameApi.programAddressConstant(programNode.name);
|
|
1357
|
+
const dataType = customData ? pascalCase(customData.importAs) : pascalCase(instructionDataName);
|
|
1358
|
+
const accountTypeParamsFragment = mergeFragments(
|
|
1359
|
+
instructionNode.accounts.map(
|
|
1360
|
+
(account) => getInstructionAccountTypeParamFragment({
|
|
1361
|
+
...scope,
|
|
1362
|
+
allowAccountMeta: true,
|
|
1363
|
+
instructionAccountNode: account
|
|
1364
|
+
})
|
|
1365
|
+
),
|
|
1366
|
+
(renders) => renders.join(", ")
|
|
1367
|
+
);
|
|
1368
|
+
const usesLegacyOptionalAccounts = instructionNode.optionalAccountStrategy === "omitted";
|
|
1369
|
+
const accountMetasFragment = mergeFragments(
|
|
1370
|
+
instructionNode.accounts.map(
|
|
1371
|
+
(account) => getInstructionAccountMetaFragment(account).mapRender((r) => {
|
|
1372
|
+
const typeParam = `TAccount${pascalCase(account.name)}`;
|
|
1373
|
+
const isLegacyOptional = account.isOptional && usesLegacyOptionalAccounts;
|
|
1374
|
+
const type = `${typeParam} extends string ? ${r} : ${typeParam}`;
|
|
1375
|
+
if (!isLegacyOptional) return type;
|
|
1376
|
+
return `...(${typeParam} extends undefined ? [] : [${type}])`;
|
|
1377
|
+
})
|
|
1378
|
+
),
|
|
1379
|
+
(renders) => renders.join(", ")
|
|
1380
|
+
);
|
|
1381
|
+
const fragment2 = fragmentFromTemplate("instructionType.njk", {
|
|
1382
|
+
accountMetas: accountMetasFragment.render,
|
|
1383
|
+
accountTypeParams: accountTypeParamsFragment.render,
|
|
1384
|
+
dataType,
|
|
1385
|
+
hasAccounts,
|
|
1386
|
+
hasData,
|
|
1387
|
+
instruction: instructionNode,
|
|
1388
|
+
instructionType: nameApi.instructionType(instructionNode.name),
|
|
1389
|
+
programAddressConstant
|
|
1390
|
+
}).mergeImportsWith(accountTypeParamsFragment, accountMetasFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", [
|
|
1391
|
+
"type IAccountMeta",
|
|
1392
|
+
"type IInstruction",
|
|
1393
|
+
"type IInstructionWithAccounts",
|
|
1394
|
+
...hasData ? ["type IInstructionWithData"] : []
|
|
1395
|
+
]);
|
|
1396
|
+
return fragment2;
|
|
1397
|
+
}
|
|
1398
|
+
function getPdaFunctionFragment(scope) {
|
|
1399
|
+
const { pdaNode, programNode, typeManifestVisitor, nameApi } = scope;
|
|
1400
|
+
const imports = new ImportMap();
|
|
1401
|
+
const seeds = pdaNode.seeds.map((seed) => {
|
|
1402
|
+
if (isNode(seed, "variablePdaSeedNode")) {
|
|
1403
|
+
const seedManifest2 = visit(seed.type, typeManifestVisitor);
|
|
1404
|
+
imports.mergeWith(seedManifest2.looseType, seedManifest2.encoder);
|
|
1405
|
+
return { ...seed, typeManifest: seedManifest2 };
|
|
1406
|
+
}
|
|
1407
|
+
if (isNode(seed.value, "programIdValueNode")) {
|
|
1408
|
+
imports.add("solanaAddresses", "getAddressEncoder");
|
|
1409
|
+
return seed;
|
|
1410
|
+
}
|
|
1411
|
+
const seedManifest = visit(seed.type, typeManifestVisitor);
|
|
1412
|
+
imports.mergeWith(seedManifest.encoder);
|
|
1413
|
+
const valueManifest = visit(seed.value, typeManifestVisitor).value;
|
|
1414
|
+
imports.mergeWith(valueManifest.imports);
|
|
1415
|
+
return { ...seed, typeManifest: seedManifest, valueManifest };
|
|
1416
|
+
});
|
|
1417
|
+
const hasVariableSeeds = pdaNode.seeds.filter(isNodeFilter("variablePdaSeedNode")).length > 0;
|
|
1418
|
+
return fragmentFromTemplate("pdaFunction.njk", {
|
|
1419
|
+
findPdaFunction: nameApi.pdaFindFunction(pdaNode.name),
|
|
1420
|
+
hasVariableSeeds,
|
|
1421
|
+
pdaSeedsType: nameApi.pdaSeedsType(pdaNode.name),
|
|
1422
|
+
programAddress: pdaNode.programId ?? programNode.publicKey,
|
|
1423
|
+
seeds
|
|
1424
|
+
}).mergeImportsWith(imports).addImports("solanaAddresses", ["type Address", "getProgramDerivedAddress", "type ProgramDerivedAddress"]);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// src/fragments/program.ts
|
|
1428
|
+
function getProgramFragment(scope) {
|
|
1429
|
+
const { programNode, nameApi } = scope;
|
|
1430
|
+
return fragmentFromTemplate("program.njk", {
|
|
1431
|
+
program: programNode,
|
|
1432
|
+
programAddressConstant: nameApi.programAddressConstant(programNode.name)
|
|
1433
|
+
}).addImports("solanaAddresses", ["type Address"]);
|
|
1434
|
+
}
|
|
1435
|
+
function getProgramAccountsFragment(scope) {
|
|
1436
|
+
if (scope.programNode.accounts.length === 0) return fragment("");
|
|
1437
|
+
return mergeFragments(
|
|
1438
|
+
[getProgramAccountsEnumFragment(scope), getProgramAccountsIdentifierFunctionFragment(scope)],
|
|
1439
|
+
(r) => `${r.join("\n\n")}
|
|
1440
|
+
`
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
function getProgramAccountsEnumFragment(scope) {
|
|
1444
|
+
const { programNode, nameApi } = scope;
|
|
1445
|
+
const programAccountsEnum = nameApi.programAccountsEnum(programNode.name);
|
|
1446
|
+
const programAccountsEnumVariants = programNode.accounts.map(
|
|
1447
|
+
(account) => nameApi.programAccountsEnumVariant(account.name)
|
|
1448
|
+
);
|
|
1449
|
+
return fragment(`export enum ${programAccountsEnum} { ${programAccountsEnumVariants.join(", ")} }`);
|
|
1450
|
+
}
|
|
1451
|
+
function getProgramAccountsIdentifierFunctionFragment(scope) {
|
|
1452
|
+
const { programNode, nameApi } = scope;
|
|
1453
|
+
const accountsWithDiscriminators = programNode.accounts.filter(
|
|
1454
|
+
(account) => (account.discriminators ?? []).length > 0
|
|
1455
|
+
);
|
|
1456
|
+
const hasAccountDiscriminators = accountsWithDiscriminators.length > 0;
|
|
1457
|
+
if (!hasAccountDiscriminators) return fragment("");
|
|
1458
|
+
const programAccountsEnum = nameApi.programAccountsEnum(programNode.name);
|
|
1459
|
+
const programAccountsIdentifierFunction = nameApi.programAccountsIdentifierFunction(programNode.name);
|
|
1460
|
+
const discriminatorsFragment = mergeFragments(
|
|
1461
|
+
accountsWithDiscriminators.map((account) => {
|
|
1462
|
+
const variant = nameApi.programAccountsEnumVariant(account.name);
|
|
1463
|
+
return getDiscriminatorConditionFragment({
|
|
1464
|
+
...scope,
|
|
1465
|
+
dataName: "data",
|
|
1466
|
+
discriminators: account.discriminators ?? [],
|
|
1467
|
+
ifTrue: `return ${programAccountsEnum}.${variant};`,
|
|
1468
|
+
struct: resolveNestedTypeNode(account.data)
|
|
1469
|
+
});
|
|
1470
|
+
}),
|
|
1471
|
+
(r) => r.join("\n")
|
|
1472
|
+
);
|
|
1473
|
+
return discriminatorsFragment.mapRender(
|
|
1474
|
+
(discriminators) => `export function ${programAccountsIdentifierFunction}(account: { data: ReadonlyUint8Array } | ReadonlyUint8Array): ${programAccountsEnum} {
|
|
1475
|
+
const data = 'data' in account ? account.data : account;
|
|
1476
|
+
${discriminators}
|
|
1477
|
+
throw new Error("The provided account could not be identified as a ${programNode.name} account.")
|
|
1478
|
+
}`
|
|
1479
|
+
).addImports("solanaCodecsCore", "type ReadonlyUint8Array");
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// src/fragments/programErrors.ts
|
|
1483
|
+
function getProgramErrorsFragment(scope) {
|
|
1484
|
+
const { programNode, nameApi } = scope;
|
|
1485
|
+
const programAddressConstant = nameApi.programAddressConstant(programNode.name);
|
|
1486
|
+
return fragmentFromTemplate("programErrors.njk", {
|
|
1487
|
+
errors: programNode.errors,
|
|
1488
|
+
getProgramErrorConstant: (name) => nameApi.programErrorConstantPrefix(programNode.name) + nameApi.programErrorConstant(name),
|
|
1489
|
+
programAddressConstant,
|
|
1490
|
+
programErrorMessagesMap: nameApi.programErrorMessagesMap(programNode.name),
|
|
1491
|
+
programErrorUnion: nameApi.programErrorUnion(programNode.name),
|
|
1492
|
+
programGetErrorMessageFunction: nameApi.programGetErrorMessageFunction(programNode.name),
|
|
1493
|
+
programIsErrorFunction: nameApi.programIsErrorFunction(programNode.name)
|
|
1494
|
+
}).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaPrograms", ["isProgramError"]).addImports("solanaErrors", ["type SolanaError", "type SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM"]).addImports("solanaAddresses", ["type Address"]);
|
|
1495
|
+
}
|
|
1496
|
+
function getProgramInstructionsFragment(scope) {
|
|
1497
|
+
if (scope.programNode.instructions.length === 0) return fragment("");
|
|
1498
|
+
const allInstructions = getAllInstructionsWithSubs(scope.programNode, {
|
|
1499
|
+
leavesOnly: !scope.renderParentInstructions,
|
|
1500
|
+
subInstructionsFirst: true
|
|
1501
|
+
});
|
|
1502
|
+
const scopeWithInstructions = { ...scope, allInstructions };
|
|
1503
|
+
return mergeFragments(
|
|
1504
|
+
[
|
|
1505
|
+
getProgramInstructionsEnumFragment(scopeWithInstructions),
|
|
1506
|
+
getProgramInstructionsIdentifierFunctionFragment(scopeWithInstructions),
|
|
1507
|
+
getProgramInstructionsParsedUnionTypeFragment(scopeWithInstructions)
|
|
1508
|
+
],
|
|
1509
|
+
(r) => `${r.join("\n\n")}
|
|
1510
|
+
`
|
|
1511
|
+
);
|
|
1512
|
+
}
|
|
1513
|
+
function getProgramInstructionsEnumFragment(scope) {
|
|
1514
|
+
const { programNode, allInstructions, nameApi } = scope;
|
|
1515
|
+
const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name);
|
|
1516
|
+
const programInstructionsEnumVariants = allInstructions.map(
|
|
1517
|
+
(instruction) => nameApi.programInstructionsEnumVariant(instruction.name)
|
|
1518
|
+
);
|
|
1519
|
+
return fragment(
|
|
1520
|
+
`export enum ${programInstructionsEnum} { ${programInstructionsEnumVariants.join(", ")} }`
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
function getProgramInstructionsIdentifierFunctionFragment(scope) {
|
|
1524
|
+
const { programNode, nameApi, allInstructions } = scope;
|
|
1525
|
+
const instructionsWithDiscriminators = allInstructions.filter(
|
|
1526
|
+
(instruction) => (instruction.discriminators ?? []).length > 0
|
|
1527
|
+
);
|
|
1528
|
+
const hasInstructionDiscriminators = instructionsWithDiscriminators.length > 0;
|
|
1529
|
+
if (!hasInstructionDiscriminators) return fragment("");
|
|
1530
|
+
const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name);
|
|
1531
|
+
const programInstructionsIdentifierFunction = nameApi.programInstructionsIdentifierFunction(programNode.name);
|
|
1532
|
+
const discriminatorsFragment = mergeFragments(
|
|
1533
|
+
instructionsWithDiscriminators.map((instruction) => {
|
|
1534
|
+
const variant = nameApi.programInstructionsEnumVariant(instruction.name);
|
|
1535
|
+
return getDiscriminatorConditionFragment({
|
|
1536
|
+
...scope,
|
|
1537
|
+
dataName: "data",
|
|
1538
|
+
discriminators: instruction.discriminators ?? [],
|
|
1539
|
+
ifTrue: `return ${programInstructionsEnum}.${variant};`,
|
|
1540
|
+
struct: structTypeNodeFromInstructionArgumentNodes(instruction.arguments)
|
|
1541
|
+
});
|
|
1542
|
+
}),
|
|
1543
|
+
(r) => r.join("\n")
|
|
1544
|
+
);
|
|
1545
|
+
return discriminatorsFragment.mapRender(
|
|
1546
|
+
(discriminators) => `export function ${programInstructionsIdentifierFunction}(instruction: { data: ReadonlyUint8Array } | ReadonlyUint8Array): ${programInstructionsEnum} {
|
|
1547
|
+
const data = 'data' in instruction ? instruction.data : instruction;
|
|
1548
|
+
${discriminators}
|
|
1549
|
+
throw new Error("The provided instruction could not be identified as a ${programNode.name} instruction.")
|
|
1550
|
+
}`
|
|
1551
|
+
).addImports("solanaCodecsCore", "type ReadonlyUint8Array");
|
|
1552
|
+
}
|
|
1553
|
+
function getProgramInstructionsParsedUnionTypeFragment(scope) {
|
|
1554
|
+
const { programNode, allInstructions, nameApi } = scope;
|
|
1555
|
+
const programAddress = programNode.publicKey;
|
|
1556
|
+
const programInstructionsType = nameApi.programInstructionsParsedUnionType(programNode.name);
|
|
1557
|
+
const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name);
|
|
1558
|
+
const typeVariants = allInstructions.map((instruction) => {
|
|
1559
|
+
const instructionEnumVariant = nameApi.programInstructionsEnumVariant(instruction.name);
|
|
1560
|
+
const parsedInstructionType = nameApi.instructionParsedType(instruction.name);
|
|
1561
|
+
return fragment(
|
|
1562
|
+
`| { instructionType: ${programInstructionsEnum}.${instructionEnumVariant} } & ${parsedInstructionType}<TProgram>`
|
|
1563
|
+
).addImports("generatedInstructions", `type ${parsedInstructionType}`);
|
|
1564
|
+
});
|
|
1565
|
+
return mergeFragments(
|
|
1566
|
+
[
|
|
1567
|
+
fragment(`export type ${programInstructionsType}<TProgram extends string = '${programAddress}'> =`),
|
|
1568
|
+
...typeVariants
|
|
1569
|
+
],
|
|
1570
|
+
(r) => r.join("\n")
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
function getTypeDiscriminatedUnionHelpersFragment(scope) {
|
|
1574
|
+
const { name, typeNode, nameApi } = scope;
|
|
1575
|
+
const isDiscriminatedUnion = isNode(typeNode, "enumTypeNode") && isDataEnum(typeNode);
|
|
1576
|
+
if (!isDiscriminatedUnion) {
|
|
1577
|
+
return fragment("");
|
|
1578
|
+
}
|
|
1579
|
+
return fragmentFromTemplate("typeDiscriminatedUnionHelpers.njk", {
|
|
1580
|
+
discriminatedUnionDiscriminator: nameApi.discriminatedUnionDiscriminator(name),
|
|
1581
|
+
discriminatedUnionFunction: nameApi.discriminatedUnionFunction(name),
|
|
1582
|
+
getVariant: (variant) => nameApi.discriminatedUnionVariant(variant),
|
|
1583
|
+
isDiscriminatedUnionFunction: nameApi.isDiscriminatedUnionFunction(name),
|
|
1584
|
+
looseName: nameApi.dataArgsType(name),
|
|
1585
|
+
strictName: nameApi.dataType(name),
|
|
1586
|
+
typeNode
|
|
1587
|
+
}).addImports("solanaCodecsDataStructures", [
|
|
1588
|
+
"type GetDiscriminatedUnionVariantContent",
|
|
1589
|
+
"type GetDiscriminatedUnionVariant"
|
|
1590
|
+
]);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// src/TypeManifest.ts
|
|
1594
|
+
function typeManifest() {
|
|
1595
|
+
return {
|
|
1596
|
+
decoder: fragment(""),
|
|
1597
|
+
encoder: fragment(""),
|
|
1598
|
+
isEnum: false,
|
|
1599
|
+
looseType: fragment(""),
|
|
1600
|
+
strictType: fragment(""),
|
|
1601
|
+
value: fragment("")
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
function mergeManifests(manifests, options = {}) {
|
|
1605
|
+
const { mergeTypes, mergeCodecs, mergeValues } = options;
|
|
1606
|
+
const merge = (fragmentFn, mergeFn) => mergeFn ? mergeFragments(manifests.map(fragmentFn), mergeFn) : fragment("");
|
|
1607
|
+
return {
|
|
1608
|
+
decoder: merge((m) => m.decoder, mergeCodecs),
|
|
1609
|
+
encoder: merge((m) => m.encoder, mergeCodecs),
|
|
1610
|
+
isEnum: false,
|
|
1611
|
+
looseType: merge((m) => m.looseType, mergeTypes),
|
|
1612
|
+
strictType: merge((m) => m.strictType, mergeTypes),
|
|
1613
|
+
value: merge((m) => m.value, mergeValues)
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
function getTypeManifestVisitor(input) {
|
|
1617
|
+
const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input;
|
|
1618
|
+
const stack = new NodeStack();
|
|
1619
|
+
let parentName = input.parentName ?? null;
|
|
1620
|
+
return pipe(
|
|
1621
|
+
staticVisitor(
|
|
1622
|
+
() => ({
|
|
1623
|
+
decoder: fragment(""),
|
|
1624
|
+
encoder: fragment(""),
|
|
1625
|
+
isEnum: false,
|
|
1626
|
+
looseType: fragment(""),
|
|
1627
|
+
strictType: fragment(""),
|
|
1628
|
+
value: fragment("")
|
|
1629
|
+
}),
|
|
1630
|
+
[
|
|
1631
|
+
...REGISTERED_TYPE_NODE_KINDS,
|
|
1632
|
+
...REGISTERED_VALUE_NODE_KINDS,
|
|
1633
|
+
"definedTypeLinkNode",
|
|
1634
|
+
"definedTypeNode",
|
|
1635
|
+
"accountNode",
|
|
1636
|
+
"instructionNode"
|
|
1637
|
+
]
|
|
1638
|
+
),
|
|
1639
|
+
(visitor) => extendVisitor(visitor, {
|
|
1640
|
+
visitAccount(account, { self }) {
|
|
1641
|
+
parentName = {
|
|
1642
|
+
loose: nameApi.dataArgsType(account.name),
|
|
1643
|
+
strict: nameApi.dataType(account.name)
|
|
1644
|
+
};
|
|
1645
|
+
const link = customAccountData.get(account.name)?.linkNode;
|
|
1646
|
+
const manifest = link ? visit(link, self) : visit(account.data, self);
|
|
1647
|
+
parentName = null;
|
|
1648
|
+
return manifest;
|
|
1649
|
+
},
|
|
1650
|
+
visitAmountType(amountType, { self }) {
|
|
1651
|
+
return visit(amountType.number, self);
|
|
1652
|
+
},
|
|
1653
|
+
visitArrayType(arrayType, { self }) {
|
|
1654
|
+
const childManifest = visit(arrayType.item, self);
|
|
1655
|
+
childManifest.looseType.mapRender((r) => `Array<${r}>`);
|
|
1656
|
+
childManifest.strictType.mapRender((r) => `Array<${r}>`);
|
|
1657
|
+
const sizeManifest = getArrayLikeSizeOption(arrayType.count, self);
|
|
1658
|
+
const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : "";
|
|
1659
|
+
const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : "";
|
|
1660
|
+
childManifest.encoder.mapRender((r) => `getArrayEncoder(${r + encoderOptions})`).mergeImportsWith(sizeManifest.encoder).addImports("solanaCodecsDataStructures", "getArrayEncoder");
|
|
1661
|
+
childManifest.decoder.mapRender((r) => `getArrayDecoder(${r + decoderOptions})`).mergeImportsWith(sizeManifest.decoder).addImports("solanaCodecsDataStructures", "getArrayDecoder");
|
|
1662
|
+
return childManifest;
|
|
1663
|
+
},
|
|
1664
|
+
visitArrayValue(node, { self }) {
|
|
1665
|
+
return mergeManifests(
|
|
1666
|
+
node.items.map((v) => visit(v, self)),
|
|
1667
|
+
{ mergeValues: (renders) => `[${renders.join(", ")}]` }
|
|
1668
|
+
);
|
|
1669
|
+
},
|
|
1670
|
+
visitBooleanType(booleanType, { self }) {
|
|
1671
|
+
const encoderImports = new ImportMap().add("solanaCodecsDataStructures", "getBooleanEncoder");
|
|
1672
|
+
const decoderImports = new ImportMap().add("solanaCodecsDataStructures", "getBooleanDecoder");
|
|
1673
|
+
let sizeEncoder = "";
|
|
1674
|
+
let sizeDecoder = "";
|
|
1675
|
+
const resolvedSize = resolveNestedTypeNode(booleanType.size);
|
|
1676
|
+
if (resolvedSize.format !== "u8" || resolvedSize.endian !== "le") {
|
|
1677
|
+
const size = visit(booleanType.size, self);
|
|
1678
|
+
encoderImports.mergeWith(size.encoder);
|
|
1679
|
+
decoderImports.mergeWith(size.decoder);
|
|
1680
|
+
sizeEncoder = `{ size: ${size.encoder.render} }`;
|
|
1681
|
+
sizeDecoder = `{ size: ${size.decoder.render} }`;
|
|
1682
|
+
}
|
|
1683
|
+
return {
|
|
1684
|
+
decoder: fragment(`getBooleanDecoder(${sizeDecoder})`, decoderImports),
|
|
1685
|
+
encoder: fragment(`getBooleanEncoder(${sizeEncoder})`, encoderImports),
|
|
1686
|
+
isEnum: false,
|
|
1687
|
+
looseType: fragment("boolean"),
|
|
1688
|
+
strictType: fragment("boolean"),
|
|
1689
|
+
value: fragment("")
|
|
1690
|
+
};
|
|
1691
|
+
},
|
|
1692
|
+
visitBooleanValue(node) {
|
|
1693
|
+
const manifest = typeManifest();
|
|
1694
|
+
manifest.value.setRender(JSON.stringify(node.boolean));
|
|
1695
|
+
return manifest;
|
|
1696
|
+
},
|
|
1697
|
+
visitBytesType() {
|
|
1698
|
+
return {
|
|
1699
|
+
decoder: fragment(`getBytesDecoder()`).addImports(
|
|
1700
|
+
"solanaCodecsDataStructures",
|
|
1701
|
+
"getBytesDecoder"
|
|
1702
|
+
),
|
|
1703
|
+
encoder: fragment(`getBytesEncoder()`).addImports(
|
|
1704
|
+
"solanaCodecsDataStructures",
|
|
1705
|
+
"getBytesEncoder"
|
|
1706
|
+
),
|
|
1707
|
+
isEnum: false,
|
|
1708
|
+
looseType: fragment("ReadonlyUint8Array").addImports(
|
|
1709
|
+
"solanaCodecsCore",
|
|
1710
|
+
"type ReadonlyUint8Array"
|
|
1711
|
+
),
|
|
1712
|
+
strictType: fragment("ReadonlyUint8Array").addImports(
|
|
1713
|
+
"solanaCodecsCore",
|
|
1714
|
+
"type ReadonlyUint8Array"
|
|
1715
|
+
),
|
|
1716
|
+
value: fragment("")
|
|
1717
|
+
};
|
|
1718
|
+
},
|
|
1719
|
+
visitBytesValue(node) {
|
|
1720
|
+
const manifest = typeManifest();
|
|
1721
|
+
const bytes = getBytesFromBytesValueNode(node);
|
|
1722
|
+
manifest.value.setRender(`new Uint8Array([${Array.from(bytes).join(", ")}])`);
|
|
1723
|
+
return manifest;
|
|
1724
|
+
},
|
|
1725
|
+
visitConstantValue(node, { self }) {
|
|
1726
|
+
if (isNode(node.type, "bytesTypeNode") && isNode(node.value, "bytesValueNode")) {
|
|
1727
|
+
return visit(node.value, self);
|
|
1728
|
+
}
|
|
1729
|
+
return {
|
|
1730
|
+
...typeManifest(),
|
|
1731
|
+
value: mergeFragments(
|
|
1732
|
+
[visit(node.type, self).encoder, visit(node.value, self).value],
|
|
1733
|
+
([encoderFunction, value]) => `${encoderFunction}.encode(${value})`
|
|
1734
|
+
)
|
|
1735
|
+
};
|
|
1736
|
+
},
|
|
1737
|
+
visitDateTimeType(dateTimeType, { self }) {
|
|
1738
|
+
return visit(dateTimeType.number, self);
|
|
1739
|
+
},
|
|
1740
|
+
visitDefinedType(definedType, { self }) {
|
|
1741
|
+
parentName = {
|
|
1742
|
+
loose: nameApi.dataArgsType(definedType.name),
|
|
1743
|
+
strict: nameApi.dataType(definedType.name)
|
|
1744
|
+
};
|
|
1745
|
+
const manifest = visit(definedType.type, self);
|
|
1746
|
+
parentName = null;
|
|
1747
|
+
return manifest;
|
|
1748
|
+
},
|
|
1749
|
+
visitDefinedTypeLink(node) {
|
|
1750
|
+
const strictName = nameApi.dataType(node.name);
|
|
1751
|
+
const looseName = nameApi.dataArgsType(node.name);
|
|
1752
|
+
const encoderFunction = nameApi.encoderFunction(node.name);
|
|
1753
|
+
const decoderFunction = nameApi.decoderFunction(node.name);
|
|
1754
|
+
const importFrom = getImportFrom(node);
|
|
1755
|
+
return {
|
|
1756
|
+
decoder: fragment(`${decoderFunction}()`).addImports(importFrom, decoderFunction),
|
|
1757
|
+
encoder: fragment(`${encoderFunction}()`).addImports(importFrom, encoderFunction),
|
|
1758
|
+
isEnum: false,
|
|
1759
|
+
looseType: fragment(looseName).addImports(importFrom, `type ${looseName}`),
|
|
1760
|
+
strictType: fragment(strictName).addImports(importFrom, `type ${strictName}`),
|
|
1761
|
+
value: fragment("")
|
|
1762
|
+
};
|
|
1763
|
+
},
|
|
1764
|
+
visitEnumEmptyVariantType(enumEmptyVariantType) {
|
|
1765
|
+
const discriminator = nameApi.discriminatedUnionDiscriminator(camelCase(parentName?.strict ?? ""));
|
|
1766
|
+
const name = nameApi.discriminatedUnionVariant(enumEmptyVariantType.name);
|
|
1767
|
+
const kindAttribute = `${discriminator}: "${name}"`;
|
|
1768
|
+
return {
|
|
1769
|
+
decoder: fragment(`['${name}', getUnitDecoder()]`).addImports(
|
|
1770
|
+
"solanaCodecsDataStructures",
|
|
1771
|
+
"getUnitDecoder"
|
|
1772
|
+
),
|
|
1773
|
+
encoder: fragment(`['${name}', getUnitEncoder()]`).addImports(
|
|
1774
|
+
"solanaCodecsDataStructures",
|
|
1775
|
+
"getUnitEncoder"
|
|
1776
|
+
),
|
|
1777
|
+
isEnum: false,
|
|
1778
|
+
looseType: fragment(`{ ${kindAttribute} }`),
|
|
1779
|
+
strictType: fragment(`{ ${kindAttribute} }`),
|
|
1780
|
+
value: fragment("")
|
|
1781
|
+
};
|
|
1782
|
+
},
|
|
1783
|
+
visitEnumStructVariantType(enumStructVariantType, { self }) {
|
|
1784
|
+
const currentParentName = parentName;
|
|
1785
|
+
const discriminator = nameApi.discriminatedUnionDiscriminator(
|
|
1786
|
+
camelCase(currentParentName?.strict ?? "")
|
|
1787
|
+
);
|
|
1788
|
+
const name = nameApi.discriminatedUnionVariant(enumStructVariantType.name);
|
|
1789
|
+
const kindAttribute = `${discriminator}: "${name}"`;
|
|
1790
|
+
parentName = null;
|
|
1791
|
+
const structManifest = visit(enumStructVariantType.struct, self);
|
|
1792
|
+
parentName = currentParentName;
|
|
1793
|
+
structManifest.strictType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`);
|
|
1794
|
+
structManifest.looseType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`);
|
|
1795
|
+
structManifest.encoder.mapRender((r) => `['${name}', ${r}]`);
|
|
1796
|
+
structManifest.decoder.mapRender((r) => `['${name}', ${r}]`);
|
|
1797
|
+
return structManifest;
|
|
1798
|
+
},
|
|
1799
|
+
visitEnumTupleVariantType(enumTupleVariantType, { self }) {
|
|
1800
|
+
const currentParentName = parentName;
|
|
1801
|
+
const discriminator = nameApi.discriminatedUnionDiscriminator(
|
|
1802
|
+
camelCase(currentParentName?.strict ?? "")
|
|
1803
|
+
);
|
|
1804
|
+
const name = nameApi.discriminatedUnionVariant(enumTupleVariantType.name);
|
|
1805
|
+
const kindAttribute = `${discriminator}: "${name}"`;
|
|
1806
|
+
const struct = structTypeNode([
|
|
1807
|
+
structFieldTypeNode({
|
|
1808
|
+
name: "fields",
|
|
1809
|
+
type: enumTupleVariantType.tuple
|
|
1810
|
+
})
|
|
1811
|
+
]);
|
|
1812
|
+
parentName = null;
|
|
1813
|
+
const structManifest = visit(struct, self);
|
|
1814
|
+
parentName = currentParentName;
|
|
1815
|
+
structManifest.strictType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`);
|
|
1816
|
+
structManifest.looseType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`);
|
|
1817
|
+
structManifest.encoder.mapRender((r) => `['${name}', ${r}]`);
|
|
1818
|
+
structManifest.decoder.mapRender((r) => `['${name}', ${r}]`);
|
|
1819
|
+
return structManifest;
|
|
1820
|
+
},
|
|
1821
|
+
visitEnumType(enumType, { self }) {
|
|
1822
|
+
const currentParentName = parentName;
|
|
1823
|
+
const encoderImports = new ImportMap();
|
|
1824
|
+
const decoderImports = new ImportMap();
|
|
1825
|
+
const encoderOptions = [];
|
|
1826
|
+
const decoderOptions = [];
|
|
1827
|
+
const enumSize = resolveNestedTypeNode(enumType.size);
|
|
1828
|
+
if (enumSize.format !== "u8" || enumSize.endian !== "le") {
|
|
1829
|
+
const sizeManifest = visit(enumType.size, self);
|
|
1830
|
+
encoderImports.mergeWith(sizeManifest.encoder);
|
|
1831
|
+
decoderImports.mergeWith(sizeManifest.decoder);
|
|
1832
|
+
encoderOptions.push(`size: ${sizeManifest.encoder.render}`);
|
|
1833
|
+
decoderOptions.push(`size: ${sizeManifest.decoder.render}`);
|
|
1834
|
+
}
|
|
1835
|
+
const discriminator = nameApi.discriminatedUnionDiscriminator(
|
|
1836
|
+
camelCase(currentParentName?.strict ?? "")
|
|
1837
|
+
);
|
|
1838
|
+
if (!isScalarEnum(enumType) && discriminator !== "__kind") {
|
|
1839
|
+
encoderOptions.push(`discriminator: '${discriminator}'`);
|
|
1840
|
+
decoderOptions.push(`discriminator: '${discriminator}'`);
|
|
1841
|
+
}
|
|
1842
|
+
const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : "";
|
|
1843
|
+
const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : "";
|
|
1844
|
+
if (isScalarEnum(enumType)) {
|
|
1845
|
+
if (currentParentName === null) {
|
|
1846
|
+
throw new Error(
|
|
1847
|
+
"Scalar enums cannot be inlined and must be introduced via a defined type. Ensure you are not inlining a defined type that is a scalar enum through a visitor."
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
const variantNames = enumType.variants.map(({ name }) => nameApi.enumVariant(name));
|
|
1851
|
+
return {
|
|
1852
|
+
decoder: fragment(
|
|
1853
|
+
`getEnumDecoder(${currentParentName.strict + decoderOptionsAsString})`,
|
|
1854
|
+
decoderImports.add("solanaCodecsDataStructures", "getEnumDecoder")
|
|
1855
|
+
),
|
|
1856
|
+
encoder: fragment(
|
|
1857
|
+
`getEnumEncoder(${currentParentName.strict + encoderOptionsAsString})`,
|
|
1858
|
+
encoderImports.add("solanaCodecsDataStructures", "getEnumEncoder")
|
|
1859
|
+
),
|
|
1860
|
+
isEnum: true,
|
|
1861
|
+
looseType: fragment(`{ ${variantNames.join(", ")} }`),
|
|
1862
|
+
strictType: fragment(`{ ${variantNames.join(", ")} }`),
|
|
1863
|
+
value: fragment("")
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
const mergedManifest = mergeManifests(
|
|
1867
|
+
enumType.variants.map((variant) => visit(variant, self)),
|
|
1868
|
+
{
|
|
1869
|
+
mergeCodecs: (renders) => renders.join(", "),
|
|
1870
|
+
mergeTypes: (renders) => renders.join(" | ")
|
|
1871
|
+
}
|
|
1872
|
+
);
|
|
1873
|
+
mergedManifest.encoder.mapRender((r) => `getDiscriminatedUnionEncoder([${r}]${encoderOptionsAsString})`).mergeImportsWith(encoderImports).addImports("solanaCodecsDataStructures", ["getDiscriminatedUnionEncoder"]);
|
|
1874
|
+
mergedManifest.decoder.mapRender((r) => `getDiscriminatedUnionDecoder([${r}]${decoderOptionsAsString})`).mergeImportsWith(decoderImports).addImports("solanaCodecsDataStructures", ["getDiscriminatedUnionDecoder"]);
|
|
1875
|
+
return mergedManifest;
|
|
1876
|
+
},
|
|
1877
|
+
visitEnumValue(node, { self }) {
|
|
1878
|
+
const manifest = typeManifest();
|
|
1879
|
+
const enumName = nameApi.dataType(node.enum.name);
|
|
1880
|
+
const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name);
|
|
1881
|
+
const importFrom = getImportFrom(node.enum);
|
|
1882
|
+
const enumNode = linkables.get(node.enum)?.type;
|
|
1883
|
+
const isScalar = enumNode && isNode(enumNode, "enumTypeNode") ? isScalarEnum(enumNode) : !nonScalarEnums.includes(node.enum.name);
|
|
1884
|
+
if (!node.value && isScalar) {
|
|
1885
|
+
const variantName2 = nameApi.enumVariant(node.variant);
|
|
1886
|
+
manifest.value.setRender(`${enumName}.${variantName2}`).addImports(importFrom, enumName);
|
|
1887
|
+
return manifest;
|
|
1888
|
+
}
|
|
1889
|
+
const variantName = nameApi.discriminatedUnionVariant(node.variant);
|
|
1890
|
+
if (!node.value) {
|
|
1891
|
+
manifest.value.setRender(`${enumFunction}('${variantName}')`).addImports(importFrom, enumFunction);
|
|
1892
|
+
return manifest;
|
|
1893
|
+
}
|
|
1894
|
+
manifest.value = visit(node.value, self).value.mapRender((r) => `${enumFunction}('${variantName}', ${r})`).addImports(importFrom, enumFunction);
|
|
1895
|
+
return manifest;
|
|
1896
|
+
},
|
|
1897
|
+
visitFixedSizeType(node, { self }) {
|
|
1898
|
+
const manifest = visit(node.type, self);
|
|
1899
|
+
manifest.encoder.mapRender((r) => `fixEncoderSize(${r}, ${node.size})`).addImports("solanaCodecsCore", "fixEncoderSize");
|
|
1900
|
+
manifest.decoder.mapRender((r) => `fixDecoderSize(${r}, ${node.size})`).addImports("solanaCodecsCore", "fixDecoderSize");
|
|
1901
|
+
return manifest;
|
|
1902
|
+
},
|
|
1903
|
+
visitHiddenPrefixType(node, { self }) {
|
|
1904
|
+
const manifest = visit(node.type, self);
|
|
1905
|
+
const prefixes = node.prefix.map((c) => visit(c, self).value);
|
|
1906
|
+
const prefixEncoders = fragment(prefixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...prefixes);
|
|
1907
|
+
const prefixDecoders = fragment(prefixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...prefixes);
|
|
1908
|
+
manifest.encoder.mapRender((r) => `getHiddenPrefixEncoder(${r}, [${prefixEncoders}])`).mergeImportsWith(prefixEncoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixEncoder");
|
|
1909
|
+
manifest.decoder.mapRender((r) => `getHiddenPrefixDecoder(${r}, [${prefixDecoders}])`).mergeImportsWith(prefixDecoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixDecoder");
|
|
1910
|
+
return manifest;
|
|
1911
|
+
},
|
|
1912
|
+
visitHiddenSuffixType(node, { self }) {
|
|
1913
|
+
const manifest = visit(node.type, self);
|
|
1914
|
+
const suffixes = node.suffix.map((c) => visit(c, self).value);
|
|
1915
|
+
const suffixEncoders = fragment(suffixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...suffixes);
|
|
1916
|
+
const suffixDecoders = fragment(suffixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...suffixes);
|
|
1917
|
+
manifest.encoder.mapRender((r) => `getHiddenSuffixEncoder(${r}, [${suffixEncoders}])`).mergeImportsWith(suffixEncoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixEncoder");
|
|
1918
|
+
manifest.decoder.mapRender((r) => `getHiddenSuffixDecoder(${r}, [${suffixDecoders}])`).mergeImportsWith(suffixDecoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixDecoder");
|
|
1919
|
+
return manifest;
|
|
1920
|
+
},
|
|
1921
|
+
visitInstruction(instruction, { self }) {
|
|
1922
|
+
const instructionDataName = nameApi.instructionDataType(instruction.name);
|
|
1923
|
+
parentName = {
|
|
1924
|
+
loose: nameApi.dataArgsType(instructionDataName),
|
|
1925
|
+
strict: nameApi.dataType(instructionDataName)
|
|
1926
|
+
};
|
|
1927
|
+
const link = customInstructionData.get(instruction.name)?.linkNode;
|
|
1928
|
+
const struct = structTypeNodeFromInstructionArgumentNodes(instruction.arguments);
|
|
1929
|
+
const manifest = link ? visit(link, self) : visit(struct, self);
|
|
1930
|
+
parentName = null;
|
|
1931
|
+
return manifest;
|
|
1932
|
+
},
|
|
1933
|
+
visitMapEntryValue(node, { self }) {
|
|
1934
|
+
return mergeManifests([visit(node.key, self), visit(node.value, self)], {
|
|
1935
|
+
mergeValues: (renders) => `[${renders.join(", ")}]`
|
|
1936
|
+
});
|
|
1937
|
+
},
|
|
1938
|
+
visitMapType(mapType, { self }) {
|
|
1939
|
+
const key = visit(mapType.key, self);
|
|
1940
|
+
const value = visit(mapType.value, self);
|
|
1941
|
+
const mergedManifest = mergeManifests([key, value], {
|
|
1942
|
+
mergeCodecs: ([k, v]) => `${k}, ${v}`,
|
|
1943
|
+
mergeTypes: ([k, v]) => `Map<${k}, ${v}>`
|
|
1944
|
+
});
|
|
1945
|
+
const sizeManifest = getArrayLikeSizeOption(mapType.count, self);
|
|
1946
|
+
const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : "";
|
|
1947
|
+
const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : "";
|
|
1948
|
+
mergedManifest.encoder.mapRender((r) => `getMapEncoder(${r}${encoderOptions})`).addImports("solanaCodecsDataStructures", "getMapEncoder");
|
|
1949
|
+
mergedManifest.decoder.mapRender((r) => `getMapDecoder(${r}${decoderOptions})`).addImports("solanaCodecsDataStructures", "getMapDecoder");
|
|
1950
|
+
return mergedManifest;
|
|
1951
|
+
},
|
|
1952
|
+
visitMapValue(node, { self }) {
|
|
1953
|
+
const entryFragments = node.entries.map((entry) => visit(entry, self));
|
|
1954
|
+
return mergeManifests(entryFragments, {
|
|
1955
|
+
mergeValues: (renders) => `new Map([${renders.join(", ")}])`
|
|
1956
|
+
});
|
|
1957
|
+
},
|
|
1958
|
+
visitNoneValue() {
|
|
1959
|
+
const manifest = typeManifest();
|
|
1960
|
+
manifest.value.setRender("none()").addImports("solanaOptions", "none");
|
|
1961
|
+
return manifest;
|
|
1962
|
+
},
|
|
1963
|
+
visitNumberType(numberType) {
|
|
1964
|
+
const encoderFunction = nameApi.encoderFunction(numberType.format);
|
|
1965
|
+
const decoderFunction = nameApi.decoderFunction(numberType.format);
|
|
1966
|
+
const isBigNumber = ["u64", "u128", "i64", "i128"].includes(numberType.format);
|
|
1967
|
+
const encoderImports = new ImportMap().add("solanaCodecsNumbers", encoderFunction);
|
|
1968
|
+
const decoderImports = new ImportMap().add("solanaCodecsNumbers", decoderFunction);
|
|
1969
|
+
let endianness = "";
|
|
1970
|
+
if (numberType.endian === "be") {
|
|
1971
|
+
encoderImports.add("solanaCodecsNumbers", "Endian");
|
|
1972
|
+
decoderImports.add("solanaCodecsNumbers", "Endian");
|
|
1973
|
+
endianness = "{ endian: Endian.Big }";
|
|
1974
|
+
}
|
|
1975
|
+
return {
|
|
1976
|
+
decoder: fragment(`${decoderFunction}(${endianness})`, decoderImports),
|
|
1977
|
+
encoder: fragment(`${encoderFunction}(${endianness})`, encoderImports),
|
|
1978
|
+
isEnum: false,
|
|
1979
|
+
looseType: fragment(isBigNumber ? "number | bigint" : "number"),
|
|
1980
|
+
strictType: fragment(isBigNumber ? "bigint" : "number"),
|
|
1981
|
+
value: fragment("")
|
|
1982
|
+
};
|
|
1983
|
+
},
|
|
1984
|
+
visitNumberValue(node) {
|
|
1985
|
+
const manifest = typeManifest();
|
|
1986
|
+
manifest.value.setRender(JSON.stringify(node.number));
|
|
1987
|
+
return manifest;
|
|
1988
|
+
},
|
|
1989
|
+
visitOptionType(optionType, { self }) {
|
|
1990
|
+
const childManifest = visit(optionType.item, self);
|
|
1991
|
+
childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option");
|
|
1992
|
+
childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable");
|
|
1993
|
+
const encoderOptions = [];
|
|
1994
|
+
const decoderOptions = [];
|
|
1995
|
+
const optionPrefix = resolveNestedTypeNode(optionType.prefix);
|
|
1996
|
+
if (optionPrefix.format !== "u8" || optionPrefix.endian !== "le") {
|
|
1997
|
+
const prefixManifest = visit(optionType.prefix, self);
|
|
1998
|
+
childManifest.encoder.mergeImportsWith(prefixManifest.encoder);
|
|
1999
|
+
childManifest.decoder.mergeImportsWith(prefixManifest.decoder);
|
|
2000
|
+
encoderOptions.push(`prefix: ${prefixManifest.encoder.render}`);
|
|
2001
|
+
decoderOptions.push(`prefix: ${prefixManifest.decoder.render}`);
|
|
2002
|
+
}
|
|
2003
|
+
if (optionType.fixed) {
|
|
2004
|
+
encoderOptions.push(`noneValue: "zeroes"`);
|
|
2005
|
+
decoderOptions.push(`noneValue: "zeroes"`);
|
|
2006
|
+
}
|
|
2007
|
+
const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : "";
|
|
2008
|
+
const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : "";
|
|
2009
|
+
childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder");
|
|
2010
|
+
childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder");
|
|
2011
|
+
return childManifest;
|
|
2012
|
+
},
|
|
2013
|
+
visitPostOffsetType(node, { self }) {
|
|
2014
|
+
const manifest = visit(node.type, self);
|
|
2015
|
+
if (node.strategy === "padded") {
|
|
2016
|
+
manifest.encoder.mapRender((r) => `padRightEncoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padRightEncoder");
|
|
2017
|
+
manifest.decoder.mapRender((r) => `padRightDecoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padRightDecoder");
|
|
2018
|
+
return manifest;
|
|
2019
|
+
}
|
|
2020
|
+
const fn = (() => {
|
|
2021
|
+
switch (node.strategy) {
|
|
2022
|
+
case "absolute":
|
|
2023
|
+
return node.offset < 0 ? `({ wrapBytes }) => wrapBytes(${node.offset})` : `() => ${node.offset}`;
|
|
2024
|
+
case "preOffset":
|
|
2025
|
+
return node.offset < 0 ? `({ preOffset }) => preOffset ${node.offset}` : `({ preOffset }) => preOffset + ${node.offset}`;
|
|
2026
|
+
case "relative":
|
|
2027
|
+
default:
|
|
2028
|
+
return node.offset < 0 ? `({ postOffset }) => postOffset ${node.offset}` : `({ postOffset }) => postOffset + ${node.offset}`;
|
|
2029
|
+
}
|
|
2030
|
+
})();
|
|
2031
|
+
manifest.encoder.mapRender((r) => `offsetEncoder(${r}, { postOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetEncoder");
|
|
2032
|
+
manifest.decoder.mapRender((r) => `offsetDecoder(${r}, { postOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetDecoder");
|
|
2033
|
+
return manifest;
|
|
2034
|
+
},
|
|
2035
|
+
visitPreOffsetType(node, { self }) {
|
|
2036
|
+
const manifest = visit(node.type, self);
|
|
2037
|
+
if (node.strategy === "padded") {
|
|
2038
|
+
manifest.encoder.mapRender((r) => `padLeftEncoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padLeftEncoder");
|
|
2039
|
+
manifest.decoder.mapRender((r) => `padLeftDecoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padLeftDecoder");
|
|
2040
|
+
return manifest;
|
|
2041
|
+
}
|
|
2042
|
+
const fn = (() => {
|
|
2043
|
+
switch (node.strategy) {
|
|
2044
|
+
case "absolute":
|
|
2045
|
+
return node.offset < 0 ? `({ wrapBytes }) => wrapBytes(${node.offset})` : `() => ${node.offset}`;
|
|
2046
|
+
case "relative":
|
|
2047
|
+
default:
|
|
2048
|
+
return node.offset < 0 ? `({ preOffset }) => preOffset ${node.offset}` : `({ preOffset }) => preOffset + ${node.offset}`;
|
|
2049
|
+
}
|
|
2050
|
+
})();
|
|
2051
|
+
manifest.encoder.mapRender((r) => `offsetEncoder(${r}, { preOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetEncoder");
|
|
2052
|
+
manifest.decoder.mapRender((r) => `offsetDecoder(${r}, { preOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetDecoder");
|
|
2053
|
+
return manifest;
|
|
2054
|
+
},
|
|
2055
|
+
visitPublicKeyType() {
|
|
2056
|
+
const imports = new ImportMap().add("solanaAddresses", "type Address");
|
|
2057
|
+
return {
|
|
2058
|
+
decoder: fragment("getAddressDecoder()").addImports("solanaAddresses", "getAddressDecoder"),
|
|
2059
|
+
encoder: fragment("getAddressEncoder()").addImports("solanaAddresses", "getAddressEncoder"),
|
|
2060
|
+
isEnum: false,
|
|
2061
|
+
looseType: fragment("Address", imports),
|
|
2062
|
+
strictType: fragment("Address", imports),
|
|
2063
|
+
value: fragment("")
|
|
2064
|
+
};
|
|
2065
|
+
},
|
|
2066
|
+
visitPublicKeyValue(node) {
|
|
2067
|
+
const manifest = typeManifest();
|
|
2068
|
+
manifest.value.setRender(`address("${node.publicKey}")`).addImports("solanaAddresses", "address");
|
|
2069
|
+
return manifest;
|
|
2070
|
+
},
|
|
2071
|
+
visitRemainderOptionType(node, { self }) {
|
|
2072
|
+
const childManifest = visit(node.item, self);
|
|
2073
|
+
childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option");
|
|
2074
|
+
childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable");
|
|
2075
|
+
const encoderOptions = ["prefix: null"];
|
|
2076
|
+
const decoderOptions = ["prefix: null"];
|
|
2077
|
+
const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : "";
|
|
2078
|
+
const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : "";
|
|
2079
|
+
childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder");
|
|
2080
|
+
childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder");
|
|
2081
|
+
return childManifest;
|
|
2082
|
+
},
|
|
2083
|
+
visitSentinelType(node, { self }) {
|
|
2084
|
+
const manifest = visit(node.type, self);
|
|
2085
|
+
const sentinel = visit(node.sentinel, self).value;
|
|
2086
|
+
manifest.encoder.mapRender((r) => `addEncoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addEncoderSentinel");
|
|
2087
|
+
manifest.decoder.mapRender((r) => `addDecoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addDecoderSentinel");
|
|
2088
|
+
return manifest;
|
|
2089
|
+
},
|
|
2090
|
+
visitSetType(setType, { self }) {
|
|
2091
|
+
const childManifest = visit(setType.item, self);
|
|
2092
|
+
childManifest.strictType.mapRender((r) => `Set<${r}>`);
|
|
2093
|
+
childManifest.looseType.mapRender((r) => `Set<${r}>`);
|
|
2094
|
+
const sizeManifest = getArrayLikeSizeOption(setType.count, self);
|
|
2095
|
+
const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : "";
|
|
2096
|
+
const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : "";
|
|
2097
|
+
childManifest.encoder.mergeImportsWith(sizeManifest.encoder).mapRender((r) => `getSetEncoder(${r + encoderOptions})`).addImports("solanaCodecsDataStructures", "getSetEncoder");
|
|
2098
|
+
childManifest.decoder.mergeImportsWith(sizeManifest.decoder).mapRender((r) => `getSetDecoder(${r + decoderOptions})`).addImports("solanaCodecsDataStructures", "getSetDecoder");
|
|
2099
|
+
return childManifest;
|
|
2100
|
+
},
|
|
2101
|
+
visitSetValue(node, { self }) {
|
|
2102
|
+
return mergeManifests(
|
|
2103
|
+
node.items.map((v) => visit(v, self)),
|
|
2104
|
+
{ mergeValues: (renders) => `new Set([${renders.join(", ")}])` }
|
|
2105
|
+
);
|
|
2106
|
+
},
|
|
2107
|
+
visitSizePrefixType(node, { self }) {
|
|
2108
|
+
const manifest = visit(node.type, self);
|
|
2109
|
+
const prefix = visit(node.prefix, self);
|
|
2110
|
+
manifest.encoder.mapRender((r) => `addEncoderSizePrefix(${r}, ${prefix.encoder})`).mergeImportsWith(prefix.encoder).addImports("solanaCodecsCore", "addEncoderSizePrefix");
|
|
2111
|
+
manifest.decoder.mapRender((r) => `addDecoderSizePrefix(${r}, ${prefix.decoder})`).mergeImportsWith(prefix.decoder).addImports("solanaCodecsCore", "addDecoderSizePrefix");
|
|
2112
|
+
return manifest;
|
|
2113
|
+
},
|
|
2114
|
+
visitSolAmountType({ number }, { self }) {
|
|
2115
|
+
const numberManifest = visit(number, self);
|
|
2116
|
+
const lamportsType = "LamportsUnsafeBeyond2Pow53Minus1";
|
|
2117
|
+
const lamportsImport = new ImportMap().add(
|
|
2118
|
+
"solanaRpcTypes",
|
|
2119
|
+
"type LamportsUnsafeBeyond2Pow53Minus1"
|
|
2120
|
+
);
|
|
2121
|
+
return {
|
|
2122
|
+
...numberManifest,
|
|
2123
|
+
decoder: numberManifest.decoder.mapRender((r) => `getLamportsDecoder(${r})`).addImports("solanaRpcTypes", "getLamportsDecoder"),
|
|
2124
|
+
encoder: numberManifest.encoder.mapRender((r) => `getLamportsEncoder(${r})`).addImports("solanaRpcTypes", "getLamportsEncoder"),
|
|
2125
|
+
looseType: fragment(lamportsType, lamportsImport),
|
|
2126
|
+
strictType: fragment(lamportsType, lamportsImport)
|
|
2127
|
+
};
|
|
2128
|
+
},
|
|
2129
|
+
visitSomeValue(node, { self }) {
|
|
2130
|
+
const manifest = typeManifest();
|
|
2131
|
+
manifest.value = visit(node.value, self).value.mapRender((r) => `some(${r})`).addImports("solanaOptions", "some");
|
|
2132
|
+
return manifest;
|
|
2133
|
+
},
|
|
2134
|
+
visitStringType(stringType) {
|
|
2135
|
+
const [encoder, decoder] = (() => {
|
|
2136
|
+
switch (stringType.encoding) {
|
|
2137
|
+
case "base16":
|
|
2138
|
+
return ["getBase16Encoder", "getBase16Decoder"];
|
|
2139
|
+
case "base58":
|
|
2140
|
+
return ["getBase58Encoder", "getBase58Decoder"];
|
|
2141
|
+
case "base64":
|
|
2142
|
+
return ["getBase64Encoder", "getBase64Decoder"];
|
|
2143
|
+
case "utf8":
|
|
2144
|
+
return ["getUtf8Encoder", "getUtf8Decoder"];
|
|
2145
|
+
default:
|
|
2146
|
+
throw new Error(`Unsupported string encoding: ${stringType.encoding}`);
|
|
2147
|
+
}
|
|
2148
|
+
})();
|
|
2149
|
+
return {
|
|
2150
|
+
decoder: fragment(`${decoder}()`).addImports("solanaCodecsStrings", decoder),
|
|
2151
|
+
encoder: fragment(`${encoder}()`).addImports("solanaCodecsStrings", encoder),
|
|
2152
|
+
isEnum: false,
|
|
2153
|
+
looseType: fragment("string"),
|
|
2154
|
+
strictType: fragment("string"),
|
|
2155
|
+
value: fragment("")
|
|
2156
|
+
};
|
|
2157
|
+
},
|
|
2158
|
+
visitStringValue(node) {
|
|
2159
|
+
const manifest = typeManifest();
|
|
2160
|
+
manifest.value.setRender(JSON.stringify(node.string));
|
|
2161
|
+
return manifest;
|
|
2162
|
+
},
|
|
2163
|
+
visitStructFieldType(structFieldType, { self }) {
|
|
2164
|
+
const name = camelCase(structFieldType.name);
|
|
2165
|
+
const childManifest = visit(structFieldType.type, self);
|
|
2166
|
+
const docblock = structFieldType.docs.length > 0 ? `
|
|
2167
|
+
${jsDocblock(structFieldType.docs)}` : "";
|
|
2168
|
+
const originalLooseType = childManifest.looseType.render;
|
|
2169
|
+
childManifest.strictType.mapRender((r) => `${docblock}${name}: ${r}; `);
|
|
2170
|
+
childManifest.looseType.mapRender((r) => `${docblock}${name}: ${r}; `);
|
|
2171
|
+
childManifest.encoder.mapRender((r) => `['${name}', ${r}]`);
|
|
2172
|
+
childManifest.decoder.mapRender((r) => `['${name}', ${r}]`);
|
|
2173
|
+
if (!structFieldType.defaultValue) {
|
|
2174
|
+
return childManifest;
|
|
2175
|
+
}
|
|
2176
|
+
if (structFieldType.defaultValueStrategy !== "omitted") {
|
|
2177
|
+
childManifest.looseType.setRender(`${docblock}${name}?: ${originalLooseType}; `);
|
|
2178
|
+
return childManifest;
|
|
2179
|
+
}
|
|
2180
|
+
childManifest.looseType = fragment("");
|
|
2181
|
+
return childManifest;
|
|
2182
|
+
},
|
|
2183
|
+
visitStructFieldValue(node, { self }) {
|
|
2184
|
+
const manifest = typeManifest();
|
|
2185
|
+
manifest.value = visit(node.value, self).value.mapRender((r) => `${node.name}: ${r}`);
|
|
2186
|
+
return manifest;
|
|
2187
|
+
},
|
|
2188
|
+
visitStructType(structType, { self }) {
|
|
2189
|
+
const optionalFields = structType.fields.filter((f) => !!f.defaultValue);
|
|
2190
|
+
const mergedManifest = mergeManifests(
|
|
2191
|
+
structType.fields.map((field) => visit(field, self)),
|
|
2192
|
+
{
|
|
2193
|
+
mergeCodecs: (renders) => `([${renders.join(", ")}])`,
|
|
2194
|
+
mergeTypes: (renders) => `{ ${renders.join("")} }`
|
|
2195
|
+
}
|
|
2196
|
+
);
|
|
2197
|
+
mergedManifest.encoder.mapRender((r) => `getStructEncoder${r}`).addImports("solanaCodecsDataStructures", "getStructEncoder");
|
|
2198
|
+
mergedManifest.decoder.mapRender((r) => `getStructDecoder${r}`).addImports("solanaCodecsDataStructures", "getStructDecoder");
|
|
2199
|
+
if (optionalFields.length === 0) {
|
|
2200
|
+
return mergedManifest;
|
|
2201
|
+
}
|
|
2202
|
+
const instructionNode = stack.find("instructionNode");
|
|
2203
|
+
const accountNode = stack.find("accountNode");
|
|
2204
|
+
const discriminatorPrefix = instructionNode ? instructionNode.name : accountNode?.name;
|
|
2205
|
+
const discriminators = (instructionNode ? instructionNode.discriminators : accountNode?.discriminators) ?? [];
|
|
2206
|
+
const fieldDiscriminators = discriminators.filter(isNodeFilter("fieldDiscriminatorNode"));
|
|
2207
|
+
const defaultValues = optionalFields.map((f) => {
|
|
2208
|
+
const key = camelCase(f.name);
|
|
2209
|
+
if (fieldDiscriminators.some((d) => d.name === f.name)) {
|
|
2210
|
+
const constantName = nameApi.constant(camelCase(`${discriminatorPrefix}_${f.name}`));
|
|
2211
|
+
return f.defaultValueStrategy === "omitted" ? `${key}: ${constantName}` : `${key}: value.${key} ?? ${constantName}`;
|
|
2212
|
+
}
|
|
2213
|
+
const defaultValue = f.defaultValue;
|
|
2214
|
+
const { render: renderedValue, imports } = visit(defaultValue, self).value;
|
|
2215
|
+
mergedManifest.encoder.mergeImportsWith(imports);
|
|
2216
|
+
return f.defaultValueStrategy === "omitted" ? `${key}: ${renderedValue}` : `${key}: value.${key} ?? ${renderedValue}`;
|
|
2217
|
+
}).join(", ");
|
|
2218
|
+
mergedManifest.encoder.mapRender((r) => `transformEncoder(${r}, (value) => ({ ...value, ${defaultValues} }))`).addImports("solanaCodecsCore", "transformEncoder");
|
|
2219
|
+
return mergedManifest;
|
|
2220
|
+
},
|
|
2221
|
+
visitStructValue(node, { self }) {
|
|
2222
|
+
return mergeManifests(
|
|
2223
|
+
node.fields.map((field) => visit(field, self)),
|
|
2224
|
+
{ mergeValues: (renders) => `{ ${renders.join(", ")} }` }
|
|
2225
|
+
);
|
|
2226
|
+
},
|
|
2227
|
+
visitTupleType(tupleType, { self }) {
|
|
2228
|
+
const items = tupleType.items.map((item) => visit(item, self));
|
|
2229
|
+
const mergedManifest = mergeManifests(items, {
|
|
2230
|
+
mergeCodecs: (codecs) => `[${codecs.join(", ")}]`,
|
|
2231
|
+
mergeTypes: (types) => `readonly [${types.join(", ")}]`
|
|
2232
|
+
});
|
|
2233
|
+
mergedManifest.encoder.mapRender((render2) => `getTupleEncoder(${render2})`).addImports("solanaCodecsDataStructures", "getTupleEncoder");
|
|
2234
|
+
mergedManifest.decoder.mapRender((render2) => `getTupleDecoder(${render2})`).addImports("solanaCodecsDataStructures", "getTupleDecoder");
|
|
2235
|
+
return mergedManifest;
|
|
2236
|
+
},
|
|
2237
|
+
visitTupleValue(node, { self }) {
|
|
2238
|
+
return mergeManifests(
|
|
2239
|
+
node.items.map((v) => visit(v, self)),
|
|
2240
|
+
{ mergeValues: (renders) => `[${renders.join(", ")}]` }
|
|
2241
|
+
);
|
|
2242
|
+
},
|
|
2243
|
+
visitZeroableOptionType(node, { self }) {
|
|
2244
|
+
const childManifest = visit(node.item, self);
|
|
2245
|
+
childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option");
|
|
2246
|
+
childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable");
|
|
2247
|
+
const encoderOptions = ["prefix: null"];
|
|
2248
|
+
const decoderOptions = ["prefix: null"];
|
|
2249
|
+
if (node.zeroValue) {
|
|
2250
|
+
const zeroValueManifest = visit(node.zeroValue, self);
|
|
2251
|
+
childManifest.encoder.mergeImportsWith(zeroValueManifest.value);
|
|
2252
|
+
childManifest.decoder.mergeImportsWith(zeroValueManifest.value);
|
|
2253
|
+
encoderOptions.push(`noneValue: ${zeroValueManifest.value.render}`);
|
|
2254
|
+
decoderOptions.push(`noneValue: ${zeroValueManifest.value.render}`);
|
|
2255
|
+
} else {
|
|
2256
|
+
encoderOptions.push(`noneValue: "zeroes"`);
|
|
2257
|
+
decoderOptions.push(`noneValue: "zeroes"`);
|
|
2258
|
+
}
|
|
2259
|
+
const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : "";
|
|
2260
|
+
const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : "";
|
|
2261
|
+
childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder");
|
|
2262
|
+
childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder");
|
|
2263
|
+
return childManifest;
|
|
2264
|
+
}
|
|
2265
|
+
}),
|
|
2266
|
+
(visitor) => recordNodeStackVisitor(visitor, stack)
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2269
|
+
function getArrayLikeSizeOption(count, visitor) {
|
|
2270
|
+
if (isNode(count, "fixedCountNode")) {
|
|
2271
|
+
return {
|
|
2272
|
+
decoder: fragment(`size: ${count.value}`),
|
|
2273
|
+
encoder: fragment(`size: ${count.value}`)
|
|
2274
|
+
};
|
|
2275
|
+
}
|
|
2276
|
+
if (isNode(count, "remainderCountNode")) {
|
|
2277
|
+
return {
|
|
2278
|
+
decoder: fragment(`size: 'remainder'`),
|
|
2279
|
+
encoder: fragment(`size: 'remainder'`)
|
|
2280
|
+
};
|
|
2281
|
+
}
|
|
2282
|
+
const prefix = resolveNestedTypeNode(count.prefix);
|
|
2283
|
+
if (prefix.format === "u32" && prefix.endian === "le") {
|
|
2284
|
+
return { decoder: fragment(""), encoder: fragment("") };
|
|
2285
|
+
}
|
|
2286
|
+
const prefixManifest = visit(count.prefix, visitor);
|
|
2287
|
+
prefixManifest.encoder.mapRender((r) => `size: ${r}`);
|
|
2288
|
+
prefixManifest.decoder.mapRender((r) => `size: ${r}`);
|
|
2289
|
+
return prefixManifest;
|
|
2290
|
+
}
|
|
2291
|
+
function getNameApi(transformers) {
|
|
2292
|
+
const helpers = {
|
|
2293
|
+
camelCase: camelCase,
|
|
2294
|
+
capitalize,
|
|
2295
|
+
kebabCase: kebabCase,
|
|
2296
|
+
pascalCase: pascalCase,
|
|
2297
|
+
snakeCase: snakeCase,
|
|
2298
|
+
titleCase: titleCase
|
|
2299
|
+
};
|
|
2300
|
+
return Object.fromEntries(
|
|
2301
|
+
Object.entries(transformers).map(([key, transformer]) => [key, (name) => transformer(name, helpers)])
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
var DEFAULT_NAME_TRANSFORMERS = {
|
|
2305
|
+
accountDecodeFunction: (name) => `decode${pascalCase(name)}`,
|
|
2306
|
+
accountFetchAllFunction: (name) => `fetchAll${pascalCase(name)}`,
|
|
2307
|
+
accountFetchAllMaybeFunction: (name) => `fetchAllMaybe${pascalCase(name)}`,
|
|
2308
|
+
accountFetchFromSeedsFunction: (name) => `fetch${pascalCase(name)}FromSeeds`,
|
|
2309
|
+
accountFetchFunction: (name) => `fetch${pascalCase(name)}`,
|
|
2310
|
+
accountFetchMaybeFromSeedsFunction: (name) => `fetchMaybe${pascalCase(name)}FromSeeds`,
|
|
2311
|
+
accountFetchMaybeFunction: (name) => `fetchMaybe${pascalCase(name)}`,
|
|
2312
|
+
accountGetSizeFunction: (name) => `get${pascalCase(name)}Size`,
|
|
2313
|
+
codecFunction: (name) => `get${pascalCase(name)}Codec`,
|
|
2314
|
+
constant: (name) => snakeCase(name).toUpperCase(),
|
|
2315
|
+
constantFunction: (name) => `get${pascalCase(name)}Bytes`,
|
|
2316
|
+
dataArgsType: (name) => `${pascalCase(name)}Args`,
|
|
2317
|
+
dataType: (name) => `${pascalCase(name)}`,
|
|
2318
|
+
decoderFunction: (name) => `get${pascalCase(name)}Decoder`,
|
|
2319
|
+
discriminatedUnionDiscriminator: () => "__kind",
|
|
2320
|
+
discriminatedUnionFunction: (name) => `${camelCase(name)}`,
|
|
2321
|
+
discriminatedUnionVariant: (name) => `${pascalCase(name)}`,
|
|
2322
|
+
encoderFunction: (name) => `get${pascalCase(name)}Encoder`,
|
|
2323
|
+
enumVariant: (name) => `${pascalCase(name)}`,
|
|
2324
|
+
instructionAsyncFunction: (name) => `get${pascalCase(name)}InstructionAsync`,
|
|
2325
|
+
instructionAsyncInputType: (name) => `${pascalCase(name)}AsyncInput`,
|
|
2326
|
+
instructionDataType: (name) => `${pascalCase(name)}InstructionData`,
|
|
2327
|
+
instructionExtraType: (name) => `${pascalCase(name)}InstructionExtra`,
|
|
2328
|
+
instructionParseFunction: (name) => `parse${pascalCase(name)}Instruction`,
|
|
2329
|
+
instructionParsedType: (name) => `Parsed${pascalCase(name)}Instruction`,
|
|
2330
|
+
instructionSyncFunction: (name) => `get${pascalCase(name)}Instruction`,
|
|
2331
|
+
instructionSyncInputType: (name) => `${pascalCase(name)}Input`,
|
|
2332
|
+
instructionType: (name) => `${pascalCase(name)}Instruction`,
|
|
2333
|
+
isDiscriminatedUnionFunction: (name) => `is${pascalCase(name)}`,
|
|
2334
|
+
pdaFindFunction: (name) => `find${pascalCase(name)}Pda`,
|
|
2335
|
+
pdaSeedsType: (name) => `${pascalCase(name)}Seeds`,
|
|
2336
|
+
programAccountsEnum: (name) => `${pascalCase(name)}Account`,
|
|
2337
|
+
programAccountsEnumVariant: (name) => `${pascalCase(name)}`,
|
|
2338
|
+
programAccountsIdentifierFunction: (name) => `identify${pascalCase(name)}Account`,
|
|
2339
|
+
programAddressConstant: (name) => `${snakeCase(name).toUpperCase()}_PROGRAM_ADDRESS`,
|
|
2340
|
+
programErrorConstant: (name) => snakeCase(name).toUpperCase(),
|
|
2341
|
+
programErrorConstantPrefix: (name) => `${snakeCase(name).toUpperCase()}_ERROR__`,
|
|
2342
|
+
programErrorMessagesMap: (name) => `${camelCase(name)}ErrorMessages`,
|
|
2343
|
+
programErrorUnion: (name) => `${pascalCase(name)}Error`,
|
|
2344
|
+
programGetErrorMessageFunction: (name) => `get${pascalCase(name)}ErrorMessage`,
|
|
2345
|
+
programInstructionsEnum: (name) => `${pascalCase(name)}Instruction`,
|
|
2346
|
+
programInstructionsEnumVariant: (name) => `${pascalCase(name)}`,
|
|
2347
|
+
programInstructionsIdentifierFunction: (name) => `identify${pascalCase(name)}Instruction`,
|
|
2348
|
+
programInstructionsParsedUnionType: (name) => `Parsed${pascalCase(name)}Instruction`,
|
|
2349
|
+
programIsErrorFunction: (name) => `is${pascalCase(name)}Error`,
|
|
2350
|
+
resolverFunction: (name) => `${camelCase(name)}`
|
|
2351
|
+
};
|
|
2352
|
+
|
|
2353
|
+
// src/getRenderMapVisitor.ts
|
|
2354
|
+
function getRenderMapVisitor(options = {}) {
|
|
2355
|
+
const linkables = new LinkableDictionary();
|
|
2356
|
+
let program = null;
|
|
2357
|
+
const nameTransformers = {
|
|
2358
|
+
...DEFAULT_NAME_TRANSFORMERS,
|
|
2359
|
+
...options.nameTransformers
|
|
2360
|
+
};
|
|
2361
|
+
const nameApi = getNameApi(nameTransformers);
|
|
2362
|
+
const renderParentInstructions = options.renderParentInstructions ?? false;
|
|
2363
|
+
const dependencyMap = options.dependencyMap ?? {};
|
|
2364
|
+
const useGranularImports = options.useGranularImports ?? false;
|
|
2365
|
+
const asyncResolvers = (options.asyncResolvers ?? []).map(camelCase);
|
|
2366
|
+
const nonScalarEnums = (options.nonScalarEnums ?? []).map(camelCase);
|
|
2367
|
+
const internalNodes = (options.internalNodes ?? []).map(camelCase);
|
|
2368
|
+
const customAccountData = parseCustomDataOptions(options.customAccountData ?? [], "AccountData");
|
|
2369
|
+
const customInstructionData = parseCustomDataOptions(options.customInstructionData ?? [], "InstructionData");
|
|
2370
|
+
const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}, customAccountData, customInstructionData);
|
|
2371
|
+
const getTypeManifestVisitor2 = (parentName) => getTypeManifestVisitor({
|
|
2372
|
+
customAccountData,
|
|
2373
|
+
customInstructionData,
|
|
2374
|
+
getImportFrom,
|
|
2375
|
+
linkables,
|
|
2376
|
+
nameApi,
|
|
2377
|
+
nonScalarEnums,
|
|
2378
|
+
parentName
|
|
2379
|
+
});
|
|
2380
|
+
const typeManifestVisitor = getTypeManifestVisitor2();
|
|
2381
|
+
const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();
|
|
2382
|
+
const globalScope = {
|
|
2383
|
+
asyncResolvers,
|
|
2384
|
+
customAccountData,
|
|
2385
|
+
customInstructionData,
|
|
2386
|
+
getImportFrom,
|
|
2387
|
+
linkables,
|
|
2388
|
+
nameApi,
|
|
2389
|
+
nonScalarEnums,
|
|
2390
|
+
renderParentInstructions,
|
|
2391
|
+
typeManifestVisitor
|
|
2392
|
+
};
|
|
2393
|
+
const render2 = (template, context, renderOptions) => {
|
|
2394
|
+
return render(join("pages", template), context, renderOptions);
|
|
2395
|
+
};
|
|
2396
|
+
return pipe(
|
|
2397
|
+
staticVisitor(
|
|
2398
|
+
() => new RenderMap(),
|
|
2399
|
+
["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"]
|
|
2400
|
+
),
|
|
2401
|
+
(v) => extendVisitor(v, {
|
|
2402
|
+
visitAccount(node) {
|
|
2403
|
+
if (!program) {
|
|
2404
|
+
throw new Error("Account must be visited inside a program.");
|
|
2405
|
+
}
|
|
2406
|
+
const scope = {
|
|
2407
|
+
...globalScope,
|
|
2408
|
+
accountNode: node,
|
|
2409
|
+
programNode: program,
|
|
2410
|
+
typeManifest: visit(node, typeManifestVisitor)
|
|
2411
|
+
};
|
|
2412
|
+
const fields = resolveNestedTypeNode(node.data).fields;
|
|
2413
|
+
const accountDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({
|
|
2414
|
+
...scope,
|
|
2415
|
+
discriminatorNodes: node.discriminators ?? [],
|
|
2416
|
+
fields,
|
|
2417
|
+
prefix: node.name
|
|
2418
|
+
});
|
|
2419
|
+
const accountTypeFragment = getAccountTypeFragment(scope);
|
|
2420
|
+
const accountFetchHelpersFragment = getAccountFetchHelpersFragment(scope);
|
|
2421
|
+
const accountSizeHelpersFragment = getAccountSizeHelpersFragment(scope);
|
|
2422
|
+
const accountPdaHelpersFragment = getAccountPdaHelpersFragment(scope);
|
|
2423
|
+
const imports = new ImportMap().mergeWith(
|
|
2424
|
+
accountDiscriminatorConstantsFragment,
|
|
2425
|
+
accountTypeFragment,
|
|
2426
|
+
accountFetchHelpersFragment,
|
|
2427
|
+
accountSizeHelpersFragment,
|
|
2428
|
+
accountPdaHelpersFragment
|
|
2429
|
+
);
|
|
2430
|
+
return new RenderMap().add(
|
|
2431
|
+
`accounts/${camelCase(node.name)}.ts`,
|
|
2432
|
+
render2("accountsPage.njk", {
|
|
2433
|
+
accountDiscriminatorConstantsFragment,
|
|
2434
|
+
accountFetchHelpersFragment,
|
|
2435
|
+
accountPdaHelpersFragment,
|
|
2436
|
+
accountSizeHelpersFragment,
|
|
2437
|
+
accountTypeFragment,
|
|
2438
|
+
imports: imports.toString(dependencyMap, useGranularImports)
|
|
2439
|
+
})
|
|
2440
|
+
);
|
|
2441
|
+
},
|
|
2442
|
+
visitDefinedType(node) {
|
|
2443
|
+
const scope = {
|
|
2444
|
+
...globalScope,
|
|
2445
|
+
codecDocs: [],
|
|
2446
|
+
decoderDocs: [],
|
|
2447
|
+
encoderDocs: [],
|
|
2448
|
+
manifest: visit(node, typeManifestVisitor),
|
|
2449
|
+
name: node.name,
|
|
2450
|
+
typeDocs: node.docs,
|
|
2451
|
+
typeNode: node.type
|
|
2452
|
+
};
|
|
2453
|
+
const typeWithCodecFragment = getTypeWithCodecFragment(scope);
|
|
2454
|
+
const typeDiscriminatedUnionHelpersFragment = getTypeDiscriminatedUnionHelpersFragment(scope);
|
|
2455
|
+
const imports = new ImportMap().mergeWith(typeWithCodecFragment, typeDiscriminatedUnionHelpersFragment).remove("generatedTypes", [
|
|
2456
|
+
nameApi.dataType(node.name),
|
|
2457
|
+
nameApi.dataArgsType(node.name),
|
|
2458
|
+
nameApi.encoderFunction(node.name),
|
|
2459
|
+
nameApi.decoderFunction(node.name),
|
|
2460
|
+
nameApi.codecFunction(node.name)
|
|
2461
|
+
]);
|
|
2462
|
+
return new RenderMap().add(
|
|
2463
|
+
`types/${camelCase(node.name)}.ts`,
|
|
2464
|
+
render2("definedTypesPage.njk", {
|
|
2465
|
+
imports: imports.toString({
|
|
2466
|
+
...dependencyMap,
|
|
2467
|
+
generatedTypes: "."
|
|
2468
|
+
}),
|
|
2469
|
+
typeDiscriminatedUnionHelpersFragment,
|
|
2470
|
+
typeWithCodecFragment
|
|
2471
|
+
})
|
|
2472
|
+
);
|
|
2473
|
+
},
|
|
2474
|
+
visitInstruction(node) {
|
|
2475
|
+
if (!program) {
|
|
2476
|
+
throw new Error("Instruction must be visited inside a program.");
|
|
2477
|
+
}
|
|
2478
|
+
const instructionExtraName = nameApi.instructionExtraType(node.name);
|
|
2479
|
+
const scope = {
|
|
2480
|
+
...globalScope,
|
|
2481
|
+
dataArgsManifest: visit(node, typeManifestVisitor),
|
|
2482
|
+
extraArgsManifest: visit(
|
|
2483
|
+
structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? []),
|
|
2484
|
+
getTypeManifestVisitor2({
|
|
2485
|
+
loose: nameApi.dataArgsType(instructionExtraName),
|
|
2486
|
+
strict: nameApi.dataType(instructionExtraName)
|
|
2487
|
+
})
|
|
2488
|
+
),
|
|
2489
|
+
instructionNode: node,
|
|
2490
|
+
programNode: program,
|
|
2491
|
+
renamedArgs: getRenamedArgsMap(node),
|
|
2492
|
+
resolvedInputs: visit(node, resolvedInstructionInputVisitor)
|
|
2493
|
+
};
|
|
2494
|
+
const instructionDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({
|
|
2495
|
+
...scope,
|
|
2496
|
+
discriminatorNodes: node.discriminators ?? [],
|
|
2497
|
+
fields: node.arguments,
|
|
2498
|
+
prefix: node.name
|
|
2499
|
+
});
|
|
2500
|
+
const instructionTypeFragment = getInstructionTypeFragment(scope);
|
|
2501
|
+
const instructionDataFragment = getInstructionDataFragment(scope);
|
|
2502
|
+
const instructionExtraArgsFragment = getInstructionExtraArgsFragment(scope);
|
|
2503
|
+
const instructionFunctionAsyncFragment = getInstructionFunctionFragment({
|
|
2504
|
+
...scope,
|
|
2505
|
+
useAsync: true
|
|
2506
|
+
});
|
|
2507
|
+
const instructionFunctionSyncFragment = getInstructionFunctionFragment({
|
|
2508
|
+
...scope,
|
|
2509
|
+
useAsync: false
|
|
2510
|
+
});
|
|
2511
|
+
const instructionParseFunctionFragment = getInstructionParseFunctionFragment(scope);
|
|
2512
|
+
const imports = new ImportMap().mergeWith(
|
|
2513
|
+
instructionDiscriminatorConstantsFragment,
|
|
2514
|
+
instructionTypeFragment,
|
|
2515
|
+
instructionDataFragment,
|
|
2516
|
+
instructionExtraArgsFragment,
|
|
2517
|
+
instructionFunctionAsyncFragment,
|
|
2518
|
+
instructionFunctionSyncFragment,
|
|
2519
|
+
instructionParseFunctionFragment
|
|
2520
|
+
);
|
|
2521
|
+
return new RenderMap().add(
|
|
2522
|
+
`instructions/${camelCase(node.name)}.ts`,
|
|
2523
|
+
render2("instructionsPage.njk", {
|
|
2524
|
+
imports: imports.toString(dependencyMap, useGranularImports),
|
|
2525
|
+
instruction: node,
|
|
2526
|
+
instructionDataFragment,
|
|
2527
|
+
instructionDiscriminatorConstantsFragment,
|
|
2528
|
+
instructionExtraArgsFragment,
|
|
2529
|
+
instructionFunctionAsyncFragment,
|
|
2530
|
+
instructionFunctionSyncFragment,
|
|
2531
|
+
instructionParseFunctionFragment,
|
|
2532
|
+
instructionTypeFragment
|
|
2533
|
+
})
|
|
2534
|
+
);
|
|
2535
|
+
},
|
|
2536
|
+
visitPda(node) {
|
|
2537
|
+
if (!program) {
|
|
2538
|
+
throw new Error("Account must be visited inside a program.");
|
|
2539
|
+
}
|
|
2540
|
+
const scope = { ...globalScope, pdaNode: node, programNode: program };
|
|
2541
|
+
const pdaFunctionFragment = getPdaFunctionFragment(scope);
|
|
2542
|
+
const imports = new ImportMap().mergeWith(pdaFunctionFragment);
|
|
2543
|
+
return new RenderMap().add(
|
|
2544
|
+
`pdas/${camelCase(node.name)}.ts`,
|
|
2545
|
+
render2("pdasPage.njk", {
|
|
2546
|
+
imports: imports.toString(dependencyMap, useGranularImports),
|
|
2547
|
+
pdaFunctionFragment
|
|
2548
|
+
})
|
|
2549
|
+
);
|
|
2550
|
+
},
|
|
2551
|
+
visitProgram(node, { self }) {
|
|
2552
|
+
program = node;
|
|
2553
|
+
const customDataDefinedType = [
|
|
2554
|
+
...getDefinedTypeNodesToExtract(node.accounts, customAccountData),
|
|
2555
|
+
...getDefinedTypeNodesToExtract(node.instructions, customInstructionData)
|
|
2556
|
+
];
|
|
2557
|
+
const scope = { ...globalScope, programNode: node };
|
|
2558
|
+
const renderMap = new RenderMap().mergeWith(...node.pdas.map((p) => visit(p, self))).mergeWith(...node.accounts.map((a) => visit(a, self))).mergeWith(...node.definedTypes.map((t) => visit(t, self))).mergeWith(...customDataDefinedType.map((t) => visit(t, self)));
|
|
2559
|
+
if (node.errors.length > 0) {
|
|
2560
|
+
const programErrorsFragment = getProgramErrorsFragment(scope);
|
|
2561
|
+
renderMap.add(
|
|
2562
|
+
`errors/${camelCase(node.name)}.ts`,
|
|
2563
|
+
render2("errorsPage.njk", {
|
|
2564
|
+
imports: new ImportMap().mergeWith(programErrorsFragment).toString(dependencyMap, useGranularImports),
|
|
2565
|
+
programErrorsFragment
|
|
2566
|
+
})
|
|
2567
|
+
);
|
|
2568
|
+
}
|
|
2569
|
+
const programFragment = getProgramFragment(scope);
|
|
2570
|
+
const programAccountsFragment = getProgramAccountsFragment(scope);
|
|
2571
|
+
const programInstructionsFragment = getProgramInstructionsFragment(scope);
|
|
2572
|
+
renderMap.add(
|
|
2573
|
+
`programs/${camelCase(node.name)}.ts`,
|
|
2574
|
+
render2("programsPage.njk", {
|
|
2575
|
+
imports: new ImportMap().mergeWith(programFragment, programAccountsFragment, programInstructionsFragment).toString(dependencyMap, useGranularImports),
|
|
2576
|
+
programAccountsFragment,
|
|
2577
|
+
programFragment,
|
|
2578
|
+
programInstructionsFragment
|
|
2579
|
+
})
|
|
2580
|
+
);
|
|
2581
|
+
renderMap.mergeWith(
|
|
2582
|
+
...getAllInstructionsWithSubs(program, {
|
|
2583
|
+
leavesOnly: !renderParentInstructions
|
|
2584
|
+
}).map((ix) => visit(ix, self))
|
|
2585
|
+
);
|
|
2586
|
+
program = null;
|
|
2587
|
+
return renderMap;
|
|
2588
|
+
},
|
|
2589
|
+
visitRoot(node, { self }) {
|
|
2590
|
+
const isNotInternal = (n) => !internalNodes.includes(n.name);
|
|
2591
|
+
const programsToExport = getAllPrograms(node).filter(isNotInternal);
|
|
2592
|
+
const programsWithErrorsToExport = programsToExport.filter((p) => p.errors.length > 0);
|
|
2593
|
+
const pdasToExport = getAllPdas(node);
|
|
2594
|
+
const accountsToExport = getAllAccounts(node).filter(isNotInternal);
|
|
2595
|
+
const instructionsToExport = getAllInstructionsWithSubs(node, {
|
|
2596
|
+
leavesOnly: !renderParentInstructions
|
|
2597
|
+
}).filter(isNotInternal);
|
|
2598
|
+
const definedTypesToExport = getAllDefinedTypes(node).filter(isNotInternal);
|
|
2599
|
+
const hasAnythingToExport = programsToExport.length > 0 || accountsToExport.length > 0 || instructionsToExport.length > 0 || definedTypesToExport.length > 0;
|
|
2600
|
+
const ctx = {
|
|
2601
|
+
accountsToExport,
|
|
2602
|
+
definedTypesToExport,
|
|
2603
|
+
hasAnythingToExport,
|
|
2604
|
+
instructionsToExport,
|
|
2605
|
+
pdasToExport,
|
|
2606
|
+
programsToExport,
|
|
2607
|
+
programsWithErrorsToExport,
|
|
2608
|
+
root: node
|
|
2609
|
+
};
|
|
2610
|
+
const map = new RenderMap();
|
|
2611
|
+
if (hasAnythingToExport) {
|
|
2612
|
+
map.add(
|
|
2613
|
+
"shared/index.ts",
|
|
2614
|
+
render2("sharedPage.njk", {
|
|
2615
|
+
...ctx,
|
|
2616
|
+
imports: new ImportMap().add("solanaAddresses", [
|
|
2617
|
+
"type Address",
|
|
2618
|
+
"isProgramDerivedAddress",
|
|
2619
|
+
"type ProgramDerivedAddress"
|
|
2620
|
+
]).add("solanaInstructions", [
|
|
2621
|
+
"AccountRole",
|
|
2622
|
+
"type IAccountMeta",
|
|
2623
|
+
"upgradeRoleToSigner"
|
|
2624
|
+
]).add("solanaSigners", [
|
|
2625
|
+
"type IAccountSignerMeta",
|
|
2626
|
+
"isTransactionSigner",
|
|
2627
|
+
"type TransactionSigner"
|
|
2628
|
+
]).addAlias("solanaSigners", "isTransactionSigner", "web3JsIsTransactionSigner").toString(dependencyMap, useGranularImports)
|
|
2629
|
+
})
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
if (programsToExport.length > 0) {
|
|
2633
|
+
map.add("programs/index.ts", render2("programsIndex.njk", ctx));
|
|
2634
|
+
}
|
|
2635
|
+
if (programsWithErrorsToExport.length > 0) {
|
|
2636
|
+
map.add("errors/index.ts", render2("errorsIndex.njk", ctx));
|
|
2637
|
+
}
|
|
2638
|
+
if (accountsToExport.length > 0) {
|
|
2639
|
+
map.add("accounts/index.ts", render2("accountsIndex.njk", ctx));
|
|
2640
|
+
}
|
|
2641
|
+
if (pdasToExport.length > 0) {
|
|
2642
|
+
map.add("pdas/index.ts", render2("pdasIndex.njk", ctx));
|
|
2643
|
+
}
|
|
2644
|
+
if (instructionsToExport.length > 0) {
|
|
2645
|
+
map.add("instructions/index.ts", render2("instructionsIndex.njk", ctx));
|
|
2646
|
+
}
|
|
2647
|
+
if (definedTypesToExport.length > 0) {
|
|
2648
|
+
map.add("types/index.ts", render2("definedTypesIndex.njk", ctx));
|
|
2649
|
+
}
|
|
2650
|
+
return map.add("index.ts", render2("rootIndex.njk", ctx)).mergeWith(...getAllPrograms(node).map((p) => visit(p, self)));
|
|
2651
|
+
}
|
|
2652
|
+
}),
|
|
2653
|
+
(v) => recordLinkablesVisitor(v, linkables)
|
|
2654
|
+
);
|
|
2655
|
+
}
|
|
2656
|
+
function getRenamedArgsMap(instruction) {
|
|
2657
|
+
const argNames = [
|
|
2658
|
+
...instruction.arguments.map((a) => a.name),
|
|
2659
|
+
...(instruction.extraArguments ?? []).map((a) => a.name)
|
|
2660
|
+
];
|
|
2661
|
+
const duplicateArgs = argNames.filter((e, i, a) => a.indexOf(e) !== i);
|
|
2662
|
+
if (duplicateArgs.length > 0) {
|
|
2663
|
+
throw new Error(`Duplicate args found: [${duplicateArgs.join(", ")}] in instruction [${instruction.name}].`);
|
|
2664
|
+
}
|
|
2665
|
+
const allNames = [...instruction.accounts.map((account) => account.name), ...argNames];
|
|
2666
|
+
const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i);
|
|
2667
|
+
if (duplicates.length === 0) return /* @__PURE__ */ new Map();
|
|
2668
|
+
logWarn(
|
|
2669
|
+
`[JavaScript] Accounts and args of instruction [${instruction.name}] have the following conflicting attributes [${duplicates.join(", ")}]. Thus, the arguments have been renamed to avoid conflicts in the input type.`
|
|
2670
|
+
);
|
|
2671
|
+
return new Map(duplicates.map((name) => [camelCase(name), camelCase(`${name}Arg`)]));
|
|
2672
|
+
}
|
|
2673
|
+
var DEFAULT_PRETTIER_OPTIONS = {
|
|
2674
|
+
arrowParens: "always",
|
|
2675
|
+
parser: "typescript",
|
|
2676
|
+
plugins: [estreePlugin, typeScriptPlugin],
|
|
2677
|
+
printWidth: 80,
|
|
2678
|
+
semi: true,
|
|
2679
|
+
singleQuote: true,
|
|
2680
|
+
tabWidth: 2,
|
|
2681
|
+
trailingComma: "es5",
|
|
2682
|
+
useTabs: false
|
|
2683
|
+
};
|
|
2684
|
+
function renderVisitor(path, options = {}) {
|
|
2685
|
+
return rootNodeVisitor(async (root) => {
|
|
2686
|
+
if (options.deleteFolderBeforeRendering ?? true) {
|
|
2687
|
+
deleteDirectory(path);
|
|
2688
|
+
}
|
|
2689
|
+
const renderMap = visit(root, getRenderMapVisitor(options));
|
|
2690
|
+
if (options.formatCode ?? true) {
|
|
2691
|
+
const prettierOptions = { ...DEFAULT_PRETTIER_OPTIONS, ...options.prettierOptions };
|
|
2692
|
+
await renderMap.mapContentAsync((code) => format(code, prettierOptions));
|
|
2693
|
+
}
|
|
2694
|
+
renderMap.write(path);
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
export { DEFAULT_NAME_TRANSFORMERS, ImportMap, getNameApi, getRenderMapVisitor, getTypeManifestVisitor, mergeManifests, renderVisitor, typeManifest };
|
|
2699
|
+
//# sourceMappingURL=index.node.mjs.map
|
|
2700
|
+
//# sourceMappingURL=index.node.mjs.map
|