'use strict'; var visitorsCore = require('@codama/visitors-core'); var path = require('path'); var nodes = require('@codama/nodes'); var codecsStrings = require('@solana/codecs-strings'); var errors = require('@codama/errors'); require('url'); var nunjucks = require('nunjucks'); var renderersCore = require('@codama/renderers-core'); var estreePlugin = require('prettier/plugins/estree'); var typeScriptPlugin = require('prettier/plugins/typescript'); var standalone = require('prettier/standalone'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var nunjucks__default = /*#__PURE__*/_interopDefault(nunjucks); var estreePlugin__namespace = /*#__PURE__*/_interopNamespace(estreePlugin); var typeScriptPlugin__namespace = /*#__PURE__*/_interopNamespace(typeScriptPlugin); // src/ImportMap.ts var DEFAULT_EXTERNAL_MODULE_MAP = { solanaAccounts: "@solana/web3.js", solanaAddresses: "@solana/web3.js", solanaCodecsCore: "@solana/web3.js", solanaCodecsDataStructures: "@solana/web3.js", solanaCodecsNumbers: "@solana/web3.js", solanaCodecsStrings: "@solana/web3.js", solanaErrors: "@solana/web3.js", solanaInstructions: "@solana/web3.js", solanaOptions: "@solana/web3.js", solanaPrograms: "@solana/web3.js", solanaRpcTypes: "@solana/web3.js", solanaSigners: "@solana/web3.js" }; var DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP = { solanaAccounts: "@solana/accounts", solanaAddresses: "@solana/addresses", solanaCodecsCore: "@solana/codecs", solanaCodecsDataStructures: "@solana/codecs", solanaCodecsNumbers: "@solana/codecs", solanaCodecsStrings: "@solana/codecs", solanaErrors: "@solana/errors", solanaInstructions: "@solana/instructions", solanaOptions: "@solana/codecs", solanaPrograms: "@solana/programs", solanaRpcTypes: "@solana/rpc-types", solanaSigners: "@solana/signers" }; var DEFAULT_INTERNAL_MODULE_MAP = { errors: "../errors", generated: "..", generatedAccounts: "../accounts", generatedErrors: "../errors", generatedInstructions: "../instructions", generatedPdas: "../pdas", generatedPrograms: "../programs", generatedTypes: "../types", hooked: "../../hooked", shared: "../shared", types: "../types" }; var ImportMap = class { _imports = /* @__PURE__ */ new Map(); _aliases = /* @__PURE__ */ new Map(); add(module, imports) { const newImports = new Set(typeof imports === "string" ? [imports] : imports); if (newImports.size === 0) return this; const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set(); newImports.forEach((i) => currentImports.add(i)); this._imports.set(module, currentImports); return this; } remove(module, imports) { const importsToRemove = new Set(typeof imports === "string" ? [imports] : imports); if (importsToRemove.size === 0) return this; const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set(); importsToRemove.forEach((i) => currentImports.delete(i)); if (currentImports.size === 0) { this._imports.delete(module); } else { this._imports.set(module, currentImports); } return this; } mergeWith(...others) { others.forEach((rawOther) => { const other = "imports" in rawOther ? rawOther.imports : rawOther; other._imports.forEach((imports, module) => { this.add(module, imports); }); other._aliases.forEach((aliases, module) => { Object.entries(aliases).forEach(([name, alias]) => { this.addAlias(module, name, alias); }); }); }); return this; } mergeWithManifest(manifest) { return this.mergeWith(manifest.strictType, manifest.looseType, manifest.encoder, manifest.decoder); } addAlias(module, name, alias) { const currentAliases = this._aliases.get(module) ?? {}; currentAliases[name] = alias; this._aliases.set(module, currentAliases); return this; } isEmpty() { return this._imports.size === 0; } resolve(dependencies = {}, useGranularImports = false) { const aliasedMap = new Map( [...this._imports.entries()].map(([module, imports]) => { const aliasMap = this._aliases.get(module) ?? {}; const joinedImports = [...imports].map((i) => aliasMap[i] ? `${i} as ${aliasMap[i]}` : i); return [module, new Set(joinedImports)]; }) ); const dependencyMap = { ...useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP, ...DEFAULT_INTERNAL_MODULE_MAP, ...dependencies }; const resolvedMap = /* @__PURE__ */ new Map(); aliasedMap.forEach((imports, module) => { const resolvedModule = dependencyMap[module] ?? module; const currentImports = resolvedMap.get(resolvedModule) ?? /* @__PURE__ */ new Set(); imports.forEach((i) => currentImports.add(i)); resolvedMap.set(resolvedModule, currentImports); }); return resolvedMap; } toString(dependencies = {}, useGranularImports = false) { return [...this.resolve(dependencies, useGranularImports).entries()].sort(([a], [b]) => { const aIsRelative = a.startsWith("."); const bIsRelative = b.startsWith("."); if (aIsRelative && !bIsRelative) return 1; if (!aIsRelative && bIsRelative) return -1; return a.localeCompare(b); }).map(([module, imports]) => { const joinedImports = [...imports].sort().filter((i) => { const name = i.split(" "); if (name.length > 1) { return !imports.has(name[1]); } return true; }).join(", "); return `import { ${joinedImports} } from '${module}';`; }).join("\n"); } }; function hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers) { const hasByteDeltasAsync = (instructionNode.byteDeltas ?? []).some( ({ value }) => nodes.isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name) ); const hasRemainingAccountsAsync = (instructionNode.remainingAccounts ?? []).some( ({ value }) => nodes.isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name) ); return hasAsyncDefaultValues(resolvedInputs, asyncResolvers) || hasByteDeltasAsync || hasRemainingAccountsAsync; } function hasAsyncDefaultValues(resolvedInputs, asyncResolvers) { return resolvedInputs.some( (input) => !!input.defaultValue && isAsyncDefaultValue(input.defaultValue, asyncResolvers) ); } function isAsyncDefaultValue(defaultValue, asyncResolvers) { switch (defaultValue.kind) { case "pdaValueNode": return true; case "resolverValueNode": return asyncResolvers.includes(defaultValue.name); case "conditionalValueNode": return isAsyncDefaultValue(defaultValue.condition, asyncResolvers) || (defaultValue.ifFalse == null ? false : isAsyncDefaultValue(defaultValue.ifFalse, asyncResolvers)) || (defaultValue.ifTrue == null ? false : isAsyncDefaultValue(defaultValue.ifTrue, asyncResolvers)); default: return false; } } function getInstructionDependencies(input, asyncResolvers, useAsync) { if (nodes.isNode(input, "instructionNode")) { return visitorsCore.deduplicateInstructionDependencies([ ...input.accounts.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)), ...input.arguments.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)), ...(input.extraArguments ?? []).flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)) ]); } if (!input.defaultValue) return []; const getNestedDependencies = (defaultValue) => { if (!defaultValue) return []; return getInstructionDependencies({ ...input, defaultValue }, asyncResolvers, useAsync); }; if (nodes.isNode(input.defaultValue, ["accountValueNode", "accountBumpValueNode"])) { return [nodes.accountValueNode(input.defaultValue.name)]; } if (nodes.isNode(input.defaultValue, ["argumentValueNode"])) { return [nodes.argumentValueNode(input.defaultValue.name)]; } if (nodes.isNode(input.defaultValue, "pdaValueNode")) { const dependencies = /* @__PURE__ */ new Map(); input.defaultValue.seeds.forEach((seed) => { if (nodes.isNode(seed.value, ["accountValueNode", "argumentValueNode"])) { dependencies.set(seed.value.name, { ...seed.value }); } }); return [...dependencies.values()]; } if (nodes.isNode(input.defaultValue, "resolverValueNode")) { const isSynchronousResolver = !asyncResolvers.includes(input.defaultValue.name); if (useAsync || isSynchronousResolver) { return input.defaultValue.dependsOn ?? []; } } if (nodes.isNode(input.defaultValue, "conditionalValueNode")) { return visitorsCore.deduplicateInstructionDependencies([ ...getNestedDependencies(input.defaultValue.condition), ...getNestedDependencies(input.defaultValue.ifTrue), ...getNestedDependencies(input.defaultValue.ifFalse) ]); } return []; } function getBytesFromBytesValueNode(node) { switch (node.encoding) { case "utf8": return codecsStrings.getUtf8Encoder().encode(node.data); case "base16": return codecsStrings.getBase16Encoder().encode(node.data); case "base58": return codecsStrings.getBase58Encoder().encode(node.data); case "base64": default: return codecsStrings.getBase64Encoder().encode(node.data); } } var parseCustomDataOptions = (customDataOptions, defaultSuffix) => new Map( customDataOptions.map((o) => { const options = typeof o === "string" ? { name: o } : o; const importAs = nodes.camelCase(options.importAs ?? `${options.name}${defaultSuffix}`); const importFrom = options.importFrom ?? "hooked"; return [ nodes.camelCase(options.name), { extract: options.extract ?? false, extractAs: options.extractAs ? nodes.camelCase(options.extractAs) : importAs, importAs, importFrom, linkNode: nodes.definedTypeLinkNode(importAs) } ]; }) ); var getDefinedTypeNodesToExtract = (nodes$1, parsedCustomDataOptions) => nodes$1.flatMap((node) => { const options = parsedCustomDataOptions.get(node.name); if (!options || !options.extract) return []; if (nodes.isNode(node, "accountNode")) { return [nodes.definedTypeNode({ name: options.extractAs, type: { ...node.data } })]; } return [ nodes.definedTypeNode({ name: options.extractAs, type: nodes.structTypeNodeFromInstructionArgumentNodes(node.arguments) }) ]; }); function getImportFromFactory(overrides, customAccountData, customInstructionData) { const customDataOverrides = Object.fromEntries( [...customAccountData.values(), ...customInstructionData.values()].map(({ importFrom, importAs }) => [ importAs, importFrom ]) ); const linkOverrides = { accounts: overrides.accounts ?? {}, definedTypes: { ...customDataOverrides, ...overrides.definedTypes }, instructions: overrides.instructions ?? {}, pdas: overrides.pdas ?? {}, programs: overrides.programs ?? {}, resolvers: overrides.resolvers ?? {} }; return (node) => { const kind = node.kind; switch (kind) { case "accountLinkNode": return linkOverrides.accounts[node.name] ?? "generatedAccounts"; case "definedTypeLinkNode": return linkOverrides.definedTypes[node.name] ?? "generatedTypes"; case "instructionLinkNode": return linkOverrides.instructions[node.name] ?? "generatedInstructions"; case "pdaLinkNode": return linkOverrides.pdas[node.name] ?? "generatedPdas"; case "programLinkNode": return linkOverrides.programs[node.name] ?? "generatedPrograms"; case "resolverValueNode": return linkOverrides.resolvers[node.name] ?? "hooked"; default: throw new errors.CodamaError(errors.CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [ "AccountLinkNode", "DefinedTypeLinkNode", "InstructionLinkNode", "PdaLinkNode", "ProgramLinkNode", "resolverValueNode" ], kind, node }); } }; } function jsDocblock(docs) { if (docs.length <= 0) return ""; if (docs.length === 1) return `/** ${docs[0]} */ `; const lines = docs.map((doc) => ` * ${doc}`); return `/** ${lines.join("\n")} */ `; } var render = (template, context, options) => { const dirname = __dirname; const templates = path.join(dirname, "templates"); const env = nunjucks__default.default.configure(templates, { autoescape: false, trimBlocks: true, ...options }); env.addFilter("pascalCase", nodes.pascalCase); env.addFilter("camelCase", nodes.camelCase); env.addFilter("snakeCase", nodes.snakeCase); env.addFilter("kebabCase", nodes.kebabCase); env.addFilter("titleCase", nodes.titleCase); env.addFilter("jsDocblock", jsDocblock); return env.render(template, context); }; // src/fragments/common.ts function fragment(render2, imports) { return new Fragment(render2, imports); } function fragmentFromTemplate(fragmentFile, context, options) { return fragment(render(path.join("fragments", fragmentFile), context, options)); } function mergeFragments(fragments, mergeRenders) { return new Fragment( mergeRenders(fragments.map((f) => f.render)), new ImportMap().mergeWith(...fragments), new Set(fragments.flatMap((f) => [...f.features])) ); } var Fragment = class _Fragment { render; imports; features; constructor(render2, imports, features) { this.render = render2; this.imports = imports ? new ImportMap().mergeWith(imports) : new ImportMap(); this.features = /* @__PURE__ */ new Set([...features ?? []]); } setRender(render2) { this.render = render2; return this; } mapRender(fn) { this.render = fn(this.render); return this; } addImports(module, imports) { this.imports.add(module, imports); return this; } removeImports(module, imports) { this.imports.remove(module, imports); return this; } mergeImportsWith(...others) { this.imports.mergeWith(...others); return this; } addImportAlias(module, name, alias) { this.imports.addAlias(module, name, alias); return this; } addFeatures(features) { const featureArray = typeof features === "string" ? [features] : features; featureArray.forEach((f) => this.features.add(f)); return this; } removeFeatures(features) { const featureArray = typeof features === "string" ? [features] : features; featureArray.forEach((f) => this.features.delete(f)); return this; } hasFeatures(features) { const featureArray = typeof features === "string" ? [features] : features; return featureArray.every((f) => this.features.has(f)); } mergeFeaturesWith(...others) { others.forEach((f) => this.addFeatures([...f.features])); return this; } clone() { return new _Fragment(this.render).mergeImportsWith(this.imports); } toString() { return this.render; } }; // src/fragments/accountFetchHelpers.ts function getAccountFetchHelpersFragment(scope) { const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope; const accountNode = visitorsCore.getLastNodeFromPath(accountPath); const hasCustomData = customAccountData.has(accountNode.name); const accountTypeFragment = hasCustomData ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name)); const decoderFunctionFragment = hasCustomData ? typeManifest2.decoder.clone() : fragment(`${nameApi.decoderFunction(accountNode.name)}()`); return fragmentFromTemplate("accountFetchHelpers.njk", { accountType: accountTypeFragment.render, decodeFunction: nameApi.accountDecodeFunction(accountNode.name), decoderFunction: decoderFunctionFragment.render, fetchAllFunction: nameApi.accountFetchAllFunction(accountNode.name), fetchAllMaybeFunction: nameApi.accountFetchAllMaybeFunction(accountNode.name), fetchFunction: nameApi.accountFetchFunction(accountNode.name), fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name) }).mergeImportsWith(accountTypeFragment, decoderFunctionFragment).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [ "type Account", "assertAccountExists", "assertAccountsExist", "decodeAccount", "type EncodedAccount", "fetchEncodedAccount", "fetchEncodedAccounts", "type FetchAccountConfig", "type FetchAccountsConfig", "type MaybeAccount", "type MaybeEncodedAccount" ]); } function getAccountPdaHelpersFragment(scope) { const { accountPath, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope; const accountNode = visitorsCore.getLastNodeFromPath(accountPath); const programNode = visitorsCore.findProgramNodeFromPath(accountPath); const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : void 0; if (!pdaNode) { return fragment(""); } const accountTypeFragment = customAccountData.has(accountNode.name) ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name)); const importFrom = "generatedPdas"; const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name); const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name); const hasVariableSeeds = pdaNode.seeds.filter(nodes.isNodeFilter("variablePdaSeedNode")).length > 0; return fragmentFromTemplate("accountPdaHelpers.njk", { accountType: accountTypeFragment.render, fetchFromSeedsFunction: nameApi.accountFetchFromSeedsFunction(accountNode.name), fetchFunction: nameApi.accountFetchFunction(accountNode.name), fetchMaybeFromSeedsFunction: nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name), fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name), findPdaFunction, hasVariableSeeds, pdaSeedsType, program: programNode }).mergeImportsWith(accountTypeFragment).addImports(importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [ "type Account", "assertAccountExists", "type FetchAccountConfig", "type MaybeAccount" ]); } function getAccountSizeHelpersFragment(scope) { const { accountPath, nameApi } = scope; const accountNode = visitorsCore.getLastNodeFromPath(accountPath); if (accountNode.size == null) { return fragment(""); } return fragmentFromTemplate("accountSizeHelpers.njk", { account: accountNode, getSizeFunction: nameApi.accountGetSizeFunction(accountNode.name) }); } // src/fragments/type.ts function getTypeFragment(scope) { const { name, manifest, nameApi, docs = [] } = scope; const typeFragment = fragmentFromTemplate("type.njk", { docs, looseName: nameApi.dataArgsType(name), manifest, strictName: nameApi.dataType(name) }); if (!manifest.isEnum) { typeFragment.mergeImportsWith(manifest.strictType, manifest.looseType); } return typeFragment; } // src/fragments/typeDecoder.ts function getTypeDecoderFragment(scope) { const { name, manifest, nameApi, docs = [] } = scope; return fragmentFromTemplate("typeDecoder.njk", { decoderFunction: nameApi.decoderFunction(name), docs, looseName: nameApi.dataArgsType(name), manifest, strictName: nameApi.dataType(name) }).mergeImportsWith(manifest.decoder).addImports("solanaCodecsCore", "type Decoder"); } // src/fragments/typeEncoder.ts function getTypeEncoderFragment(scope) { const { name, manifest, nameApi, docs = [] } = scope; return fragmentFromTemplate("typeEncoder.njk", { docs, encoderFunction: nameApi.encoderFunction(name), looseName: nameApi.dataArgsType(name), manifest, strictName: nameApi.dataType(name) }).mergeImportsWith(manifest.encoder).addImports("solanaCodecsCore", "type Encoder"); } // src/fragments/typeCodec.ts function getTypeCodecFragment(scope) { const { name, manifest, nameApi } = scope; return mergeFragments( [ getTypeEncoderFragment({ ...scope, docs: scope.encoderDocs }), getTypeDecoderFragment({ ...scope, docs: scope.decoderDocs }), fragmentFromTemplate("typeCodec.njk", { codecFunction: nameApi.codecFunction(name), decoderFunction: nameApi.decoderFunction(name), docs: scope.codecDocs, encoderFunction: nameApi.encoderFunction(name), looseName: nameApi.dataArgsType(name), manifest, strictName: nameApi.dataType(name) }).addImports("solanaCodecsCore", ["type Codec", "combineCodec"]) ], (renders) => renders.join("\n\n") ); } // src/fragments/typeWithCodec.ts function getTypeWithCodecFragment(scope) { return mergeFragments( [getTypeFragment({ ...scope, docs: scope.typeDocs }), getTypeCodecFragment(scope)], (renders) => renders.join("\n\n") ); } // src/fragments/accountType.ts function getAccountTypeFragment(scope) { const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope; const accountNode = visitorsCore.getLastNodeFromPath(accountPath); if (customAccountData.has(accountNode.name)) { return fragment(""); } return getTypeWithCodecFragment({ manifest: typeManifest2, name: accountNode.name, nameApi }); } function getDiscriminatorConditionFragment(scope) { return mergeFragments( scope.discriminators.flatMap((discriminator) => { if (nodes.isNode(discriminator, "sizeDiscriminatorNode")) { return [getSizeConditionFragment(discriminator, scope)]; } if (nodes.isNode(discriminator, "constantDiscriminatorNode")) { return [getByteConditionFragment(discriminator, scope)]; } if (nodes.isNode(discriminator, "fieldDiscriminatorNode")) { return [getFieldConditionFragment(discriminator, scope)]; } return []; }), (r) => r.join(" && ") ).mapRender((r) => `if (${r}) { ${scope.ifTrue}; }`); } function getSizeConditionFragment(discriminator, scope) { const { dataName } = scope; return fragment(`${dataName}.length === ${discriminator.size}`); } function getByteConditionFragment(discriminator, scope) { const { dataName, typeManifestVisitor } = scope; const constant = visitorsCore.visit(discriminator.constant, typeManifestVisitor).value; return constant.mapRender((r) => `containsBytes(${dataName}, ${r}, ${discriminator.offset})`).addImports("solanaCodecsCore", "containsBytes"); } function getFieldConditionFragment(discriminator, scope) { const field = scope.struct.fields.find((f) => f.name === discriminator.name); if (!field || !field.defaultValue) { throw new Error( `Field discriminator "${discriminator.name}" does not have a matching argument with default value.` ); } if (nodes.isNode(field.type, "arrayTypeNode") && nodes.isNode(field.type.item, "numberTypeNode") && field.type.item.format === "u8" && nodes.isNode(field.type.count, "fixedCountNode") && nodes.isNode(field.defaultValue, "arrayValueNode") && field.defaultValue.items.every(nodes.isNodeFilter("numberValueNode"))) { const base64Bytes = codecsStrings.getBase64Decoder().decode( new Uint8Array(field.defaultValue.items.map((node) => node.number)) ); return getByteConditionFragment( nodes.constantDiscriminatorNode(nodes.constantValueNodeFromBytes("base64", base64Bytes), discriminator.offset), scope ); } return getByteConditionFragment( nodes.constantDiscriminatorNode(nodes.constantValueNode(field.type, field.defaultValue), discriminator.offset), scope ); } function getInstructionAccountMetaFragment(instructionAccountNode) { const typeParam = `TAccount${nodes.pascalCase(instructionAccountNode.name)}`; if (instructionAccountNode.isSigner === true && instructionAccountNode.isWritable) { return fragment(`WritableSignerAccount<${typeParam}> & IAccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type WritableSignerAccount"]).addImports("solanaSigners", ["type IAccountSignerMeta"]); } if (instructionAccountNode.isSigner === true) { return fragment(`ReadonlySignerAccount<${typeParam}> & IAccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type ReadonlySignerAccount"]).addImports("solanaSigners", ["type IAccountSignerMeta"]); } if (instructionAccountNode.isWritable) { return fragment(`WritableAccount<${typeParam}>`).addImports("solanaInstructions", "type WritableAccount"); } return fragment(`ReadonlyAccount<${typeParam}>`).addImports("solanaInstructions", "type ReadonlyAccount"); } function getInstructionAccountTypeParamFragment(scope) { const { instructionAccountPath, allowAccountMeta, linkables } = scope; const instructionAccountNode = visitorsCore.getLastNodeFromPath(instructionAccountPath); const instructionNode = visitorsCore.findInstructionNodeFromPath(instructionAccountPath); const programNode = visitorsCore.findProgramNodeFromPath(instructionAccountPath); const typeParam = `TAccount${nodes.pascalCase(instructionAccountNode.name)}`; const accountMeta = allowAccountMeta ? " | IAccountMeta" : ""; const imports = new ImportMap(); if (allowAccountMeta) { imports.add("solanaInstructions", "type IAccountMeta"); } if (instructionNode.optionalAccountStrategy === "omitted" && instructionAccountNode.isOptional) { return fragment(`${typeParam} extends string${accountMeta} | undefined = undefined`, imports); } const defaultAddress = getDefaultAddress(instructionAccountNode.defaultValue, programNode.publicKey, linkables); return fragment(`${typeParam} extends string${accountMeta} = ${defaultAddress}`, imports); } function getDefaultAddress(defaultValue, programId, linkables) { switch (defaultValue?.kind) { case "publicKeyValueNode": return `"${defaultValue.publicKey}"`; case "programLinkNode": const programNode = linkables.get([defaultValue]); return programNode ? `"${programNode.publicKey}"` : "string"; case "programIdValueNode": return `"${programId}"`; default: return "string"; } } function getInstructionByteDeltaFragment(scope) { const { byteDeltas } = visitorsCore.getLastNodeFromPath(scope.instructionPath); const fragments = (byteDeltas ?? []).flatMap((r) => getByteDeltaFragment(r, scope)); if (fragments.length === 0) return fragment(""); return mergeFragments( fragments, (r) => `// Bytes created or reallocated by the instruction. const byteDelta: number = [${r.join(",")}].reduce((a, b) => a + b, 0);` ); } function getByteDeltaFragment(byteDelta, scope) { const bytesFragment = (() => { if (nodes.isNode(byteDelta.value, "numberValueNode")) { return getNumberValueNodeFragment(byteDelta); } if (nodes.isNode(byteDelta.value, "argumentValueNode")) { return getArgumentValueNodeFragment(byteDelta); } if (nodes.isNode(byteDelta.value, "accountLinkNode")) { return getAccountLinkNodeFragment(byteDelta, scope); } if (nodes.isNode(byteDelta.value, "resolverValueNode")) { return getResolverValueNodeFragment(byteDelta, scope); } return null; })(); if (bytesFragment === null) return []; if (byteDelta.withHeader) { bytesFragment.mapRender((r) => `${r} + BASE_ACCOUNT_SIZE`).addImports("solanaAccounts", "BASE_ACCOUNT_SIZE"); } if (byteDelta.subtract) { bytesFragment.mapRender((r) => `- (${r})`); } return [bytesFragment]; } function getNumberValueNodeFragment(byteDelta) { nodes.assertIsNode(byteDelta.value, "numberValueNode"); return fragment(byteDelta.value.number.toString()); } function getArgumentValueNodeFragment(byteDelta) { nodes.assertIsNode(byteDelta.value, "argumentValueNode"); const argumentName = nodes.camelCase(byteDelta.value.name); return fragment(`Number(args.${argumentName})`); } function getAccountLinkNodeFragment(byteDelta, scope) { nodes.assertIsNode(byteDelta.value, "accountLinkNode"); const functionName = scope.nameApi.accountGetSizeFunction(byteDelta.value.name); return fragment(`${functionName}()`).addImports(scope.getImportFrom(byteDelta.value), functionName); } function getResolverValueNodeFragment(byteDelta, scope) { nodes.assertIsNode(byteDelta.value, "resolverValueNode"); const isAsync = scope.asyncResolvers.includes(byteDelta.value.name); if (!scope.useAsync && isAsync) return null; const awaitKeyword = scope.useAsync && isAsync ? "await " : ""; const functionName = scope.nameApi.resolverFunction(byteDelta.value.name); return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(byteDelta.value), functionName).addFeatures(["instruction:resolverScopeVariable"]); } function getInstructionDataFragment(scope) { const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) { return fragment(""); } const instructionDataName = nameApi.instructionDataType(instructionNode.name); return getTypeWithCodecFragment({ manifest: dataArgsManifest, name: instructionDataName, nameApi }); } function getDiscriminatorConstantsFragment(scope) { const fragments = scope.discriminatorNodes.map((node) => getDiscriminatorConstantFragment(node, scope)).filter(Boolean); return mergeFragments(fragments, (r) => r.join("\n\n")); } function getDiscriminatorConstantFragment(discriminatorNode, scope) { switch (discriminatorNode.kind) { case "constantDiscriminatorNode": return getConstantDiscriminatorConstantFragment(discriminatorNode, scope); case "fieldDiscriminatorNode": return getFieldDiscriminatorConstantFragment(discriminatorNode, scope); default: return null; } } function getConstantDiscriminatorConstantFragment(discriminatorNode, scope) { const { discriminatorNodes, typeManifestVisitor, prefix } = scope; const index = discriminatorNodes.filter(nodes.isNodeFilter("constantDiscriminatorNode")).indexOf(discriminatorNode); const suffix = index <= 0 ? "" : `_${index + 1}`; const name = nodes.camelCase(`${prefix}_discriminator${suffix}`); const encoder = visitorsCore.visit(discriminatorNode.constant.type, typeManifestVisitor).encoder; const value = visitorsCore.visit(discriminatorNode.constant.value, typeManifestVisitor).value; return getConstantFragment({ ...scope, encoder, name, value }); } function getFieldDiscriminatorConstantFragment(discriminatorNode, scope) { const { fields, prefix, typeManifestVisitor } = scope; const field = fields.find((f) => f.name === discriminatorNode.name); if (!field || !field.defaultValue || !nodes.isNode(field.defaultValue, nodes.VALUE_NODES)) { return null; } const name = nodes.camelCase(`${prefix}_${discriminatorNode.name}`); const encoder = visitorsCore.visit(field.type, typeManifestVisitor).encoder; const value = visitorsCore.visit(field.defaultValue, typeManifestVisitor).value; return getConstantFragment({ ...scope, encoder, name, value }); } function getConstantFragment(scope) { const { encoder, name, nameApi, value } = scope; const constantName = nameApi.constant(name); const constantFunction = nameApi.constantFunction(name); return mergeFragments( [ value.mapRender((r) => `export const ${constantName} = ${r};`), encoder.mapRender((r) => `export function ${constantFunction}() { return ${r}.encode(${constantName}); }`) ], (r) => r.join("\n\n") ); } function getInstructionExtraArgsFragment(scope) { const { instructionPath, extraArgsManifest, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); if ((instructionNode.extraArguments ?? []).length === 0) { return fragment(""); } const instructionExtraName = nameApi.instructionExtraType(instructionNode.name); return fragmentFromTemplate("instructionExtraArgs.njk", { looseName: nameApi.dataArgsType(instructionExtraName), manifest: extraArgsManifest, strictName: nameApi.dataType(instructionExtraName) }).mergeImportsWith(extraArgsManifest.looseType); } function getInstructionInputDefaultFragment(scope) { const { input, optionalAccountStrategy, asyncResolvers, useAsync, nameApi, typeManifestVisitor, getImportFrom } = scope; if (!input.defaultValue) { return fragment(""); } if (!useAsync && isAsyncDefaultValue(input.defaultValue, asyncResolvers)) { return fragment(""); } const { defaultValue } = input; const defaultFragment = (renderedValue, isWritable) => { const inputName = nodes.camelCase(input.name); if (input.kind === "instructionAccountNode" && nodes.isNode(defaultValue, "resolverValueNode")) { return fragment(`accounts.${inputName} = { ...accounts.${inputName}, ...${renderedValue} };`); } if (input.kind === "instructionAccountNode" && isWritable === void 0) { return fragment(`accounts.${inputName}.value = ${renderedValue};`); } if (input.kind === "instructionAccountNode") { return fragment( `accounts.${inputName}.value = ${renderedValue}; accounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}` ); } return fragment(`args.${inputName} = ${renderedValue};`); }; switch (defaultValue.kind) { case "accountValueNode": const name = nodes.camelCase(defaultValue.name); if (input.kind === "instructionAccountNode" && input.resolvedIsSigner && !input.isSigner) { return defaultFragment(`expectTransactionSigner(accounts.${name}.value).address`).addImports( "shared", "expectTransactionSigner" ); } if (input.kind === "instructionAccountNode") { return defaultFragment(`expectSome(accounts.${name}.value)`).addImports("shared", "expectSome"); } return defaultFragment(`expectAddress(accounts.${name}.value)`).addImports("shared", "expectAddress"); case "pdaValueNode": if (nodes.isNode(defaultValue.pda, "pdaNode")) { const pdaProgram = defaultValue.pda.programId ? fragment( `'${defaultValue.pda.programId}' as Address<'${defaultValue.pda.programId}'>` ).addImports("solanaAddresses", "type Address") : fragment("programAddress"); const pdaSeeds2 = defaultValue.pda.seeds.flatMap((seed) => { if (nodes.isNode(seed, "constantPdaSeedNode") && nodes.isNode(seed.value, "programIdValueNode")) { return [ fragment(`getAddressEncoder().encode(${pdaProgram})`).mergeImportsWith(pdaProgram).addImports("solanaAddresses", "getAddressEncoder") ]; } if (nodes.isNode(seed, "constantPdaSeedNode") && !nodes.isNode(seed.value, "programIdValueNode")) { const typeManifest2 = visitorsCore.visit(seed.type, typeManifestVisitor); const valueManifest2 = visitorsCore.visit(seed.value, typeManifestVisitor); return [ fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith( typeManifest2.encoder, valueManifest2.value ) ]; } if (nodes.isNode(seed, "variablePdaSeedNode")) { const typeManifest2 = visitorsCore.visit(seed.type, typeManifestVisitor); const valueSeed = defaultValue.seeds.find((s) => s.name === seed.name)?.value; if (!valueSeed) return []; if (nodes.isNode(valueSeed, "accountValueNode")) { return [ fragment( `${typeManifest2.encoder}.encode(expectAddress(accounts.${nodes.camelCase(valueSeed.name)}.value))` ).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectAddress") ]; } if (nodes.isNode(valueSeed, "argumentValueNode")) { return [ fragment( `${typeManifest2.encoder}.encode(expectSome(args.${nodes.camelCase(valueSeed.name)}))` ).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectSome") ]; } const valueManifest2 = visitorsCore.visit(valueSeed, typeManifestVisitor); return [ fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith( typeManifest2.encoder, valueManifest2.value ) ]; } return []; }); const pdaStatement = mergeFragments([pdaProgram, ...pdaSeeds2], ([p, ...s]) => { const programAddress2 = p === "programAddress" ? p : `programAddress: ${p}`; return `await getProgramDerivedAddress({ ${programAddress2}, seeds: [${s.join(", ")}] })`; }).addImports("solanaAddresses", "getProgramDerivedAddress"); return defaultFragment(pdaStatement.render).mergeImportsWith(pdaStatement); } const pdaFunction = nameApi.pdaFindFunction(defaultValue.pda.name); const pdaArgs = []; const pdaSeeds = defaultValue.seeds.map((seed) => { if (nodes.isNode(seed.value, "accountValueNode")) { return fragment( `${seed.name}: expectAddress(accounts.${nodes.camelCase(seed.value.name)}.value)` ).addImports("shared", "expectAddress"); } if (nodes.isNode(seed.value, "argumentValueNode")) { return fragment(`${seed.name}: expectSome(args.${nodes.camelCase(seed.value.name)})`).addImports( "shared", "expectSome" ); } return visitorsCore.visit(seed.value, typeManifestVisitor).value.mapRender((r) => `${seed.name}: ${r}`); }); const pdaSeedsFragment = mergeFragments(pdaSeeds, (renders) => renders.join(", ")).mapRender((r) => `{ ${r} }`); if (pdaSeeds.length > 0) { pdaArgs.push(pdaSeedsFragment.render); } return defaultFragment(`await ${pdaFunction}(${pdaArgs.join(", ")})`).mergeImportsWith(pdaSeedsFragment).addImports(getImportFrom(defaultValue.pda), pdaFunction); case "publicKeyValueNode": return defaultFragment(`'${defaultValue.publicKey}' as Address<'${defaultValue.publicKey}'>`).addImports( "solanaAddresses", "type Address" ); case "programLinkNode": const programAddress = nameApi.programAddressConstant(defaultValue.name); return defaultFragment(programAddress, false).addImports(getImportFrom(defaultValue), programAddress); case "programIdValueNode": if (optionalAccountStrategy === "programId" && input.kind === "instructionAccountNode" && input.isOptional) { return fragment(""); } return defaultFragment("programAddress", false); case "identityValueNode": case "payerValueNode": return fragment(""); case "accountBumpValueNode": return defaultFragment( `expectProgramDerivedAddress(accounts.${nodes.camelCase(defaultValue.name)}.value)[1]` ).addImports("shared", "expectProgramDerivedAddress"); case "argumentValueNode": return defaultFragment(`expectSome(args.${nodes.camelCase(defaultValue.name)})`).addImports( "shared", "expectSome" ); case "resolverValueNode": const resolverFunction = nameApi.resolverFunction(defaultValue.name); const resolverAwait = useAsync && asyncResolvers.includes(defaultValue.name) ? "await " : ""; return defaultFragment(`${resolverAwait}${resolverFunction}(resolverScope)`).addImports(getImportFrom(defaultValue), resolverFunction).addFeatures(["instruction:resolverScopeVariable"]); case "conditionalValueNode": const ifTrueRenderer = renderNestedInstructionDefault({ ...scope, defaultValue: defaultValue.ifTrue }); const ifFalseRenderer = renderNestedInstructionDefault({ ...scope, defaultValue: defaultValue.ifFalse }); if (!ifTrueRenderer && !ifFalseRenderer) { return fragment(""); } const conditionalFragment = fragment(""); if (ifTrueRenderer) { conditionalFragment.mergeImportsWith(ifTrueRenderer).mergeFeaturesWith(ifTrueRenderer); } if (ifFalseRenderer) { conditionalFragment.mergeImportsWith(ifFalseRenderer).mergeFeaturesWith(ifFalseRenderer); } const negatedCondition = !ifTrueRenderer; let condition = "true"; if (nodes.isNode(defaultValue.condition, "resolverValueNode")) { const conditionalResolverFunction = nameApi.resolverFunction(defaultValue.condition.name); conditionalFragment.addImports(getImportFrom(defaultValue.condition), conditionalResolverFunction).addFeatures(["instruction:resolverScopeVariable"]); const conditionalResolverAwait = useAsync && asyncResolvers.includes(defaultValue.condition.name) ? "await " : ""; condition = `${conditionalResolverAwait}${conditionalResolverFunction}(resolverScope)`; condition = negatedCondition ? `!${condition}` : condition; } else { const comparedInputName = nodes.isNode(defaultValue.condition, "accountValueNode") ? `accounts.${nodes.camelCase(defaultValue.condition.name)}.value` : `args.${nodes.camelCase(defaultValue.condition.name)}`; if (defaultValue.value) { const comparedValue = visitorsCore.visit(defaultValue.value, typeManifestVisitor).value; conditionalFragment.mergeImportsWith(comparedValue).mergeFeaturesWith(comparedValue); const operator = negatedCondition ? "!==" : "==="; condition = `${comparedInputName} ${operator} ${comparedValue.render}`; } else { condition = negatedCondition ? `!${comparedInputName}` : comparedInputName; } } if (ifTrueRenderer && ifFalseRenderer) { return conditionalFragment.setRender( `if (${condition}) { ${ifTrueRenderer.render} } else { ${ifFalseRenderer.render} }` ); } return conditionalFragment.setRender( `if (${condition}) { ${ifTrueRenderer ? ifTrueRenderer.render : ifFalseRenderer?.render} }` ); default: const valueManifest = visitorsCore.visit(defaultValue, typeManifestVisitor).value; return defaultFragment(valueManifest.render).mergeImportsWith(valueManifest); } } function renderNestedInstructionDefault(scope) { const { input, defaultValue } = scope; if (!defaultValue) return void 0; return getInstructionInputDefaultFragment({ ...scope, input: { ...input, defaultValue } }); } // src/fragments/instructionInputResolved.ts function getInstructionInputResolvedFragment(scope) { const instructionNode = visitorsCore.getLastNodeFromPath(scope.instructionPath); const resolvedInputFragments = scope.resolvedInputs.flatMap((input) => { const inputFragment = getInstructionInputDefaultFragment({ ...scope, input, optionalAccountStrategy: instructionNode.optionalAccountStrategy }); if (!inputFragment.render) return []; const camelName = nodes.camelCase(input.name); return [ inputFragment.mapRender( (r) => nodes.isNode(input, "instructionArgumentNode") ? `if (!args.${camelName}) { ${r} }` : `if (!accounts.${camelName}.value) { ${r} }` ) ]; }); if (resolvedInputFragments.length === 0) { return fragment(""); } return mergeFragments( [fragment("// Resolve default values."), ...resolvedInputFragments], (renders) => renders.join("\n") ); } function getInstructionInputTypeFragment(scope) { const { instructionPath, useAsync, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const instructionInputType = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name); const accountsFragment = getAccountsFragment(scope); const [dataArgumentsFragment, customDataArgumentsFragment] = getDataArgumentsFragments(scope); const extraArgumentsFragment = getExtraArgumentsFragment(scope); const remainingAccountsFragment = getRemainingAccountsFragment(instructionNode); return fragmentFromTemplate("instructionInputType.njk", { accountsFragment, customDataArgumentsFragment, dataArgumentsFragment, extraArgumentsFragment, instruction: instructionNode, instructionInputType, remainingAccountsFragment }).mergeImportsWith( accountsFragment, dataArgumentsFragment, customDataArgumentsFragment, extraArgumentsFragment, remainingAccountsFragment ).addImports("solanaAddresses", ["type Address"]); } function getAccountsFragment(scope) { const { instructionPath, resolvedInputs, useAsync, asyncResolvers } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const fragments = instructionNode.accounts.map((account) => { const resolvedAccount = resolvedInputs.find( (input) => input.kind === "instructionAccountNode" && input.name === account.name ); const hasDefaultValue = !!resolvedAccount.defaultValue && !nodes.isNode(resolvedAccount.defaultValue, ["identityValueNode", "payerValueNode"]) && (useAsync || !isAsyncDefaultValue(resolvedAccount.defaultValue, asyncResolvers)); const docblock = account.docs.length > 0 ? jsDocblock(account.docs) : ""; const optionalSign = hasDefaultValue || resolvedAccount.isOptional ? "?" : ""; return getAccountTypeFragment2(resolvedAccount).mapRender( (r) => `${docblock}${nodes.camelCase(account.name)}${optionalSign}: ${r};` ); }); return mergeFragments(fragments, (r) => r.join("\n")); } function getAccountTypeFragment2(account) { const typeParam = `TAccount${nodes.pascalCase(account.name)}`; if (account.isPda && account.isSigner === false) { return fragment(`ProgramDerivedAddress<${typeParam}>`).addImports("solanaAddresses", [ "type ProgramDerivedAddress" ]); } if (account.isPda && account.isSigner === "either") { return fragment(`ProgramDerivedAddress<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type ProgramDerivedAddress"]).addImports("solanaSigners", ["type TransactionSigner"]); } if (account.isSigner === "either") { return fragment(`Address<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type Address"]).addImports("solanaSigners", ["type TransactionSigner"]); } if (account.isSigner) { return fragment(`TransactionSigner<${typeParam}>`).addImports("solanaSigners", ["type TransactionSigner"]); } return fragment(`Address<${typeParam}>`).addImports("solanaAddresses", ["type Address"]); } function getDataArgumentsFragments(scope) { const { instructionPath, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const customData = scope.customInstructionData.get(instructionNode.name); if (customData) { return [ fragment(""), fragment(nameApi.dataArgsType(customData.importAs)).mergeImportsWith(scope.dataArgsManifest.looseType).mapRender((r) => `${r} & `) ]; } const instructionDataName = nameApi.instructionDataType(instructionNode.name); const dataArgsType = nameApi.dataArgsType(instructionDataName); const fragments = instructionNode.arguments.flatMap((arg) => { const argFragment = getArgumentFragment(arg, fragment(dataArgsType), scope.resolvedInputs, scope.renamedArgs); return argFragment ? [argFragment] : []; }); return [mergeFragments(fragments, (r) => r.join("\n")), fragment("")]; } function getExtraArgumentsFragment(scope) { const { instructionPath, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const instructionExtraName = nameApi.instructionExtraType(instructionNode.name); const extraArgsType = nameApi.dataArgsType(instructionExtraName); const fragments = (instructionNode.extraArguments ?? []).flatMap((arg) => { const argFragment = getArgumentFragment(arg, fragment(extraArgsType), scope.resolvedInputs, scope.renamedArgs); return argFragment ? [argFragment] : []; }); return mergeFragments(fragments, (r) => r.join("\n")); } function getArgumentFragment(arg, argsType, resolvedInputs, renamedArgs) { const resolvedArg = resolvedInputs.find( (input) => nodes.isNode(input, "instructionArgumentNode") && input.name === arg.name ); if (arg.defaultValue && arg.defaultValueStrategy === "omitted") return null; const renamedName = renamedArgs.get(arg.name) ?? arg.name; const optionalSign = arg.defaultValue || resolvedArg?.defaultValue ? "?" : ""; return argsType.mapRender((r) => `${nodes.camelCase(renamedName)}${optionalSign}: ${r}["${nodes.camelCase(arg.name)}"];`); } function getRemainingAccountsFragment(instructionNode) { const fragments = (instructionNode.remainingAccounts ?? []).flatMap((remainingAccountsNode) => { if (nodes.isNode(remainingAccountsNode.value, "resolverValueNode")) return []; const { name } = remainingAccountsNode.value; const allArguments = nodes.getAllInstructionArguments(instructionNode); const argumentExists = allArguments.some((arg) => arg.name === name); if (argumentExists) return []; const isSigner = remainingAccountsNode.isSigner ?? false; const optionalSign = remainingAccountsNode.isOptional ?? false ? "?" : ""; const signerFragment = fragment(`TransactionSigner`).addImports("solanaSigners", ["type TransactionSigner"]); const addressFragment = fragment(`Address`).addImports("solanaAddresses", ["type Address"]); return (() => { if (isSigner === "either") { return mergeFragments([signerFragment, addressFragment], (r) => r.join(" | ")); } return isSigner ? signerFragment : addressFragment; })().mapRender((r) => `${nodes.camelCase(name)}${optionalSign}: Array<${r}>;`); }); return mergeFragments(fragments, (r) => r.join("\n")); } function getInstructionRemainingAccountsFragment(scope) { const { remainingAccounts } = visitorsCore.getLastNodeFromPath(scope.instructionPath); const fragments = (remainingAccounts ?? []).flatMap((r) => getRemainingAccountsFragment2(r, scope)); if (fragments.length === 0) return fragment(""); return mergeFragments( fragments, (r) => `// Remaining accounts. const remainingAccounts: IAccountMeta[] = ${r.length === 1 ? r[0] : `[...${r.join(", ...")}]`}` ).addImports("solanaInstructions", ["type IAccountMeta"]); } function getRemainingAccountsFragment2(remainingAccounts, scope) { const remainingAccountsFragment = (() => { if (nodes.isNode(remainingAccounts.value, "argumentValueNode")) { return getArgumentValueNodeFragment2(remainingAccounts, scope); } if (nodes.isNode(remainingAccounts.value, "resolverValueNode")) { return getResolverValueNodeFragment2(remainingAccounts, scope); } return null; })(); if (remainingAccountsFragment === null) return []; return [remainingAccountsFragment]; } function getArgumentValueNodeFragment2(remainingAccounts, scope) { const instructionNode = visitorsCore.getLastNodeFromPath(scope.instructionPath); nodes.assertIsNode(remainingAccounts.value, "argumentValueNode"); const argumentName = nodes.camelCase(remainingAccounts.value.name); const isOptional = remainingAccounts.isOptional ?? false; const isSigner = remainingAccounts.isSigner ?? false; const isWritable = remainingAccounts.isWritable ?? false; const nonSignerRole = isWritable ? "AccountRole.WRITABLE" : "AccountRole.READONLY"; const signerRole = isWritable ? "AccountRole.WRITABLE_SIGNER" : "AccountRole.READONLY_SIGNER"; const role = isSigner === true ? signerRole : nonSignerRole; const argumentArray = isOptional ? `(args.${argumentName} ?? [])` : `args.${argumentName}`; const allArguments = nodes.getAllInstructionArguments(instructionNode); const argumentExists = allArguments.some((arg) => arg.name === remainingAccounts.value.name); if (argumentExists || isSigner === false) { return fragment(`${argumentArray}.map((address) => ({ address, role: ${role} }))`).addImports( "solanaInstructions", ["AccountRole"] ); } if (isSigner === "either") { return fragment( `${argumentArray}.map((addressOrSigner) => (isTransactionSigner(addressOrSigner) ? { address: addressOrSigner.address, role: ${role}, signer: addressOrSigner } : { address: addressOrSigner, role: ${role} } ))` ).addImports("solanaInstructions", ["AccountRole"]).addImports("shared", ["isTransactionSigner"]); } return fragment( `${argumentArray}.map((signer) => ({ address: signer.address, role: ${signerRole}, signer }))` ).addImports("solanaInstructions", ["AccountRole"]); } function getResolverValueNodeFragment2(remainingAccounts, scope) { nodes.assertIsNode(remainingAccounts.value, "resolverValueNode"); const isAsync = scope.asyncResolvers.includes(remainingAccounts.value.name); if (!scope.useAsync && isAsync) return null; const awaitKeyword = scope.useAsync && isAsync ? "await " : ""; const functionName = scope.nameApi.resolverFunction(remainingAccounts.value.name); return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(remainingAccounts.value), functionName).addFeatures(["instruction:resolverScopeVariable"]); } // src/fragments/instructionFunction.ts function getInstructionFunctionFragment(scope) { const { useAsync, instructionPath, resolvedInputs, renamedArgs, dataArgsManifest, asyncResolvers, nameApi, customInstructionData } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const programNode = visitorsCore.findProgramNodeFromPath(instructionPath); if (useAsync && !hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers)) { return fragment(""); } const customData = customInstructionData.get(instructionNode.name); const hasAccounts = instructionNode.accounts.length > 0; const hasLegacyOptionalAccounts = instructionNode.optionalAccountStrategy === "omitted" && instructionNode.accounts.some((account) => account.isOptional); const instructionDependencies = getInstructionDependencies(instructionNode, asyncResolvers, useAsync); const argDependencies = instructionDependencies.filter(nodes.isNodeFilter("argumentValueNode")).map((node) => node.name); const hasData = !!customData || instructionNode.arguments.length > 0; const argIsNotOmitted = (arg) => !(arg.defaultValue && arg.defaultValueStrategy === "omitted"); const argIsDependent = (arg) => argDependencies.includes(arg.name); const argHasDefaultValue = (arg) => { if (!arg.defaultValue) return false; if (useAsync) return true; return !isAsyncDefaultValue(arg.defaultValue, asyncResolvers); }; const hasDataArgs = !!customData || instructionNode.arguments.filter(argIsNotOmitted).length > 0; const hasExtraArgs = (instructionNode.extraArguments ?? []).filter( (field) => argIsNotOmitted(field) && (argIsDependent(field) || argHasDefaultValue(field)) ).length > 0; const hasRemainingAccountArgs = (instructionNode.remainingAccounts ?? []).filter(({ value }) => nodes.isNode(value, "argumentValueNode")).length > 0; const hasAnyArgs = hasDataArgs || hasExtraArgs || hasRemainingAccountArgs; const hasInput = hasAccounts || hasAnyArgs; const instructionDataName = nameApi.instructionDataType(instructionNode.name); const programAddressConstant = nameApi.programAddressConstant(programNode.name); const encoderFunction = customData ? dataArgsManifest.encoder.render : `${nameApi.encoderFunction(instructionDataName)}()`; const argsTypeFragment = fragment( customData ? dataArgsManifest.looseType.render : nameApi.dataArgsType(instructionDataName) ); if (customData) { argsTypeFragment.mergeImportsWith(dataArgsManifest.looseType, dataArgsManifest.encoder); } const functionName = useAsync ? nameApi.instructionAsyncFunction(instructionNode.name) : nameApi.instructionSyncFunction(instructionNode.name); const typeParamsFragment = getTypeParams(instructionNode, programAddressConstant); const instructionTypeFragment = getInstructionType(scope); const inputTypeFragment = getInstructionInputTypeFragment(scope); const inputTypeCallFragment = getInputTypeCall(scope); const renamedArgsText = [...renamedArgs.entries()].map(([k, v]) => `${k}: input.${v}`).join(", "); const resolvedInputsFragment = getInstructionInputResolvedFragment(scope); const remainingAccountsFragment = getInstructionRemainingAccountsFragment(scope); const byteDeltaFragment = getInstructionByteDeltaFragment(scope); const resolvedFragment = mergeFragments( [resolvedInputsFragment, remainingAccountsFragment, byteDeltaFragment], (renders) => renders.join("\n\n") ); const hasRemainingAccounts = remainingAccountsFragment.render !== ""; const hasByteDeltas = byteDeltaFragment.render !== ""; const hasResolver = resolvedFragment.hasFeatures("instruction:resolverScopeVariable"); const getReturnType = (instructionType) => { let returnType = instructionType; if (hasByteDeltas) { returnType = `${returnType} & IInstructionWithByteDelta`; } return useAsync ? `Promise<${returnType}>` : returnType; }; const functionFragment = fragmentFromTemplate("instructionFunction.njk", { argsTypeFragment, encoderFunction, functionName, getReturnType, hasAccounts, hasAnyArgs, hasByteDeltas, hasData, hasDataArgs, hasExtraArgs, hasInput, hasLegacyOptionalAccounts, hasRemainingAccounts, hasResolver, inputTypeCallFragment, inputTypeFragment, instruction: instructionNode, instructionTypeFragment, programAddressConstant, renamedArgs: renamedArgsText, resolvedFragment, typeParamsFragment, useAsync }).mergeImportsWith( typeParamsFragment, instructionTypeFragment, inputTypeFragment, inputTypeCallFragment, resolvedFragment, argsTypeFragment ).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaAddresses", ["type Address"]); if (hasAccounts) { functionFragment.addImports("solanaInstructions", ["type IAccountMeta"]).addImports("shared", ["getAccountMetaFactory", "type ResolvedAccount"]); } if (hasByteDeltas) { functionFragment.addImports("shared", ["type IInstructionWithByteDelta"]); } return functionFragment; } function getTypeParams(instructionNode, programAddressConstant) { const typeParams = instructionNode.accounts.map((account) => `TAccount${nodes.pascalCase(account.name)} extends string`); typeParams.push(`TProgramAddress extends Address = typeof ${programAddressConstant}`); return fragment(typeParams.filter((x) => !!x).join(", ")).mapRender((r) => `<${r}>`).addImports("generatedPrograms", [programAddressConstant]); } function getInstructionType(scope) { const { instructionPath, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const instructionTypeName = nameApi.instructionType(instructionNode.name); const programAddressFragment = fragment("TProgramAddress"); const accountTypeParamsFragments = instructionNode.accounts.map((account) => { const typeParam = `TAccount${nodes.pascalCase(account.name)}`; const camelName = nodes.camelCase(account.name); if (account.isSigner === "either") { const signerRole = account.isWritable ? "WritableSignerAccount" : "ReadonlySignerAccount"; return fragment( `typeof input["${camelName}"] extends TransactionSigner<${typeParam}> ? ${signerRole}<${typeParam}> & IAccountSignerMeta<${typeParam}> : ${typeParam}` ).addImports("solanaInstructions", [`type ${signerRole}`]).addImports("solanaSigners", ["type IAccountSignerMeta"]); } return fragment(typeParam); }); return mergeFragments( [programAddressFragment, ...accountTypeParamsFragments], (renders) => renders.join(", ") ).mapRender((r) => `${instructionTypeName}<${r}>`); } function getInputTypeCall(scope) { const { instructionPath, useAsync, nameApi } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const inputTypeName = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name); if (instructionNode.accounts.length === 0) return fragment(inputTypeName); const accountTypeParams = instructionNode.accounts.map((account) => `TAccount${nodes.pascalCase(account.name)}`).join(", "); return fragment(`${inputTypeName}<${accountTypeParams}>`); } function getInstructionParseFunctionFragment(scope) { const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const programNode = visitorsCore.findProgramNodeFromPath(instructionPath); const customData = customInstructionData.get(instructionNode.name); const hasAccounts = instructionNode.accounts.length > 0; const hasOptionalAccounts = instructionNode.accounts.some((account) => account.isOptional); const minimumNumberOfAccounts = instructionNode.optionalAccountStrategy === "omitted" ? instructionNode.accounts.filter((account) => !account.isOptional).length : instructionNode.accounts.length; const hasData = !!customData || instructionNode.arguments.length > 0; const instructionDataName = nameApi.instructionDataType(instructionNode.name); const programAddressConstant = nameApi.programAddressConstant(programNode.name); const dataTypeFragment = fragment( customData ? dataArgsManifest.strictType.render : nameApi.dataType(instructionDataName) ); const decoderFunction = customData ? dataArgsManifest.decoder.render : `${nameApi.decoderFunction(instructionDataName)}()`; if (customData) { dataTypeFragment.mergeImportsWith(dataArgsManifest.strictType, dataArgsManifest.decoder); } return fragmentFromTemplate("instructionParseFunction.njk", { dataTypeFragment, decoderFunction, hasAccounts, hasData, hasOptionalAccounts, instruction: instructionNode, instructionParseFunction: nameApi.instructionParseFunction(instructionNode.name), instructionParsedType: nameApi.instructionParsedType(instructionNode.name), minimumNumberOfAccounts, programAddressConstant }).mergeImportsWith(dataTypeFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", ["type IInstruction"]).addImports("solanaInstructions", hasAccounts ? ["type IInstructionWithAccounts", "type IAccountMeta"] : []).addImports("solanaInstructions", hasData ? ["type IInstructionWithData"] : []); } function getInstructionTypeFragment(scope) { const { instructionPath, nameApi, customInstructionData } = scope; const instructionNode = visitorsCore.getLastNodeFromPath(instructionPath); const programNode = visitorsCore.findProgramNodeFromPath(instructionPath); const hasAccounts = instructionNode.accounts.length > 0; const customData = customInstructionData.get(instructionNode.name); const hasData = !!customData || instructionNode.arguments.length > 0; const instructionDataName = nameApi.instructionDataType(instructionNode.name); const programAddressConstant = nameApi.programAddressConstant(programNode.name); const dataType = customData ? nodes.pascalCase(customData.importAs) : nodes.pascalCase(instructionDataName); const accountTypeParamsFragment = mergeFragments( instructionNode.accounts.map( (account) => getInstructionAccountTypeParamFragment({ ...scope, allowAccountMeta: true, instructionAccountPath: [...instructionPath, account] }) ), (renders) => renders.join(", ") ); const usesLegacyOptionalAccounts = instructionNode.optionalAccountStrategy === "omitted"; const accountMetasFragment = mergeFragments( instructionNode.accounts.map( (account) => getInstructionAccountMetaFragment(account).mapRender((r) => { const typeParam = `TAccount${nodes.pascalCase(account.name)}`; const isLegacyOptional = account.isOptional && usesLegacyOptionalAccounts; const type = `${typeParam} extends string ? ${r} : ${typeParam}`; if (!isLegacyOptional) return type; return `...(${typeParam} extends undefined ? [] : [${type}])`; }) ), (renders) => renders.join(", ") ); const fragment2 = fragmentFromTemplate("instructionType.njk", { accountMetas: accountMetasFragment.render, accountTypeParams: accountTypeParamsFragment.render, dataType, hasAccounts, hasData, instruction: instructionNode, instructionType: nameApi.instructionType(instructionNode.name), programAddressConstant }).mergeImportsWith(accountTypeParamsFragment, accountMetasFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", [ "type IAccountMeta", "type IInstruction", "type IInstructionWithAccounts", ...hasData ? ["type IInstructionWithData"] : [] ]); return fragment2; } function getPdaFunctionFragment(scope) { const { pdaPath, typeManifestVisitor, nameApi } = scope; const pdaNode = visitorsCore.getLastNodeFromPath(pdaPath); const programNode = visitorsCore.findProgramNodeFromPath(pdaPath); const imports = new ImportMap(); const seeds = pdaNode.seeds.map((seed) => { if (nodes.isNode(seed, "variablePdaSeedNode")) { const seedManifest2 = visitorsCore.visit(seed.type, typeManifestVisitor); imports.mergeWith(seedManifest2.looseType, seedManifest2.encoder); return { ...seed, typeManifest: seedManifest2 }; } if (nodes.isNode(seed.value, "programIdValueNode")) { imports.add("solanaAddresses", "getAddressEncoder"); return seed; } const seedManifest = visitorsCore.visit(seed.type, typeManifestVisitor); imports.mergeWith(seedManifest.encoder); const valueManifest = visitorsCore.visit(seed.value, typeManifestVisitor).value; imports.mergeWith(valueManifest.imports); return { ...seed, typeManifest: seedManifest, valueManifest }; }); const hasVariableSeeds = pdaNode.seeds.filter(nodes.isNodeFilter("variablePdaSeedNode")).length > 0; return fragmentFromTemplate("pdaFunction.njk", { findPdaFunction: nameApi.pdaFindFunction(pdaNode.name), hasVariableSeeds, pdaSeedsType: nameApi.pdaSeedsType(pdaNode.name), programAddress: pdaNode.programId ?? programNode.publicKey, seeds }).mergeImportsWith(imports).addImports("solanaAddresses", ["type Address", "getProgramDerivedAddress", "type ProgramDerivedAddress"]); } // src/fragments/program.ts function getProgramFragment(scope) { const { programNode, nameApi } = scope; return fragmentFromTemplate("program.njk", { program: programNode, programAddressConstant: nameApi.programAddressConstant(programNode.name) }).addImports("solanaAddresses", ["type Address"]); } function getProgramAccountsFragment(scope) { if (scope.programNode.accounts.length === 0) return fragment(""); return mergeFragments( [getProgramAccountsEnumFragment(scope), getProgramAccountsIdentifierFunctionFragment(scope)], (r) => `${r.join("\n\n")} ` ); } function getProgramAccountsEnumFragment(scope) { const { programNode, nameApi } = scope; const programAccountsEnum = nameApi.programAccountsEnum(programNode.name); const programAccountsEnumVariants = programNode.accounts.map( (account) => nameApi.programAccountsEnumVariant(account.name) ); return fragment(`export enum ${programAccountsEnum} { ${programAccountsEnumVariants.join(", ")} }`); } function getProgramAccountsIdentifierFunctionFragment(scope) { const { programNode, nameApi } = scope; const accountsWithDiscriminators = programNode.accounts.filter( (account) => (account.discriminators ?? []).length > 0 ); const hasAccountDiscriminators = accountsWithDiscriminators.length > 0; if (!hasAccountDiscriminators) return fragment(""); const programAccountsEnum = nameApi.programAccountsEnum(programNode.name); const programAccountsIdentifierFunction = nameApi.programAccountsIdentifierFunction(programNode.name); const discriminatorsFragment = mergeFragments( accountsWithDiscriminators.map((account) => { const variant = nameApi.programAccountsEnumVariant(account.name); return getDiscriminatorConditionFragment({ ...scope, dataName: "data", discriminators: account.discriminators ?? [], ifTrue: `return ${programAccountsEnum}.${variant};`, struct: nodes.resolveNestedTypeNode(account.data) }); }), (r) => r.join("\n") ); return discriminatorsFragment.mapRender( (discriminators) => `export function ${programAccountsIdentifierFunction}(account: { data: ReadonlyUint8Array } | ReadonlyUint8Array): ${programAccountsEnum} { const data = 'data' in account ? account.data : account; ${discriminators} throw new Error("The provided account could not be identified as a ${programNode.name} account.") }` ).addImports("solanaCodecsCore", "type ReadonlyUint8Array"); } // src/fragments/programErrors.ts function getProgramErrorsFragment(scope) { const { programNode, nameApi } = scope; const programAddressConstant = nameApi.programAddressConstant(programNode.name); return fragmentFromTemplate("programErrors.njk", { errors: programNode.errors, getProgramErrorConstant: (name) => nameApi.programErrorConstantPrefix(programNode.name) + nameApi.programErrorConstant(name), programAddressConstant, programErrorMessagesMap: nameApi.programErrorMessagesMap(programNode.name), programErrorUnion: nameApi.programErrorUnion(programNode.name), programGetErrorMessageFunction: nameApi.programGetErrorMessageFunction(programNode.name), programIsErrorFunction: nameApi.programIsErrorFunction(programNode.name) }).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaPrograms", ["isProgramError"]).addImports("solanaErrors", ["type SolanaError", "type SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM"]).addImports("solanaAddresses", ["type Address"]); } function getProgramInstructionsFragment(scope) { if (scope.programNode.instructions.length === 0) return fragment(""); const allInstructions = nodes.getAllInstructionsWithSubs(scope.programNode, { leavesOnly: !scope.renderParentInstructions, subInstructionsFirst: true }); const scopeWithInstructions = { ...scope, allInstructions }; return mergeFragments( [ getProgramInstructionsEnumFragment(scopeWithInstructions), getProgramInstructionsIdentifierFunctionFragment(scopeWithInstructions), getProgramInstructionsParsedUnionTypeFragment(scopeWithInstructions) ], (r) => `${r.join("\n\n")} ` ); } function getProgramInstructionsEnumFragment(scope) { const { programNode, allInstructions, nameApi } = scope; const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name); const programInstructionsEnumVariants = allInstructions.map( (instruction) => nameApi.programInstructionsEnumVariant(instruction.name) ); return fragment( `export enum ${programInstructionsEnum} { ${programInstructionsEnumVariants.join(", ")} }` ); } function getProgramInstructionsIdentifierFunctionFragment(scope) { const { programNode, nameApi, allInstructions } = scope; const instructionsWithDiscriminators = allInstructions.filter( (instruction) => (instruction.discriminators ?? []).length > 0 ); const hasInstructionDiscriminators = instructionsWithDiscriminators.length > 0; if (!hasInstructionDiscriminators) return fragment(""); const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name); const programInstructionsIdentifierFunction = nameApi.programInstructionsIdentifierFunction(programNode.name); const discriminatorsFragment = mergeFragments( instructionsWithDiscriminators.map((instruction) => { const variant = nameApi.programInstructionsEnumVariant(instruction.name); return getDiscriminatorConditionFragment({ ...scope, dataName: "data", discriminators: instruction.discriminators ?? [], ifTrue: `return ${programInstructionsEnum}.${variant};`, struct: nodes.structTypeNodeFromInstructionArgumentNodes(instruction.arguments) }); }), (r) => r.join("\n") ); return discriminatorsFragment.mapRender( (discriminators) => `export function ${programInstructionsIdentifierFunction}(instruction: { data: ReadonlyUint8Array } | ReadonlyUint8Array): ${programInstructionsEnum} { const data = 'data' in instruction ? instruction.data : instruction; ${discriminators} throw new Error("The provided instruction could not be identified as a ${programNode.name} instruction.") }` ).addImports("solanaCodecsCore", "type ReadonlyUint8Array"); } function getProgramInstructionsParsedUnionTypeFragment(scope) { const { programNode, allInstructions, nameApi } = scope; const programAddress = programNode.publicKey; const programInstructionsType = nameApi.programInstructionsParsedUnionType(programNode.name); const programInstructionsEnum = nameApi.programInstructionsEnum(programNode.name); const typeVariants = allInstructions.map((instruction) => { const instructionEnumVariant = nameApi.programInstructionsEnumVariant(instruction.name); const parsedInstructionType = nameApi.instructionParsedType(instruction.name); return fragment( `| { instructionType: ${programInstructionsEnum}.${instructionEnumVariant} } & ${parsedInstructionType}` ).addImports("generatedInstructions", `type ${parsedInstructionType}`); }); return mergeFragments( [ fragment(`export type ${programInstructionsType} =`), ...typeVariants ], (r) => r.join("\n") ); } function getTypeDiscriminatedUnionHelpersFragment(scope) { const { name, typeNode, nameApi } = scope; const isDiscriminatedUnion = nodes.isNode(typeNode, "enumTypeNode") && nodes.isDataEnum(typeNode); if (!isDiscriminatedUnion) { return fragment(""); } return fragmentFromTemplate("typeDiscriminatedUnionHelpers.njk", { discriminatedUnionDiscriminator: nameApi.discriminatedUnionDiscriminator(name), discriminatedUnionFunction: nameApi.discriminatedUnionFunction(name), getVariant: (variant) => nameApi.discriminatedUnionVariant(variant), isDiscriminatedUnionFunction: nameApi.isDiscriminatedUnionFunction(name), looseName: nameApi.dataArgsType(name), strictName: nameApi.dataType(name), typeNode }).addImports("solanaCodecsDataStructures", [ "type GetDiscriminatedUnionVariantContent", "type GetDiscriminatedUnionVariant" ]); } // src/TypeManifest.ts function typeManifest() { return { decoder: fragment(""), encoder: fragment(""), isEnum: false, looseType: fragment(""), strictType: fragment(""), value: fragment("") }; } function mergeManifests(manifests, options = {}) { const { mergeTypes, mergeCodecs, mergeValues } = options; const merge = (fragmentFn, mergeFn) => mergeFn ? mergeFragments(manifests.map(fragmentFn), mergeFn) : fragment(""); return { decoder: merge((m) => m.decoder, mergeCodecs), encoder: merge((m) => m.encoder, mergeCodecs), isEnum: false, looseType: merge((m) => m.looseType, mergeTypes), strictType: merge((m) => m.strictType, mergeTypes), value: merge((m) => m.value, mergeValues) }; } function getTypeManifestVisitor(input) { const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input; const stack = input.stack ?? new visitorsCore.NodeStack(); let parentName = null; return visitorsCore.pipe( visitorsCore.staticVisitor( () => ({ decoder: fragment(""), encoder: fragment(""), isEnum: false, looseType: fragment(""), strictType: fragment(""), value: fragment("") }), { keys: [ ...nodes.REGISTERED_TYPE_NODE_KINDS, ...nodes.REGISTERED_VALUE_NODE_KINDS, "definedTypeLinkNode", "definedTypeNode", "accountNode", "instructionNode" ] } ), (visitor) => visitorsCore.extendVisitor(visitor, { visitAccount(account, { self }) { parentName = { loose: nameApi.dataArgsType(account.name), strict: nameApi.dataType(account.name) }; const link = customAccountData.get(account.name)?.linkNode; const manifest = link ? visitorsCore.visit(link, self) : visitorsCore.visit(account.data, self); parentName = null; return manifest; }, visitAmountType(amountType, { self }) { return visitorsCore.visit(amountType.number, self); }, visitArrayType(arrayType, { self }) { const childManifest = visitorsCore.visit(arrayType.item, self); childManifest.looseType.mapRender((r) => `Array<${r}>`); childManifest.strictType.mapRender((r) => `Array<${r}>`); const sizeManifest = getArrayLikeSizeOption(arrayType.count, self); const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : ""; const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : ""; childManifest.encoder.mapRender((r) => `getArrayEncoder(${r + encoderOptions})`).mergeImportsWith(sizeManifest.encoder).addImports("solanaCodecsDataStructures", "getArrayEncoder"); childManifest.decoder.mapRender((r) => `getArrayDecoder(${r + decoderOptions})`).mergeImportsWith(sizeManifest.decoder).addImports("solanaCodecsDataStructures", "getArrayDecoder"); return childManifest; }, visitArrayValue(node, { self }) { return mergeManifests( node.items.map((v) => visitorsCore.visit(v, self)), { mergeValues: (renders) => `[${renders.join(", ")}]` } ); }, visitBooleanType(booleanType, { self }) { const encoderImports = new ImportMap().add("solanaCodecsDataStructures", "getBooleanEncoder"); const decoderImports = new ImportMap().add("solanaCodecsDataStructures", "getBooleanDecoder"); let sizeEncoder = ""; let sizeDecoder = ""; const resolvedSize = nodes.resolveNestedTypeNode(booleanType.size); if (resolvedSize.format !== "u8" || resolvedSize.endian !== "le") { const size = visitorsCore.visit(booleanType.size, self); encoderImports.mergeWith(size.encoder); decoderImports.mergeWith(size.decoder); sizeEncoder = `{ size: ${size.encoder.render} }`; sizeDecoder = `{ size: ${size.decoder.render} }`; } return { decoder: fragment(`getBooleanDecoder(${sizeDecoder})`, decoderImports), encoder: fragment(`getBooleanEncoder(${sizeEncoder})`, encoderImports), isEnum: false, looseType: fragment("boolean"), strictType: fragment("boolean"), value: fragment("") }; }, visitBooleanValue(node) { const manifest = typeManifest(); manifest.value.setRender(JSON.stringify(node.boolean)); return manifest; }, visitBytesType() { return { decoder: fragment(`getBytesDecoder()`).addImports( "solanaCodecsDataStructures", "getBytesDecoder" ), encoder: fragment(`getBytesEncoder()`).addImports( "solanaCodecsDataStructures", "getBytesEncoder" ), isEnum: false, looseType: fragment("ReadonlyUint8Array").addImports( "solanaCodecsCore", "type ReadonlyUint8Array" ), strictType: fragment("ReadonlyUint8Array").addImports( "solanaCodecsCore", "type ReadonlyUint8Array" ), value: fragment("") }; }, visitBytesValue(node) { const manifest = typeManifest(); const bytes = getBytesFromBytesValueNode(node); manifest.value.setRender(`new Uint8Array([${Array.from(bytes).join(", ")}])`); return manifest; }, visitConstantValue(node, { self }) { if (nodes.isNode(node.type, "bytesTypeNode") && nodes.isNode(node.value, "bytesValueNode")) { return visitorsCore.visit(node.value, self); } return { ...typeManifest(), value: mergeFragments( [visitorsCore.visit(node.type, self).encoder, visitorsCore.visit(node.value, self).value], ([encoderFunction, value]) => `${encoderFunction}.encode(${value})` ) }; }, visitDateTimeType(dateTimeType, { self }) { return visitorsCore.visit(dateTimeType.number, self); }, visitDefinedType(definedType, { self }) { parentName = { loose: nameApi.dataArgsType(definedType.name), strict: nameApi.dataType(definedType.name) }; const manifest = visitorsCore.visit(definedType.type, self); parentName = null; return manifest; }, visitDefinedTypeLink(node) { const strictName = nameApi.dataType(node.name); const looseName = nameApi.dataArgsType(node.name); const encoderFunction = nameApi.encoderFunction(node.name); const decoderFunction = nameApi.decoderFunction(node.name); const importFrom = getImportFrom(node); return { decoder: fragment(`${decoderFunction}()`).addImports(importFrom, decoderFunction), encoder: fragment(`${encoderFunction}()`).addImports(importFrom, encoderFunction), isEnum: false, looseType: fragment(looseName).addImports(importFrom, `type ${looseName}`), strictType: fragment(strictName).addImports(importFrom, `type ${strictName}`), value: fragment("") }; }, visitEnumEmptyVariantType(enumEmptyVariantType) { const discriminator = nameApi.discriminatedUnionDiscriminator(nodes.camelCase(parentName?.strict ?? "")); const name = nameApi.discriminatedUnionVariant(enumEmptyVariantType.name); const kindAttribute = `${discriminator}: "${name}"`; return { decoder: fragment(`['${name}', getUnitDecoder()]`).addImports( "solanaCodecsDataStructures", "getUnitDecoder" ), encoder: fragment(`['${name}', getUnitEncoder()]`).addImports( "solanaCodecsDataStructures", "getUnitEncoder" ), isEnum: false, looseType: fragment(`{ ${kindAttribute} }`), strictType: fragment(`{ ${kindAttribute} }`), value: fragment("") }; }, visitEnumStructVariantType(enumStructVariantType, { self }) { const currentParentName = parentName; const discriminator = nameApi.discriminatedUnionDiscriminator( nodes.camelCase(currentParentName?.strict ?? "") ); const name = nameApi.discriminatedUnionVariant(enumStructVariantType.name); const kindAttribute = `${discriminator}: "${name}"`; parentName = null; const structManifest = visitorsCore.visit(enumStructVariantType.struct, self); parentName = currentParentName; structManifest.strictType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`); structManifest.looseType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`); structManifest.encoder.mapRender((r) => `['${name}', ${r}]`); structManifest.decoder.mapRender((r) => `['${name}', ${r}]`); return structManifest; }, visitEnumTupleVariantType(enumTupleVariantType, { self }) { const currentParentName = parentName; const discriminator = nameApi.discriminatedUnionDiscriminator( nodes.camelCase(currentParentName?.strict ?? "") ); const name = nameApi.discriminatedUnionVariant(enumTupleVariantType.name); const kindAttribute = `${discriminator}: "${name}"`; const struct = nodes.structTypeNode([ nodes.structFieldTypeNode({ name: "fields", type: enumTupleVariantType.tuple }) ]); parentName = null; const structManifest = visitorsCore.visit(struct, self); parentName = currentParentName; structManifest.strictType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`); structManifest.looseType.mapRender((r) => `{ ${kindAttribute},${r.slice(1, -1)}}`); structManifest.encoder.mapRender((r) => `['${name}', ${r}]`); structManifest.decoder.mapRender((r) => `['${name}', ${r}]`); return structManifest; }, visitEnumType(enumType, { self }) { const currentParentName = parentName; const encoderImports = new ImportMap(); const decoderImports = new ImportMap(); const encoderOptions = []; const decoderOptions = []; const enumSize = nodes.resolveNestedTypeNode(enumType.size); if (enumSize.format !== "u8" || enumSize.endian !== "le") { const sizeManifest = visitorsCore.visit(enumType.size, self); encoderImports.mergeWith(sizeManifest.encoder); decoderImports.mergeWith(sizeManifest.decoder); encoderOptions.push(`size: ${sizeManifest.encoder.render}`); decoderOptions.push(`size: ${sizeManifest.decoder.render}`); } const discriminator = nameApi.discriminatedUnionDiscriminator( nodes.camelCase(currentParentName?.strict ?? "") ); if (!nodes.isScalarEnum(enumType) && discriminator !== "__kind") { encoderOptions.push(`discriminator: '${discriminator}'`); decoderOptions.push(`discriminator: '${discriminator}'`); } const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : ""; const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : ""; if (nodes.isScalarEnum(enumType)) { if (currentParentName === null) { throw new Error( "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." ); } const variantNames = enumType.variants.map(({ name }) => nameApi.enumVariant(name)); return { decoder: fragment( `getEnumDecoder(${currentParentName.strict + decoderOptionsAsString})`, decoderImports.add("solanaCodecsDataStructures", "getEnumDecoder") ), encoder: fragment( `getEnumEncoder(${currentParentName.strict + encoderOptionsAsString})`, encoderImports.add("solanaCodecsDataStructures", "getEnumEncoder") ), isEnum: true, looseType: fragment(`{ ${variantNames.join(", ")} }`), strictType: fragment(`{ ${variantNames.join(", ")} }`), value: fragment("") }; } const mergedManifest = mergeManifests( enumType.variants.map((variant) => visitorsCore.visit(variant, self)), { mergeCodecs: (renders) => renders.join(", "), mergeTypes: (renders) => renders.join(" | ") } ); mergedManifest.encoder.mapRender((r) => `getDiscriminatedUnionEncoder([${r}]${encoderOptionsAsString})`).mergeImportsWith(encoderImports).addImports("solanaCodecsDataStructures", ["getDiscriminatedUnionEncoder"]); mergedManifest.decoder.mapRender((r) => `getDiscriminatedUnionDecoder([${r}]${decoderOptionsAsString})`).mergeImportsWith(decoderImports).addImports("solanaCodecsDataStructures", ["getDiscriminatedUnionDecoder"]); return mergedManifest; }, visitEnumValue(node, { self }) { const manifest = typeManifest(); const enumName = nameApi.dataType(node.enum.name); const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name); const importFrom = getImportFrom(node.enum); const enumNode = linkables.get([...stack.getPath(), node.enum])?.type; const isScalar = enumNode && nodes.isNode(enumNode, "enumTypeNode") ? nodes.isScalarEnum(enumNode) : !nonScalarEnums.includes(node.enum.name); if (!node.value && isScalar) { const variantName2 = nameApi.enumVariant(node.variant); manifest.value.setRender(`${enumName}.${variantName2}`).addImports(importFrom, enumName); return manifest; } const variantName = nameApi.discriminatedUnionVariant(node.variant); if (!node.value) { manifest.value.setRender(`${enumFunction}('${variantName}')`).addImports(importFrom, enumFunction); return manifest; } manifest.value = visitorsCore.visit(node.value, self).value.mapRender((r) => `${enumFunction}('${variantName}', ${r})`).addImports(importFrom, enumFunction); return manifest; }, visitFixedSizeType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); manifest.encoder.mapRender((r) => `fixEncoderSize(${r}, ${node.size})`).addImports("solanaCodecsCore", "fixEncoderSize"); manifest.decoder.mapRender((r) => `fixDecoderSize(${r}, ${node.size})`).addImports("solanaCodecsCore", "fixDecoderSize"); return manifest; }, visitHiddenPrefixType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); const prefixes = node.prefix.map((c) => visitorsCore.visit(c, self).value); const prefixEncoders = fragment(prefixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...prefixes); const prefixDecoders = fragment(prefixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...prefixes); manifest.encoder.mapRender((r) => `getHiddenPrefixEncoder(${r}, [${prefixEncoders}])`).mergeImportsWith(prefixEncoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixEncoder"); manifest.decoder.mapRender((r) => `getHiddenPrefixDecoder(${r}, [${prefixDecoders}])`).mergeImportsWith(prefixDecoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixDecoder"); return manifest; }, visitHiddenSuffixType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); const suffixes = node.suffix.map((c) => visitorsCore.visit(c, self).value); const suffixEncoders = fragment(suffixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...suffixes); const suffixDecoders = fragment(suffixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...suffixes); manifest.encoder.mapRender((r) => `getHiddenSuffixEncoder(${r}, [${suffixEncoders}])`).mergeImportsWith(suffixEncoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixEncoder"); manifest.decoder.mapRender((r) => `getHiddenSuffixDecoder(${r}, [${suffixDecoders}])`).mergeImportsWith(suffixDecoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixDecoder"); return manifest; }, visitInstruction(instruction, { self }) { const instructionDataName = nameApi.instructionDataType(instruction.name); parentName = { loose: nameApi.dataArgsType(instructionDataName), strict: nameApi.dataType(instructionDataName) }; const link = customInstructionData.get(instruction.name)?.linkNode; const struct = nodes.structTypeNodeFromInstructionArgumentNodes(instruction.arguments); const manifest = link ? visitorsCore.visit(link, self) : visitorsCore.visit(struct, self); parentName = null; return manifest; }, visitMapEntryValue(node, { self }) { return mergeManifests([visitorsCore.visit(node.key, self), visitorsCore.visit(node.value, self)], { mergeValues: (renders) => `[${renders.join(", ")}]` }); }, visitMapType(mapType, { self }) { const key = visitorsCore.visit(mapType.key, self); const value = visitorsCore.visit(mapType.value, self); const mergedManifest = mergeManifests([key, value], { mergeCodecs: ([k, v]) => `${k}, ${v}`, mergeTypes: ([k, v]) => `Map<${k}, ${v}>` }); const sizeManifest = getArrayLikeSizeOption(mapType.count, self); const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : ""; const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : ""; mergedManifest.encoder.mapRender((r) => `getMapEncoder(${r}${encoderOptions})`).addImports("solanaCodecsDataStructures", "getMapEncoder"); mergedManifest.decoder.mapRender((r) => `getMapDecoder(${r}${decoderOptions})`).addImports("solanaCodecsDataStructures", "getMapDecoder"); return mergedManifest; }, visitMapValue(node, { self }) { const entryFragments = node.entries.map((entry) => visitorsCore.visit(entry, self)); return mergeManifests(entryFragments, { mergeValues: (renders) => `new Map([${renders.join(", ")}])` }); }, visitNoneValue() { const manifest = typeManifest(); manifest.value.setRender("none()").addImports("solanaOptions", "none"); return manifest; }, visitNumberType(numberType) { const encoderFunction = nameApi.encoderFunction(numberType.format); const decoderFunction = nameApi.decoderFunction(numberType.format); const isBigNumber = ["u64", "u128", "i64", "i128"].includes(numberType.format); const encoderImports = new ImportMap().add("solanaCodecsNumbers", encoderFunction); const decoderImports = new ImportMap().add("solanaCodecsNumbers", decoderFunction); let endianness = ""; if (numberType.endian === "be") { encoderImports.add("solanaCodecsNumbers", "Endian"); decoderImports.add("solanaCodecsNumbers", "Endian"); endianness = "{ endian: Endian.Big }"; } return { decoder: fragment(`${decoderFunction}(${endianness})`, decoderImports), encoder: fragment(`${encoderFunction}(${endianness})`, encoderImports), isEnum: false, looseType: fragment(isBigNumber ? "number | bigint" : "number"), strictType: fragment(isBigNumber ? "bigint" : "number"), value: fragment("") }; }, visitNumberValue(node) { const manifest = typeManifest(); manifest.value.setRender(JSON.stringify(node.number)); return manifest; }, visitOptionType(optionType, { self }) { const childManifest = visitorsCore.visit(optionType.item, self); childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option"); childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable"); const encoderOptions = []; const decoderOptions = []; const optionPrefix = nodes.resolveNestedTypeNode(optionType.prefix); if (optionPrefix.format !== "u8" || optionPrefix.endian !== "le") { const prefixManifest = visitorsCore.visit(optionType.prefix, self); childManifest.encoder.mergeImportsWith(prefixManifest.encoder); childManifest.decoder.mergeImportsWith(prefixManifest.decoder); encoderOptions.push(`prefix: ${prefixManifest.encoder.render}`); decoderOptions.push(`prefix: ${prefixManifest.decoder.render}`); } if (optionType.fixed) { encoderOptions.push(`noneValue: "zeroes"`); decoderOptions.push(`noneValue: "zeroes"`); } const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : ""; const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : ""; childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder"); childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder"); return childManifest; }, visitPostOffsetType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); if (node.strategy === "padded") { manifest.encoder.mapRender((r) => `padRightEncoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padRightEncoder"); manifest.decoder.mapRender((r) => `padRightDecoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padRightDecoder"); return manifest; } const fn = (() => { switch (node.strategy) { case "absolute": return node.offset < 0 ? `({ wrapBytes }) => wrapBytes(${node.offset})` : `() => ${node.offset}`; case "preOffset": return node.offset < 0 ? `({ preOffset }) => preOffset ${node.offset}` : `({ preOffset }) => preOffset + ${node.offset}`; case "relative": default: return node.offset < 0 ? `({ postOffset }) => postOffset ${node.offset}` : `({ postOffset }) => postOffset + ${node.offset}`; } })(); manifest.encoder.mapRender((r) => `offsetEncoder(${r}, { postOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetEncoder"); manifest.decoder.mapRender((r) => `offsetDecoder(${r}, { postOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetDecoder"); return manifest; }, visitPreOffsetType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); if (node.strategy === "padded") { manifest.encoder.mapRender((r) => `padLeftEncoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padLeftEncoder"); manifest.decoder.mapRender((r) => `padLeftDecoder(${r}, ${node.offset})`).addImports("solanaCodecsCore", "padLeftDecoder"); return manifest; } const fn = (() => { switch (node.strategy) { case "absolute": return node.offset < 0 ? `({ wrapBytes }) => wrapBytes(${node.offset})` : `() => ${node.offset}`; case "relative": default: return node.offset < 0 ? `({ preOffset }) => preOffset ${node.offset}` : `({ preOffset }) => preOffset + ${node.offset}`; } })(); manifest.encoder.mapRender((r) => `offsetEncoder(${r}, { preOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetEncoder"); manifest.decoder.mapRender((r) => `offsetDecoder(${r}, { preOffset: ${fn} })`).addImports("solanaCodecsCore", "offsetDecoder"); return manifest; }, visitPublicKeyType() { const imports = new ImportMap().add("solanaAddresses", "type Address"); return { decoder: fragment("getAddressDecoder()").addImports("solanaAddresses", "getAddressDecoder"), encoder: fragment("getAddressEncoder()").addImports("solanaAddresses", "getAddressEncoder"), isEnum: false, looseType: fragment("Address", imports), strictType: fragment("Address", imports), value: fragment("") }; }, visitPublicKeyValue(node) { const manifest = typeManifest(); manifest.value.setRender(`address("${node.publicKey}")`).addImports("solanaAddresses", "address"); return manifest; }, visitRemainderOptionType(node, { self }) { const childManifest = visitorsCore.visit(node.item, self); childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option"); childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable"); const encoderOptions = ["prefix: null"]; const decoderOptions = ["prefix: null"]; const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : ""; const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : ""; childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder"); childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder"); return childManifest; }, visitSentinelType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); const sentinel = visitorsCore.visit(node.sentinel, self).value; manifest.encoder.mapRender((r) => `addEncoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addEncoderSentinel"); manifest.decoder.mapRender((r) => `addDecoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addDecoderSentinel"); return manifest; }, visitSetType(setType, { self }) { const childManifest = visitorsCore.visit(setType.item, self); childManifest.strictType.mapRender((r) => `Set<${r}>`); childManifest.looseType.mapRender((r) => `Set<${r}>`); const sizeManifest = getArrayLikeSizeOption(setType.count, self); const encoderOptions = sizeManifest.encoder.render ? `, { ${sizeManifest.encoder.render} }` : ""; const decoderOptions = sizeManifest.decoder.render ? `, { ${sizeManifest.decoder.render} }` : ""; childManifest.encoder.mergeImportsWith(sizeManifest.encoder).mapRender((r) => `getSetEncoder(${r + encoderOptions})`).addImports("solanaCodecsDataStructures", "getSetEncoder"); childManifest.decoder.mergeImportsWith(sizeManifest.decoder).mapRender((r) => `getSetDecoder(${r + decoderOptions})`).addImports("solanaCodecsDataStructures", "getSetDecoder"); return childManifest; }, visitSetValue(node, { self }) { return mergeManifests( node.items.map((v) => visitorsCore.visit(v, self)), { mergeValues: (renders) => `new Set([${renders.join(", ")}])` } ); }, visitSizePrefixType(node, { self }) { const manifest = visitorsCore.visit(node.type, self); const prefix = visitorsCore.visit(node.prefix, self); manifest.encoder.mapRender((r) => `addEncoderSizePrefix(${r}, ${prefix.encoder})`).mergeImportsWith(prefix.encoder).addImports("solanaCodecsCore", "addEncoderSizePrefix"); manifest.decoder.mapRender((r) => `addDecoderSizePrefix(${r}, ${prefix.decoder})`).mergeImportsWith(prefix.decoder).addImports("solanaCodecsCore", "addDecoderSizePrefix"); return manifest; }, visitSolAmountType({ number }, { self }) { const numberManifest = visitorsCore.visit(number, self); const lamportsType = "LamportsUnsafeBeyond2Pow53Minus1"; const lamportsImport = new ImportMap().add( "solanaRpcTypes", "type LamportsUnsafeBeyond2Pow53Minus1" ); return { ...numberManifest, decoder: numberManifest.decoder.mapRender((r) => `getLamportsDecoder(${r})`).addImports("solanaRpcTypes", "getLamportsDecoder"), encoder: numberManifest.encoder.mapRender((r) => `getLamportsEncoder(${r})`).addImports("solanaRpcTypes", "getLamportsEncoder"), looseType: fragment(lamportsType, lamportsImport), strictType: fragment(lamportsType, lamportsImport) }; }, visitSomeValue(node, { self }) { const manifest = typeManifest(); manifest.value = visitorsCore.visit(node.value, self).value.mapRender((r) => `some(${r})`).addImports("solanaOptions", "some"); return manifest; }, visitStringType(stringType) { const [encoder, decoder] = (() => { switch (stringType.encoding) { case "base16": return ["getBase16Encoder", "getBase16Decoder"]; case "base58": return ["getBase58Encoder", "getBase58Decoder"]; case "base64": return ["getBase64Encoder", "getBase64Decoder"]; case "utf8": return ["getUtf8Encoder", "getUtf8Decoder"]; default: throw new Error(`Unsupported string encoding: ${stringType.encoding}`); } })(); return { decoder: fragment(`${decoder}()`).addImports("solanaCodecsStrings", decoder), encoder: fragment(`${encoder}()`).addImports("solanaCodecsStrings", encoder), isEnum: false, looseType: fragment("string"), strictType: fragment("string"), value: fragment("") }; }, visitStringValue(node) { const manifest = typeManifest(); manifest.value.setRender(JSON.stringify(node.string)); return manifest; }, visitStructFieldType(structFieldType, { self }) { const name = nodes.camelCase(structFieldType.name); const childManifest = visitorsCore.visit(structFieldType.type, self); const docblock = structFieldType.docs.length > 0 ? ` ${jsDocblock(structFieldType.docs)}` : ""; const originalLooseType = childManifest.looseType.render; childManifest.strictType.mapRender((r) => `${docblock}${name}: ${r}; `); childManifest.looseType.mapRender((r) => `${docblock}${name}: ${r}; `); childManifest.encoder.mapRender((r) => `['${name}', ${r}]`); childManifest.decoder.mapRender((r) => `['${name}', ${r}]`); if (!structFieldType.defaultValue) { return childManifest; } if (structFieldType.defaultValueStrategy !== "omitted") { childManifest.looseType.setRender(`${docblock}${name}?: ${originalLooseType}; `); return childManifest; } childManifest.looseType = fragment(""); return childManifest; }, visitStructFieldValue(node, { self }) { const manifest = typeManifest(); manifest.value = visitorsCore.visit(node.value, self).value.mapRender((r) => `${node.name}: ${r}`); return manifest; }, visitStructType(structType, { self }) { const optionalFields = structType.fields.filter((f) => !!f.defaultValue); const mergedManifest = mergeManifests( structType.fields.map((field) => visitorsCore.visit(field, self)), { mergeCodecs: (renders) => `([${renders.join(", ")}])`, mergeTypes: (renders) => `{ ${renders.join("")} }` } ); mergedManifest.encoder.mapRender((r) => `getStructEncoder${r}`).addImports("solanaCodecsDataStructures", "getStructEncoder"); mergedManifest.decoder.mapRender((r) => `getStructDecoder${r}`).addImports("solanaCodecsDataStructures", "getStructDecoder"); if (optionalFields.length === 0) { return mergedManifest; } const parentPath = stack.getPath(); const instructionNode = visitorsCore.findLastNodeFromPath(parentPath, "instructionNode"); const accountNode = visitorsCore.findLastNodeFromPath(parentPath, "accountNode"); const discriminatorPrefix = instructionNode ? instructionNode.name : accountNode?.name; const discriminators = (instructionNode ? instructionNode.discriminators : accountNode?.discriminators) ?? []; const fieldDiscriminators = discriminators.filter(nodes.isNodeFilter("fieldDiscriminatorNode")); const defaultValues = optionalFields.map((f) => { const key = nodes.camelCase(f.name); if (fieldDiscriminators.some((d) => d.name === f.name)) { const constantName = nameApi.constant(nodes.camelCase(`${discriminatorPrefix}_${f.name}`)); return f.defaultValueStrategy === "omitted" ? `${key}: ${constantName}` : `${key}: value.${key} ?? ${constantName}`; } const defaultValue = f.defaultValue; const { render: renderedValue, imports } = visitorsCore.visit(defaultValue, self).value; mergedManifest.encoder.mergeImportsWith(imports); return f.defaultValueStrategy === "omitted" ? `${key}: ${renderedValue}` : `${key}: value.${key} ?? ${renderedValue}`; }).join(", "); mergedManifest.encoder.mapRender((r) => `transformEncoder(${r}, (value) => ({ ...value, ${defaultValues} }))`).addImports("solanaCodecsCore", "transformEncoder"); return mergedManifest; }, visitStructValue(node, { self }) { return mergeManifests( node.fields.map((field) => visitorsCore.visit(field, self)), { mergeValues: (renders) => `{ ${renders.join(", ")} }` } ); }, visitTupleType(tupleType, { self }) { const items = tupleType.items.map((item) => visitorsCore.visit(item, self)); const mergedManifest = mergeManifests(items, { mergeCodecs: (codecs) => `[${codecs.join(", ")}]`, mergeTypes: (types) => `readonly [${types.join(", ")}]` }); mergedManifest.encoder.mapRender((render2) => `getTupleEncoder(${render2})`).addImports("solanaCodecsDataStructures", "getTupleEncoder"); mergedManifest.decoder.mapRender((render2) => `getTupleDecoder(${render2})`).addImports("solanaCodecsDataStructures", "getTupleDecoder"); return mergedManifest; }, visitTupleValue(node, { self }) { return mergeManifests( node.items.map((v) => visitorsCore.visit(v, self)), { mergeValues: (renders) => `[${renders.join(", ")}]` } ); }, visitZeroableOptionType(node, { self }) { const childManifest = visitorsCore.visit(node.item, self); childManifest.strictType.mapRender((r) => `Option<${r}>`).addImports("solanaOptions", "type Option"); childManifest.looseType.mapRender((r) => `OptionOrNullable<${r}>`).addImports("solanaOptions", "type OptionOrNullable"); const encoderOptions = ["prefix: null"]; const decoderOptions = ["prefix: null"]; if (node.zeroValue) { const zeroValueManifest = visitorsCore.visit(node.zeroValue, self); childManifest.encoder.mergeImportsWith(zeroValueManifest.value); childManifest.decoder.mergeImportsWith(zeroValueManifest.value); encoderOptions.push(`noneValue: ${zeroValueManifest.value.render}`); decoderOptions.push(`noneValue: ${zeroValueManifest.value.render}`); } else { encoderOptions.push(`noneValue: "zeroes"`); decoderOptions.push(`noneValue: "zeroes"`); } const encoderOptionsAsString = encoderOptions.length > 0 ? `, { ${encoderOptions.join(", ")} }` : ""; const decoderOptionsAsString = decoderOptions.length > 0 ? `, { ${decoderOptions.join(", ")} }` : ""; childManifest.encoder.mapRender((r) => `getOptionEncoder(${r + encoderOptionsAsString})`).addImports("solanaOptions", "getOptionEncoder"); childManifest.decoder.mapRender((r) => `getOptionDecoder(${r + decoderOptionsAsString})`).addImports("solanaOptions", "getOptionDecoder"); return childManifest; } }), (visitor) => visitorsCore.recordNodeStackVisitor(visitor, stack) ); } function getArrayLikeSizeOption(count, visitor) { if (nodes.isNode(count, "fixedCountNode")) { return { decoder: fragment(`size: ${count.value}`), encoder: fragment(`size: ${count.value}`) }; } if (nodes.isNode(count, "remainderCountNode")) { return { decoder: fragment(`size: 'remainder'`), encoder: fragment(`size: 'remainder'`) }; } const prefix = nodes.resolveNestedTypeNode(count.prefix); if (prefix.format === "u32" && prefix.endian === "le") { return { decoder: fragment(""), encoder: fragment("") }; } const prefixManifest = visitorsCore.visit(count.prefix, visitor); prefixManifest.encoder.mapRender((r) => `size: ${r}`); prefixManifest.decoder.mapRender((r) => `size: ${r}`); return prefixManifest; } function getNameApi(transformers) { const helpers = { camelCase: nodes.camelCase, capitalize: nodes.capitalize, kebabCase: nodes.kebabCase, pascalCase: nodes.pascalCase, snakeCase: nodes.snakeCase, titleCase: nodes.titleCase }; return Object.fromEntries( Object.entries(transformers).map(([key, transformer]) => [key, (name) => transformer(name, helpers)]) ); } var DEFAULT_NAME_TRANSFORMERS = { accountDecodeFunction: (name) => `decode${nodes.pascalCase(name)}`, accountFetchAllFunction: (name) => `fetchAll${nodes.pascalCase(name)}`, accountFetchAllMaybeFunction: (name) => `fetchAllMaybe${nodes.pascalCase(name)}`, accountFetchFromSeedsFunction: (name) => `fetch${nodes.pascalCase(name)}FromSeeds`, accountFetchFunction: (name) => `fetch${nodes.pascalCase(name)}`, accountFetchMaybeFromSeedsFunction: (name) => `fetchMaybe${nodes.pascalCase(name)}FromSeeds`, accountFetchMaybeFunction: (name) => `fetchMaybe${nodes.pascalCase(name)}`, accountGetSizeFunction: (name) => `get${nodes.pascalCase(name)}Size`, codecFunction: (name) => `get${nodes.pascalCase(name)}Codec`, constant: (name) => nodes.snakeCase(name).toUpperCase(), constantFunction: (name) => `get${nodes.pascalCase(name)}Bytes`, dataArgsType: (name) => `${nodes.pascalCase(name)}Args`, dataType: (name) => `${nodes.pascalCase(name)}`, decoderFunction: (name) => `get${nodes.pascalCase(name)}Decoder`, discriminatedUnionDiscriminator: () => "__kind", discriminatedUnionFunction: (name) => `${nodes.camelCase(name)}`, discriminatedUnionVariant: (name) => `${nodes.pascalCase(name)}`, encoderFunction: (name) => `get${nodes.pascalCase(name)}Encoder`, enumVariant: (name) => `${nodes.pascalCase(name)}`, instructionAsyncFunction: (name) => `get${nodes.pascalCase(name)}InstructionAsync`, instructionAsyncInputType: (name) => `${nodes.pascalCase(name)}AsyncInput`, instructionDataType: (name) => `${nodes.pascalCase(name)}InstructionData`, instructionExtraType: (name) => `${nodes.pascalCase(name)}InstructionExtra`, instructionParseFunction: (name) => `parse${nodes.pascalCase(name)}Instruction`, instructionParsedType: (name) => `Parsed${nodes.pascalCase(name)}Instruction`, instructionSyncFunction: (name) => `get${nodes.pascalCase(name)}Instruction`, instructionSyncInputType: (name) => `${nodes.pascalCase(name)}Input`, instructionType: (name) => `${nodes.pascalCase(name)}Instruction`, isDiscriminatedUnionFunction: (name) => `is${nodes.pascalCase(name)}`, pdaFindFunction: (name) => `find${nodes.pascalCase(name)}Pda`, pdaSeedsType: (name) => `${nodes.pascalCase(name)}Seeds`, programAccountsEnum: (name) => `${nodes.pascalCase(name)}Account`, programAccountsEnumVariant: (name) => `${nodes.pascalCase(name)}`, programAccountsIdentifierFunction: (name) => `identify${nodes.pascalCase(name)}Account`, programAddressConstant: (name) => `${nodes.snakeCase(name).toUpperCase()}_PROGRAM_ADDRESS`, programErrorConstant: (name) => nodes.snakeCase(name).toUpperCase(), programErrorConstantPrefix: (name) => `${nodes.snakeCase(name).toUpperCase()}_ERROR__`, programErrorMessagesMap: (name) => `${nodes.camelCase(name)}ErrorMessages`, programErrorUnion: (name) => `${nodes.pascalCase(name)}Error`, programGetErrorMessageFunction: (name) => `get${nodes.pascalCase(name)}ErrorMessage`, programInstructionsEnum: (name) => `${nodes.pascalCase(name)}Instruction`, programInstructionsEnumVariant: (name) => `${nodes.pascalCase(name)}`, programInstructionsIdentifierFunction: (name) => `identify${nodes.pascalCase(name)}Instruction`, programInstructionsParsedUnionType: (name) => `Parsed${nodes.pascalCase(name)}Instruction`, programIsErrorFunction: (name) => `is${nodes.pascalCase(name)}Error`, resolverFunction: (name) => `${nodes.camelCase(name)}` }; // src/getRenderMapVisitor.ts function getRenderMapVisitor(options = {}) { const linkables = new visitorsCore.LinkableDictionary(); const stack = new visitorsCore.NodeStack(); const nameTransformers = { ...DEFAULT_NAME_TRANSFORMERS, ...options.nameTransformers }; const nameApi = getNameApi(nameTransformers); const renderParentInstructions = options.renderParentInstructions ?? false; const dependencyMap = options.dependencyMap ?? {}; const useGranularImports = options.useGranularImports ?? false; const asyncResolvers = (options.asyncResolvers ?? []).map(nodes.camelCase); const nonScalarEnums = (options.nonScalarEnums ?? []).map(nodes.camelCase); const internalNodes = (options.internalNodes ?? []).map(nodes.camelCase); const customAccountData = parseCustomDataOptions(options.customAccountData ?? [], "AccountData"); const customInstructionData = parseCustomDataOptions(options.customInstructionData ?? [], "InstructionData"); const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}, customAccountData, customInstructionData); const typeManifestVisitor = getTypeManifestVisitor({ customAccountData, customInstructionData, getImportFrom, linkables, nameApi, nonScalarEnums, stack }); const resolvedInstructionInputVisitor = visitorsCore.getResolvedInstructionInputsVisitor(); const globalScope = { asyncResolvers, customAccountData, customInstructionData, getImportFrom, linkables, nameApi, nonScalarEnums, renderParentInstructions, typeManifestVisitor }; const render2 = (template, context, renderOptions) => { return render(path.join("pages", template), context, renderOptions); }; return visitorsCore.pipe( visitorsCore.staticVisitor(() => new renderersCore.RenderMap(), { keys: ["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"] }), (v) => visitorsCore.extendVisitor(v, { visitAccount(node) { const accountPath = stack.getPath("accountNode"); if (!visitorsCore.findProgramNodeFromPath(accountPath)) { throw new Error("Account must be visited inside a program."); } const scope = { ...globalScope, accountPath, typeManifest: visitorsCore.visit(node, typeManifestVisitor) }; const fields = nodes.resolveNestedTypeNode(node.data).fields; const accountDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({ ...scope, discriminatorNodes: node.discriminators ?? [], fields, prefix: node.name }); const accountTypeFragment = getAccountTypeFragment(scope); const accountFetchHelpersFragment = getAccountFetchHelpersFragment(scope); const accountSizeHelpersFragment = getAccountSizeHelpersFragment(scope); const accountPdaHelpersFragment = getAccountPdaHelpersFragment(scope); const imports = new ImportMap().mergeWith( accountDiscriminatorConstantsFragment, accountTypeFragment, accountFetchHelpersFragment, accountSizeHelpersFragment, accountPdaHelpersFragment ); return new renderersCore.RenderMap().add( `accounts/${nodes.camelCase(node.name)}.ts`, render2("accountsPage.njk", { accountDiscriminatorConstantsFragment, accountFetchHelpersFragment, accountPdaHelpersFragment, accountSizeHelpersFragment, accountTypeFragment, imports: imports.toString(dependencyMap, useGranularImports) }) ); }, visitDefinedType(node) { const scope = { ...globalScope, codecDocs: [], decoderDocs: [], encoderDocs: [], manifest: visitorsCore.visit(node, typeManifestVisitor), name: node.name, typeDocs: node.docs, typeNode: node.type }; const typeWithCodecFragment = getTypeWithCodecFragment(scope); const typeDiscriminatedUnionHelpersFragment = getTypeDiscriminatedUnionHelpersFragment(scope); const imports = new ImportMap().mergeWith(typeWithCodecFragment, typeDiscriminatedUnionHelpersFragment).remove("generatedTypes", [ nameApi.dataType(node.name), nameApi.dataArgsType(node.name), nameApi.encoderFunction(node.name), nameApi.decoderFunction(node.name), nameApi.codecFunction(node.name) ]); return new renderersCore.RenderMap().add( `types/${nodes.camelCase(node.name)}.ts`, render2("definedTypesPage.njk", { imports: imports.toString({ ...dependencyMap, generatedTypes: "." }), typeDiscriminatedUnionHelpersFragment, typeWithCodecFragment }) ); }, visitInstruction(node) { const instructionPath = stack.getPath("instructionNode"); if (!visitorsCore.findProgramNodeFromPath(instructionPath)) { throw new Error("Instruction must be visited inside a program."); } const instructionExtraName = nameApi.instructionExtraType(node.name); const scope = { ...globalScope, dataArgsManifest: visitorsCore.visit(node, typeManifestVisitor), extraArgsManifest: visitorsCore.visit( nodes.definedTypeNode({ name: instructionExtraName, type: nodes.structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? []) }), typeManifestVisitor ), instructionPath, renamedArgs: getRenamedArgsMap(node), resolvedInputs: visitorsCore.visit(node, resolvedInstructionInputVisitor) }; const instructionDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({ ...scope, discriminatorNodes: node.discriminators ?? [], fields: node.arguments, prefix: node.name }); const instructionTypeFragment = getInstructionTypeFragment(scope); const instructionDataFragment = getInstructionDataFragment(scope); const instructionExtraArgsFragment = getInstructionExtraArgsFragment(scope); const instructionFunctionAsyncFragment = getInstructionFunctionFragment({ ...scope, useAsync: true }); const instructionFunctionSyncFragment = getInstructionFunctionFragment({ ...scope, useAsync: false }); const instructionParseFunctionFragment = getInstructionParseFunctionFragment(scope); const imports = new ImportMap().mergeWith( instructionDiscriminatorConstantsFragment, instructionTypeFragment, instructionDataFragment, instructionExtraArgsFragment, instructionFunctionAsyncFragment, instructionFunctionSyncFragment, instructionParseFunctionFragment ); return new renderersCore.RenderMap().add( `instructions/${nodes.camelCase(node.name)}.ts`, render2("instructionsPage.njk", { imports: imports.toString(dependencyMap, useGranularImports), instruction: node, instructionDataFragment, instructionDiscriminatorConstantsFragment, instructionExtraArgsFragment, instructionFunctionAsyncFragment, instructionFunctionSyncFragment, instructionParseFunctionFragment, instructionTypeFragment }) ); }, visitPda(node) { const pdaPath = stack.getPath("pdaNode"); if (!visitorsCore.findProgramNodeFromPath(pdaPath)) { throw new Error("Account must be visited inside a program."); } const scope = { ...globalScope, pdaPath }; const pdaFunctionFragment = getPdaFunctionFragment(scope); const imports = new ImportMap().mergeWith(pdaFunctionFragment); return new renderersCore.RenderMap().add( `pdas/${nodes.camelCase(node.name)}.ts`, render2("pdasPage.njk", { imports: imports.toString(dependencyMap, useGranularImports), pdaFunctionFragment }) ); }, visitProgram(node, { self }) { const customDataDefinedType = [ ...getDefinedTypeNodesToExtract(node.accounts, customAccountData), ...getDefinedTypeNodesToExtract(node.instructions, customInstructionData) ]; const scope = { ...globalScope, programNode: node }; const renderMap = new renderersCore.RenderMap().mergeWith(...node.pdas.map((p) => visitorsCore.visit(p, self))).mergeWith(...node.accounts.map((a) => visitorsCore.visit(a, self))).mergeWith(...node.definedTypes.map((t) => visitorsCore.visit(t, self))).mergeWith(...customDataDefinedType.map((t) => visitorsCore.visit(t, self))); if (node.errors.length > 0) { const programErrorsFragment = getProgramErrorsFragment(scope); renderMap.add( `errors/${nodes.camelCase(node.name)}.ts`, render2("errorsPage.njk", { imports: new ImportMap().mergeWith(programErrorsFragment).toString(dependencyMap, useGranularImports), programErrorsFragment }) ); } const programFragment = getProgramFragment(scope); const programAccountsFragment = getProgramAccountsFragment(scope); const programInstructionsFragment = getProgramInstructionsFragment(scope); renderMap.add( `programs/${nodes.camelCase(node.name)}.ts`, render2("programsPage.njk", { imports: new ImportMap().mergeWith(programFragment, programAccountsFragment, programInstructionsFragment).toString(dependencyMap, useGranularImports), programAccountsFragment, programFragment, programInstructionsFragment }) ); renderMap.mergeWith( ...nodes.getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions }).map((ix) => visitorsCore.visit(ix, self)) ); return renderMap; }, visitRoot(node, { self }) { const isNotInternal = (n) => !internalNodes.includes(n.name); const programsToExport = nodes.getAllPrograms(node).filter(isNotInternal); const programsWithErrorsToExport = programsToExport.filter((p) => p.errors.length > 0); const pdasToExport = nodes.getAllPdas(node); const accountsToExport = nodes.getAllAccounts(node).filter(isNotInternal); const instructionsToExport = nodes.getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions }).filter(isNotInternal); const definedTypesToExport = nodes.getAllDefinedTypes(node).filter(isNotInternal); const hasAnythingToExport = programsToExport.length > 0 || accountsToExport.length > 0 || instructionsToExport.length > 0 || definedTypesToExport.length > 0; const ctx = { accountsToExport, definedTypesToExport, hasAnythingToExport, instructionsToExport, pdasToExport, programsToExport, programsWithErrorsToExport, root: node }; const map = new renderersCore.RenderMap(); if (hasAnythingToExport) { map.add( "shared/index.ts", render2("sharedPage.njk", { ...ctx, imports: new ImportMap().add("solanaAddresses", [ "type Address", "isProgramDerivedAddress", "type ProgramDerivedAddress" ]).add("solanaInstructions", [ "AccountRole", "type IAccountMeta", "upgradeRoleToSigner" ]).add("solanaSigners", [ "type IAccountSignerMeta", "isTransactionSigner", "type TransactionSigner" ]).addAlias("solanaSigners", "isTransactionSigner", "web3JsIsTransactionSigner").toString(dependencyMap, useGranularImports) }) ); } if (programsToExport.length > 0) { map.add("programs/index.ts", render2("programsIndex.njk", ctx)); } if (programsWithErrorsToExport.length > 0) { map.add("errors/index.ts", render2("errorsIndex.njk", ctx)); } if (accountsToExport.length > 0) { map.add("accounts/index.ts", render2("accountsIndex.njk", ctx)); } if (pdasToExport.length > 0) { map.add("pdas/index.ts", render2("pdasIndex.njk", ctx)); } if (instructionsToExport.length > 0) { map.add("instructions/index.ts", render2("instructionsIndex.njk", ctx)); } if (definedTypesToExport.length > 0) { map.add("types/index.ts", render2("definedTypesIndex.njk", ctx)); } return map.add("index.ts", render2("rootIndex.njk", ctx)).mergeWith(...nodes.getAllPrograms(node).map((p) => visitorsCore.visit(p, self))); } }), (v) => visitorsCore.recordNodeStackVisitor(v, stack), (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables) ); } function getRenamedArgsMap(instruction) { const argNames = [ ...instruction.arguments.map((a) => a.name), ...(instruction.extraArguments ?? []).map((a) => a.name) ]; const duplicateArgs = argNames.filter((e, i, a) => a.indexOf(e) !== i); if (duplicateArgs.length > 0) { throw new Error(`Duplicate args found: [${duplicateArgs.join(", ")}] in instruction [${instruction.name}].`); } const allNames = [...instruction.accounts.map((account) => account.name), ...argNames]; const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i); if (duplicates.length === 0) return /* @__PURE__ */ new Map(); errors.logWarn( `[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.` ); return new Map(duplicates.map((name) => [nodes.camelCase(name), nodes.camelCase(`${name}Arg`)])); } var DEFAULT_PRETTIER_OPTIONS = { arrowParens: "always", parser: "typescript", plugins: [estreePlugin__namespace, typeScriptPlugin__namespace], printWidth: 80, semi: true, singleQuote: true, tabWidth: 2, trailingComma: "es5", useTabs: false }; function renderVisitor(path, options = {}) { return visitorsCore.rootNodeVisitor(async (root) => { if (options.deleteFolderBeforeRendering ?? true) { renderersCore.deleteDirectory(path); } const renderMap = visitorsCore.visit(root, getRenderMapVisitor(options)); if (options.formatCode ?? true) { const prettierOptions = { ...DEFAULT_PRETTIER_OPTIONS, ...options.prettierOptions }; await renderMap.mapContentAsync((code) => standalone.format(code, prettierOptions)); } renderMap.write(path); }); } exports.DEFAULT_NAME_TRANSFORMERS = DEFAULT_NAME_TRANSFORMERS; exports.ImportMap = ImportMap; exports.getNameApi = getNameApi; exports.getRenderMapVisitor = getRenderMapVisitor; exports.getTypeManifestVisitor = getTypeManifestVisitor; exports.mergeManifests = mergeManifests; exports.renderVisitor = renderVisitor; exports.typeManifest = typeManifest; //# sourceMappingURL=index.node.cjs.map //# sourceMappingURL=index.node.cjs.map