UNPKG

@codama/renderers-js

Version:

JavaScript renderer compatible with the Solana Kit library

1,125 lines (1,085 loc) 153 kB
// src/utils/importMap.ts var DEFAULT_EXTERNAL_MODULE_MAP = { solanaAccounts: "@solana/kit", solanaAddresses: "@solana/kit", solanaCodecsCore: "@solana/kit", solanaCodecsDataStructures: "@solana/kit", solanaCodecsNumbers: "@solana/kit", solanaCodecsStrings: "@solana/kit", solanaErrors: "@solana/kit", solanaInstructions: "@solana/kit", solanaOptions: "@solana/kit", solanaPrograms: "@solana/kit", solanaRpcTypes: "@solana/kit", solanaSigners: "@solana/kit" }; 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" }; function createImportMap() { return Object.freeze(/* @__PURE__ */ new Map()); } function parseImportInput(input) { const matches = input.match(/^(type )?([^ ]+)(?: as (.+))?$/); if (!matches) return Object.freeze({ importedIdentifier: input, isType: false, usedIdentifier: input }); const [_, isType, name, alias] = matches; return Object.freeze({ importedIdentifier: name, isType: !!isType, usedIdentifier: alias ?? name }); } function addToImportMap(importMap, module, imports) { const parsedImports = imports.map(parseImportInput).map((i) => [i.usedIdentifier, i]); return mergeImportMaps([importMap, /* @__PURE__ */ new Map([[module, new Map(parsedImports)]])]); } function removeFromImportMap(importMap, module, usedIdentifiers) { const newMap = new Map(importMap); const newModuleMap = new Map(newMap.get(module)); usedIdentifiers.forEach((usedIdentifier) => { newModuleMap.delete(usedIdentifier); }); if (newModuleMap.size === 0) { newMap.delete(module); } else { newMap.set(module, newModuleMap); } return Object.freeze(newMap); } function mergeImportMaps(importMaps) { if (importMaps.length === 0) return createImportMap(); if (importMaps.length === 1) return importMaps[0]; const mergedMap = new Map(importMaps[0]); for (const map of importMaps.slice(1)) { for (const [module, imports] of map) { const mergedModuleMap = mergedMap.get(module) ?? /* @__PURE__ */ new Map(); for (const [usedIdentifier, importInfo] of imports) { const existingImportInfo = mergedModuleMap.get(usedIdentifier); const shouldOverwriteTypeOnly = existingImportInfo && existingImportInfo.importedIdentifier === importInfo.importedIdentifier && existingImportInfo.isType && !importInfo.isType; if (!existingImportInfo || shouldOverwriteTypeOnly) { mergedModuleMap.set(usedIdentifier, importInfo); } } mergedMap.set(module, mergedModuleMap); } } return Object.freeze(mergedMap); } function importMapToString(importMap, dependencyMap = {}, useGranularImports = false) { const resolvedMap = resolveImportMapModules(importMap, dependencyMap, useGranularImports); return [...resolvedMap.entries()].sort(([a], [b]) => { const relative = Number(a.startsWith(".")) - Number(b.startsWith(".")); if (relative !== 0) return relative; return a.localeCompare(b); }).map(([module, imports]) => { const innerImports = [...imports.values()].map(importInfoToString).sort((a, b) => a.localeCompare(b)).join(", "); return `import { ${innerImports} } from '${module}';`; }).join("\n"); } function resolveImportMapModules(importMap, dependencyMap, useGranularImports) { const dependencyMapWithDefaults = { ...useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP, ...DEFAULT_INTERNAL_MODULE_MAP, ...dependencyMap }; return mergeImportMaps( [...importMap.entries()].map(([module, imports]) => { const resolvedModule = dependencyMapWithDefaults[module] ?? module; return /* @__PURE__ */ new Map([[resolvedModule, imports]]); }) ); } function importInfoToString({ importedIdentifier, isType, usedIdentifier }) { const alias = importedIdentifier !== usedIdentifier ? ` as ${usedIdentifier}` : ""; return `${isType ? "type " : ""}${importedIdentifier}${alias}`; } // src/utils/nameTransformers.ts import { camelCase, capitalize, kebabCase, pascalCase, snakeCase, titleCase } from "@codama/nodes"; function getNameApi(transformers) { const helpers = { camelCase, capitalize, kebabCase, pascalCase, snakeCase, titleCase }; return Object.fromEntries( Object.entries(transformers).map(([key, transformer]) => [key, (name) => transformer(name, helpers)]) ); } var DEFAULT_NAME_TRANSFORMERS = { accountDecodeFunction: (name) => `decode${pascalCase(name)}`, accountFetchAllFunction: (name) => `fetchAll${pascalCase(name)}`, accountFetchAllMaybeFunction: (name) => `fetchAllMaybe${pascalCase(name)}`, accountFetchFromSeedsFunction: (name) => `fetch${pascalCase(name)}FromSeeds`, accountFetchFunction: (name) => `fetch${pascalCase(name)}`, accountFetchMaybeFromSeedsFunction: (name) => `fetchMaybe${pascalCase(name)}FromSeeds`, accountFetchMaybeFunction: (name) => `fetchMaybe${pascalCase(name)}`, accountGetSizeFunction: (name) => `get${pascalCase(name)}Size`, codecFunction: (name) => `get${pascalCase(name)}Codec`, constant: (name) => snakeCase(name).toUpperCase(), constantFunction: (name) => `get${pascalCase(name)}Bytes`, dataArgsType: (name) => `${pascalCase(name)}Args`, dataType: (name) => `${pascalCase(name)}`, decoderFunction: (name) => `get${pascalCase(name)}Decoder`, discriminatedUnionDiscriminator: () => "__kind", discriminatedUnionFunction: (name) => `${camelCase(name)}`, discriminatedUnionVariant: (name) => `${pascalCase(name)}`, encoderFunction: (name) => `get${pascalCase(name)}Encoder`, enumVariant: (name) => `${pascalCase(name)}`, instructionAsyncFunction: (name) => `get${pascalCase(name)}InstructionAsync`, instructionAsyncInputType: (name) => `${pascalCase(name)}AsyncInput`, instructionDataType: (name) => `${pascalCase(name)}InstructionData`, instructionExtraType: (name) => `${pascalCase(name)}InstructionExtra`, instructionParseFunction: (name) => `parse${pascalCase(name)}Instruction`, instructionParsedType: (name) => `Parsed${pascalCase(name)}Instruction`, instructionSyncFunction: (name) => `get${pascalCase(name)}Instruction`, instructionSyncInputType: (name) => `${pascalCase(name)}Input`, instructionType: (name) => `${pascalCase(name)}Instruction`, isDiscriminatedUnionFunction: (name) => `is${pascalCase(name)}`, pdaFindFunction: (name) => `find${pascalCase(name)}Pda`, pdaSeedsType: (name) => `${pascalCase(name)}Seeds`, programAccountsEnum: (name) => `${pascalCase(name)}Account`, programAccountsEnumVariant: (name) => `${pascalCase(name)}`, programAccountsIdentifierFunction: (name) => `identify${pascalCase(name)}Account`, programAddressConstant: (name) => `${snakeCase(name).toUpperCase()}_PROGRAM_ADDRESS`, programErrorConstant: (name) => snakeCase(name).toUpperCase(), programErrorConstantPrefix: (name) => `${snakeCase(name).toUpperCase()}_ERROR__`, programErrorMessagesMap: (name) => `${camelCase(name)}ErrorMessages`, programErrorUnion: (name) => `${pascalCase(name)}Error`, programGetErrorMessageFunction: (name) => `get${pascalCase(name)}ErrorMessage`, programInstructionsEnum: (name) => `${pascalCase(name)}Instruction`, programInstructionsEnumVariant: (name) => `${pascalCase(name)}`, programInstructionsIdentifierFunction: (name) => `identify${pascalCase(name)}Instruction`, programInstructionsParsedUnionType: (name) => `Parsed${pascalCase(name)}Instruction`, programIsErrorFunction: (name) => `is${pascalCase(name)}Error`, resolverFunction: (name) => `${camelCase(name)}` }; // src/utils/fragment.ts import { createFragmentTemplate } from "@codama/renderers-core"; function createFragment(content) { return Object.freeze({ content, features: /* @__PURE__ */ new Set(), imports: createImportMap() }); } function isFragment(value) { return typeof value === "object" && value !== null && "content" in value; } function fragment(template, ...items) { return createFragmentTemplate(template, items, isFragment, mergeFragments); } function mergeFragments(fragments, mergeContent) { const filteredFragments = fragments.filter((f) => f !== void 0); return Object.freeze({ content: mergeContent(filteredFragments.map((fragment2) => fragment2.content)), features: new Set(filteredFragments.flatMap((f) => [...f.features])), imports: mergeImportMaps(filteredFragments.map((f) => f.imports)) }); } function use(importInput, module) { const importInfo = parseImportInput(importInput); return addFragmentImports(createFragment(importInfo.usedIdentifier), module, [importInput]); } function mergeFragmentImports(fragment2, importMaps) { return Object.freeze({ ...fragment2, imports: mergeImportMaps([fragment2.imports, ...importMaps]) }); } function addFragmentImports(fragment2, module, importInputs) { return Object.freeze({ ...fragment2, imports: addToImportMap(fragment2.imports, module, importInputs) }); } function removeFragmentImports(fragment2, module, usedIdentifiers) { return Object.freeze({ ...fragment2, imports: removeFromImportMap(fragment2.imports, module, usedIdentifiers) }); } function addFragmentFeatures(fragment2, features) { return Object.freeze({ ...fragment2, features: /* @__PURE__ */ new Set([...fragment2.features, ...features]) }); } function getExportAllFragment(module) { return fragment`export * from '${module}';`; } function getDocblockFragment(lines, withLineJump = false) { const lineJump = withLineJump ? "\n" : ""; if (lines.length === 0) return; if (lines.length === 1) return fragment`/** ${lines[0]} */${lineJump}`; const prefixedLines = lines.map((line) => line ? ` * ${line}` : " *"); return fragment`/**\n${prefixedLines.join("\n")}\n */${lineJump}`; } function getPageFragment(page, scope) { const header = getDocblockFragment([ "This code was AUTOGENERATED using the Codama library.", "Please DO NOT EDIT THIS FILE, instead use visitors", "to add features, then rerun Codama to update it.", "", "@see https://github.com/codama-idl/codama" ]); const imports = page.imports.size === 0 ? void 0 : fragment`${importMapToString(page.imports, scope.dependencyMap, scope.useGranularImports)}`; return mergeFragments([header, imports, page], (cs) => cs.join("\n\n")); } // src/utils/typeManifest.ts function typeManifest(input = {}) { return Object.freeze({ decoder: fragment``, encoder: fragment``, isEnum: false, looseType: fragment``, strictType: fragment``, value: fragment``, ...input }); } function mergeTypeManifests(manifests, options = {}) { const { mergeTypes, mergeCodecs, mergeValues } = options; const merge = (fragmentFn, mergeFn) => mergeFn ? mergeFragments(manifests.map(fragmentFn), mergeFn) : fragment``; return Object.freeze({ 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) }); } // src/visitors/getRenderMapVisitor.ts import { camelCase as camelCase14, getAllAccounts, getAllDefinedTypes, getAllInstructionsWithSubs as getAllInstructionsWithSubs2, getAllPdas, getAllPrograms } from "@codama/nodes"; import { createRenderMap, mergeRenderMaps } from "@codama/renderers-core"; import { extendVisitor as extendVisitor2, getByteSizeVisitor, getResolvedInstructionInputsVisitor, LinkableDictionary as LinkableDictionary3, NodeStack as NodeStack2, pipe as pipe16, recordLinkablesOnFirstVisitVisitor, recordNodeStackVisitor as recordNodeStackVisitor2, staticVisitor as staticVisitor2, visit as visit9 } from "@codama/visitors-core"; // src/fragments/accountFetchHelpers.ts import { getLastNodeFromPath, pipe } from "@codama/visitors-core"; // src/utils/async.ts import { accountValueNode, argumentValueNode, isNode } from "@codama/nodes"; import { deduplicateInstructionDependencies } from "@codama/visitors-core"; function hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers) { const hasByteDeltasAsync = (instructionNode.byteDeltas ?? []).some( ({ value }) => isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name) ); const hasRemainingAccountsAsync = (instructionNode.remainingAccounts ?? []).some( ({ value }) => 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 (isNode(input, "instructionNode")) { return 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 (isNode(input.defaultValue, ["accountValueNode", "accountBumpValueNode"])) { return [accountValueNode(input.defaultValue.name)]; } if (isNode(input.defaultValue, ["argumentValueNode"])) { return [argumentValueNode(input.defaultValue.name)]; } if (isNode(input.defaultValue, "pdaValueNode")) { const dependencies = /* @__PURE__ */ new Map(); input.defaultValue.seeds.forEach((seed) => { if (isNode(seed.value, ["accountValueNode", "argumentValueNode"])) { dependencies.set(seed.value.name, { ...seed.value }); } }); return [...dependencies.values()]; } if (isNode(input.defaultValue, "resolverValueNode")) { const isSynchronousResolver = !asyncResolvers.includes(input.defaultValue.name); if (useAsync || isSynchronousResolver) { return input.defaultValue.dependsOn ?? []; } } if (isNode(input.defaultValue, "conditionalValueNode")) { return deduplicateInstructionDependencies([ ...getNestedDependencies(input.defaultValue.condition), ...getNestedDependencies(input.defaultValue.ifTrue), ...getNestedDependencies(input.defaultValue.ifFalse) ]); } return []; } // src/utils/codecs.ts import { getBase16Encoder, getBase58Encoder, getBase64Encoder, getUtf8Encoder } from "@solana/codecs-strings"; function getBytesFromBytesValueNode(node) { switch (node.encoding) { case "utf8": return getUtf8Encoder().encode(node.data); case "base16": return getBase16Encoder().encode(node.data); case "base58": return getBase58Encoder().encode(node.data); case "base64": default: return getBase64Encoder().encode(node.data); } } // src/utils/customData.ts import { camelCase as camelCase2, definedTypeLinkNode, definedTypeNode, isNode as isNode2, structTypeNodeFromInstructionArgumentNodes } from "@codama/nodes"; var parseCustomDataOptions = (customDataOptions, defaultSuffix) => new Map( customDataOptions.map((o) => { const options = typeof o === "string" ? { name: o } : o; const importAs = camelCase2(options.importAs ?? `${options.name}${defaultSuffix}`); const importFrom = options.importFrom ?? "hooked"; return [ camelCase2(options.name), { extract: options.extract ?? false, extractAs: options.extractAs ? camelCase2(options.extractAs) : importAs, importAs, importFrom, linkNode: definedTypeLinkNode(importAs) } ]; }) ); var getDefinedTypeNodesToExtract = (nodes, parsedCustomDataOptions) => nodes.flatMap((node) => { const options = parsedCustomDataOptions.get(node.name); if (!options || !options.extract) return []; if (isNode2(node, "accountNode")) { return [definedTypeNode({ name: options.extractAs, type: { ...node.data } })]; } return [ definedTypeNode({ name: options.extractAs, type: structTypeNodeFromInstructionArgumentNodes(node.arguments) }) ]; }); // src/utils/linkOverrides.ts import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from "@codama/errors"; 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 CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [ "AccountLinkNode", "DefinedTypeLinkNode", "InstructionLinkNode", "PdaLinkNode", "ProgramLinkNode", "resolverValueNode" ], kind, node }); } }; } // src/fragments/accountFetchHelpers.ts function getAccountFetchHelpersFragment(scope) { const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope; const accountNode = getLastNodeFromPath(accountPath); const decodeFunction = nameApi.accountDecodeFunction(accountNode.name); const fetchAllFunction = nameApi.accountFetchAllFunction(accountNode.name); const fetchAllMaybeFunction = nameApi.accountFetchAllMaybeFunction(accountNode.name); const fetchFunction = nameApi.accountFetchFunction(accountNode.name); const fetchMaybeFunction = nameApi.accountFetchMaybeFunction(accountNode.name); const hasCustomData = customAccountData.has(accountNode.name); const accountType = hasCustomData ? typeManifest2.strictType : nameApi.dataType(accountNode.name); const decoderFunction = hasCustomData ? typeManifest2.decoder : `${nameApi.decoderFunction(accountNode.name)}()`; return pipe( fragment`export function ${decodeFunction}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): Account<${accountType}, TAddress>; export function ${decodeFunction}<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): MaybeAccount<${accountType}, TAddress>; export function ${decodeFunction}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>): Account<${accountType}, TAddress> | MaybeAccount<${accountType}, TAddress> { return decodeAccount(encodedAccount as MaybeEncodedAccount<TAddress>, ${decoderFunction}); } export async function ${fetchFunction}<TAddress extends string = string>( rpc: Parameters<typeof fetchEncodedAccount>[0], address: Address<TAddress>, config?: FetchAccountConfig, ): Promise<Account<${accountType}, TAddress>> { const maybeAccount = await ${fetchMaybeFunction}(rpc, address, config); assertAccountExists(maybeAccount); return maybeAccount; } export async function ${fetchMaybeFunction}<TAddress extends string = string>( rpc: Parameters<typeof fetchEncodedAccount>[0], address: Address<TAddress>, config?: FetchAccountConfig, ): Promise<MaybeAccount<${accountType}, TAddress>> { const maybeAccount = await fetchEncodedAccount(rpc, address, config); return ${decodeFunction}(maybeAccount); } export async function ${fetchAllFunction}( rpc: Parameters<typeof fetchEncodedAccounts>[0], addresses: Array<Address>, config?: FetchAccountsConfig, ): Promise<Account<${accountType}>[]> { const maybeAccounts = await ${fetchAllMaybeFunction}(rpc, addresses, config); assertAccountsExist(maybeAccounts); return maybeAccounts; } export async function ${fetchAllMaybeFunction}( rpc: Parameters<typeof fetchEncodedAccounts>[0], addresses: Array<Address>, config?: FetchAccountsConfig, ): Promise<MaybeAccount<${accountType}>[]> { const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config); return maybeAccounts.map((maybeAccount) => ${decodeFunction}(maybeAccount)); }`, (f) => addFragmentImports(f, "solanaAddresses", ["type Address"]), (f) => addFragmentImports(f, "solanaAccounts", [ "type Account", "assertAccountExists", "assertAccountsExist", "decodeAccount", "type EncodedAccount", "fetchEncodedAccount", "fetchEncodedAccounts", "type FetchAccountConfig", "type FetchAccountsConfig", "type MaybeAccount", "type MaybeEncodedAccount" ]) ); } // src/fragments/accountPage.ts import { resolveNestedTypeNode as resolveNestedTypeNode2 } from "@codama/nodes"; import { findProgramNodeFromPath, getLastNodeFromPath as getLastNodeFromPath5, visit as visit2 } from "@codama/visitors-core"; // src/fragments/accountPdaHelpers.ts import { isNodeFilter } from "@codama/nodes"; import { getLastNodeFromPath as getLastNodeFromPath2, pipe as pipe2 } from "@codama/visitors-core"; function getAccountPdaHelpersFragment(scope) { const { accountPath, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope; const accountNode = getLastNodeFromPath2(accountPath); const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : void 0; if (!pdaNode) return; const accountType = customAccountData.has(accountNode.name) ? typeManifest2.strictType : nameApi.dataType(accountNode.name); const importFrom = "generatedPdas"; const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name); const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name); const hasVariableSeeds = pdaNode.seeds.filter(isNodeFilter("variablePdaSeedNode")).length > 0; const fetchFromSeedsFunction = nameApi.accountFetchFromSeedsFunction(accountNode.name); const fetchMaybeFromSeedsFunction = nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name); const fetchMaybeFunction = nameApi.accountFetchMaybeFunction(accountNode.name); return pipe2( fragment`export async function ${fetchFromSeedsFunction}( rpc: Parameters<typeof fetchEncodedAccount>[0], ${hasVariableSeeds ? `seeds: ${pdaSeedsType},` : ""} config: FetchAccountConfig & { programAddress?: Address } = {}, ): Promise<Account<${accountType}>> { const maybeAccount = await ${fetchMaybeFromSeedsFunction}(rpc, ${hasVariableSeeds ? "seeds, " : ""}config); assertAccountExists(maybeAccount); return maybeAccount; } export async function ${fetchMaybeFromSeedsFunction}( rpc: Parameters<typeof fetchEncodedAccount>[0], ${hasVariableSeeds ? `seeds: ${pdaSeedsType},` : ""} config: FetchAccountConfig & { programAddress?: Address } = {}, ): Promise<MaybeAccount<${accountType}>> { const { programAddress, ...fetchConfig } = config; const [address] = await ${findPdaFunction}(${hasVariableSeeds ? "seeds, " : ""}{ programAddress }); return await ${fetchMaybeFunction}(rpc, address, fetchConfig); }`, (f) => addFragmentImports(f, importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]), (f) => addFragmentImports(f, "solanaAddresses", ["type Address"]), (f) => addFragmentImports(f, "solanaAccounts", [ "type Account", "assertAccountExists", "type FetchAccountConfig", "type MaybeAccount" ]) ); } // src/fragments/accountSizeHelpers.ts import { getLastNodeFromPath as getLastNodeFromPath3 } from "@codama/visitors-core"; function getAccountSizeHelpersFragment(scope) { const { accountPath, nameApi } = scope; const accountNode = getLastNodeFromPath3(accountPath); if (accountNode.size == null) return; const getSizeFunction = nameApi.accountGetSizeFunction(accountNode.name); return fragment`export function ${getSizeFunction}(): number { return ${accountNode.size}; }`; } // src/fragments/accountType.ts import { resolveNestedTypeNode } from "@codama/nodes"; import { getLastNodeFromPath as getLastNodeFromPath4 } from "@codama/visitors-core"; // src/fragments/type.ts function getTypeFragment(scope) { const { name, manifest, nameApi, docs = [] } = scope; const docblock = getDocblockFragment(docs, true); const strictName = nameApi.dataType(name); const looseName = nameApi.dataArgsType(name); const aliasedLooseName = `export type ${looseName} = ${strictName};`; if (manifest.isEnum) { return fragment`${docblock}export enum ${strictName} ${manifest.strictType};\n\n${aliasedLooseName}`; } const looseExport = manifest.strictType.content === manifest.looseType.content ? aliasedLooseName : fragment`export type ${looseName} = ${manifest.looseType};`; return fragment`${docblock}export type ${strictName} = ${manifest.strictType};\n\n${looseExport}`; } // src/fragments/typeDecoder.ts import { isDataEnum, isNode as isNode3 } from "@codama/nodes"; function getTypeDecoderFragment(scope) { const { name, node, manifest, nameApi, docs = [] } = scope; const decoderFunction = nameApi.decoderFunction(name); const strictName = nameApi.dataType(name); const docblock = getDocblockFragment(docs, true); const decoderType = use( typeof scope.size === "number" ? "type FixedSizeDecoder" : "type Decoder", "solanaCodecsCore" ); const useTypeCast = isNode3(node, "enumTypeNode") && isDataEnum(node) && typeof scope.size === "number"; const typeCast = useTypeCast ? fragment` as ${decoderType}<${strictName}>` : ""; return fragment`${docblock}export function ${decoderFunction}(): ${decoderType}<${strictName}> { return ${manifest.decoder}${typeCast}; }`; } // src/fragments/typeEncoder.ts import { isDataEnum as isDataEnum2, isNode as isNode4 } from "@codama/nodes"; function getTypeEncoderFragment(scope) { const { name, node, manifest, nameApi, docs = [] } = scope; const encoderFunction = nameApi.encoderFunction(name); const looseName = nameApi.dataArgsType(name); const docblock = getDocblockFragment(docs, true); const encoderType = use( typeof scope.size === "number" ? "type FixedSizeEncoder" : "type Encoder", "solanaCodecsCore" ); const useTypeCast = isNode4(node, "enumTypeNode") && isDataEnum2(node) && typeof scope.size === "number"; const typeCast = useTypeCast ? fragment` as ${encoderType}<${looseName}>` : ""; return fragment`${docblock}export function ${encoderFunction}(): ${encoderType}<${looseName}> { return ${manifest.encoder}${typeCast}; }`; } // src/fragments/typeCodec.ts function getTypeCodecFragment(scope) { const { codecDocs = [], name, nameApi } = scope; const codecFunction = nameApi.codecFunction(name); const decoderFunction = nameApi.decoderFunction(name); const encoderFunction = nameApi.encoderFunction(name); const looseName = nameApi.dataArgsType(name); const strictName = nameApi.dataType(name); const docblock = getDocblockFragment(codecDocs, true); const codecType = use(typeof scope.size === "number" ? "type FixedSizeCodec" : "type Codec", "solanaCodecsCore"); return mergeFragments( [ getTypeEncoderFragment({ ...scope, docs: scope.encoderDocs }), getTypeDecoderFragment({ ...scope, docs: scope.decoderDocs }), fragment`${docblock}export function ${codecFunction}(): ${codecType}<${looseName}, ${strictName}> { return ${use("combineCodec", "solanaCodecsCore")}(${encoderFunction}(), ${decoderFunction}()); }` ], (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 = getLastNodeFromPath4(accountPath); if (customAccountData.has(accountNode.name)) return; return getTypeWithCodecFragment({ manifest: typeManifest2, name: accountNode.name, nameApi, node: resolveNestedTypeNode(accountNode.data), size: scope.size }); } // src/fragments/discriminatorConstants.ts import { camelCase as camelCase3, isNode as isNode5, isNodeFilter as isNodeFilter2, VALUE_NODES } from "@codama/nodes"; import { visit } from "@codama/visitors-core"; function getDiscriminatorConstantsFragment(scope) { const fragments = scope.discriminatorNodes.map((node) => getDiscriminatorConstantFragment(node, scope)).filter(Boolean); return mergeFragments(fragments, (c) => c.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(isNodeFilter2("constantDiscriminatorNode")).indexOf(discriminatorNode); const suffix = index <= 0 ? "" : `_${index + 1}`; const name = camelCase3(`${prefix}_discriminator${suffix}`); const encoder = visit(discriminatorNode.constant.type, typeManifestVisitor).encoder; const value = 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 || !isNode5(field.defaultValue, VALUE_NODES)) { return null; } const name = camelCase3(`${prefix}_${discriminatorNode.name}`); const encoder = visit(field.type, typeManifestVisitor).encoder; const value = 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 fragment`export const ${constantName} = ${value};\n\nexport function ${constantFunction}() { return ${encoder}.encode(${constantName}); }`; } // src/fragments/accountPage.ts function getAccountPageFragment(scope) { const node = getLastNodeFromPath5(scope.accountPath); if (!findProgramNodeFromPath(scope.accountPath)) { throw new Error("Account must be visited inside a program."); } const typeManifest2 = visit2(node, scope.typeManifestVisitor); const fields = resolveNestedTypeNode2(node.data).fields; return mergeFragments( [ getDiscriminatorConstantsFragment({ ...scope, discriminatorNodes: node.discriminators ?? [], fields, prefix: node.name }), getAccountTypeFragment({ ...scope, typeManifest: typeManifest2 }), getAccountFetchHelpersFragment({ ...scope, typeManifest: typeManifest2 }), getAccountSizeHelpersFragment(scope), getAccountPdaHelpersFragment({ ...scope, typeManifest: typeManifest2 }) ], (cs) => cs.join("\n\n") ); } // src/fragments/discriminatorCondition.ts import { constantDiscriminatorNode, constantValueNode, constantValueNodeFromBytes, isNode as isNode6, isNodeFilter as isNodeFilter3 } from "@codama/nodes"; import { mapFragmentContent } from "@codama/renderers-core"; import { pipe as pipe3, visit as visit3 } from "@codama/visitors-core"; import { getBase64Decoder } from "@solana/codecs-strings"; function getDiscriminatorConditionFragment(scope) { return pipe3( mergeFragments( scope.discriminators.flatMap((discriminator) => { if (isNode6(discriminator, "sizeDiscriminatorNode")) { return [getSizeConditionFragment(discriminator, scope)]; } if (isNode6(discriminator, "constantDiscriminatorNode")) { return [getByteConditionFragment(discriminator, scope)]; } if (isNode6(discriminator, "fieldDiscriminatorNode")) { return [getFieldConditionFragment(discriminator, scope)]; } return []; }), (c) => c.join(" && ") ), (f) => mapFragmentContent(f, (c) => `if (${c}) { ${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 = visit3(discriminator.constant, typeManifestVisitor).value; return fragment`${use("containsBytes", "solanaCodecsCore")}(${dataName}, ${constant}, ${discriminator.offset})`; } 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 (isNode6(field.type, "arrayTypeNode") && isNode6(field.type.item, "numberTypeNode") && field.type.item.format === "u8" && isNode6(field.type.count, "fixedCountNode") && isNode6(field.defaultValue, "arrayValueNode") && field.defaultValue.items.every(isNodeFilter3("numberValueNode"))) { const base64Bytes = getBase64Decoder().decode( new Uint8Array(field.defaultValue.items.map((node) => node.number)) ); return getByteConditionFragment( constantDiscriminatorNode(constantValueNodeFromBytes("base64", base64Bytes), discriminator.offset), scope ); } return getByteConditionFragment( constantDiscriminatorNode(constantValueNode(field.type, field.defaultValue), discriminator.offset), scope ); } // src/fragments/errorPage.ts function getErrorPageFragment(scope) { return mergeFragments( [ getConstantsFragment(scope), getConstantUnionTypeFragment(scope), getErrorMessagesFragment(scope), getErrorMessageFunctionFragment(scope), getIsErrorFunctionFragment(scope) ], (cs) => cs.join("\n\n") ); } function getConstantsFragment(scope) { const constantPrefix = scope.nameApi.programErrorConstantPrefix(scope.programNode.name); return mergeFragments( [...scope.programNode.errors].sort((a, b) => a.code - b.code).map((error) => { const docs = getDocblockFragment(error.docs ?? [], true); const name = constantPrefix + scope.nameApi.programErrorConstant(error.name); return fragment`${docs}export const ${name} = 0x${error.code.toString(16)}; // ${error.code}`; }), (cs) => cs.join("\n") ); } function getConstantUnionTypeFragment(scope) { const constantPrefix = scope.nameApi.programErrorConstantPrefix(scope.programNode.name); const typeName = scope.nameApi.programErrorUnion(scope.programNode.name); const errorTypes = mergeFragments( [...scope.programNode.errors].sort((a, b) => a.name.localeCompare(b.name)).map((error) => fragment`typeof ${constantPrefix + scope.nameApi.programErrorConstant(error.name)}`), (cs) => cs.join(" | ") ); return fragment`export type ${typeName} = ${errorTypes};`; } function getErrorMessagesFragment(scope) { const mapName = scope.nameApi.programErrorMessagesMap(scope.programNode.name); const errorUnionType = scope.nameApi.programErrorUnion(scope.programNode.name); const constantPrefix = scope.nameApi.programErrorConstantPrefix(scope.programNode.name); const messageEntries = mergeFragments( [...scope.programNode.errors].sort((a, b) => a.name.localeCompare(b.name)).map((error) => { const constantName = constantPrefix + scope.nameApi.programErrorConstant(error.name); const escapedMessage = error.message.replace(/`/g, "\\`"); return fragment`[${constantName}]: \`${escapedMessage}\``; }), (cs) => cs.join(", ") ); return fragment`let ${mapName}: Record<${errorUnionType}, string> | undefined; if (process.env.NODE_ENV !== 'production') { ${mapName} = { ${messageEntries} }; }`; } function getErrorMessageFunctionFragment(scope) { const functionName = scope.nameApi.programGetErrorMessageFunction(scope.programNode.name); const errorUnionType = scope.nameApi.programErrorUnion(scope.programNode.name); const messageMapName = scope.nameApi.programErrorMessagesMap(scope.programNode.name); return fragment`export function ${functionName}(code: ${errorUnionType}): string { if (process.env.NODE_ENV !== 'production') { return (${messageMapName} as Record<${errorUnionType}, string>)[code]; } return 'Error message not available in production bundles.'; }`; } function getIsErrorFunctionFragment(scope) { const { programNode, nameApi } = scope; const programAddressConstant = use(nameApi.programAddressConstant(programNode.name), "generatedPrograms"); const functionName = nameApi.programIsErrorFunction(programNode.name); const programErrorUnion = nameApi.programErrorUnion(programNode.name); return fragment`export function ${functionName}<TProgramErrorCode extends ${programErrorUnion}>( error: unknown, transactionMessage: { instructions: Record<number, { programAddress: ${use("type Address", "solanaAddresses")} }> }, code?: TProgramErrorCode, ): error is ${use("type SolanaError", "solanaErrors")}<typeof ${use("type SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM", "solanaErrors")}> & Readonly<{ context: Readonly<{ code: TProgramErrorCode }> }> { return ${use("isProgramError", "solanaPrograms")}<TProgramErrorCode>(error, transactionMessage, ${programAddressConstant}, code); }`; } // src/fragments/indexPage.ts function getIndexPageFragment(items) { if (items.length === 0) return; const names = items.map((item) => item.name).sort((a, b) => a.localeCompare(b)).map((name) => getExportAllFragment(`./${name}`)); return mergeFragments(names, (cs) => cs.join("\n")); } // src/fragments/instructionAccountMeta.ts import { pascalCase as pascalCase2 } from "@codama/nodes"; function getInstructionAccountMetaFragment(instructionAccountNode) { const typeParam = `TAccount${pascalCase2(instructionAccountNode.name)}`; if (instructionAccountNode.isSigner === true && instructionAccountNode.isWritable) { return fragment`${use("type WritableSignerAccount", "solanaInstructions")}<${typeParam}> & ${use("type AccountSignerMeta", "solanaSigners")}<${typeParam}>`; } if (instructionAccountNode.isSigner === true) { return fragment`${use("type ReadonlySignerAccount", "solanaInstructions")}<${typeParam}> & ${use("type AccountSignerMeta", "solanaSigners")}<${typeParam}>`; } if (instructionAccountNode.isWritable) { return fragment`${use("type WritableAccount", "solanaInstructions")}<${typeParam}>`; } return fragment`${use("type ReadonlyAccount", "solanaInstructions")}<${typeParam}>`; } // src/fragments/instructionAccountTypeParam.ts import { pascalCase as pascalCase3 } from "@codama/nodes"; import { findInstructionNodeFromPath, findProgramNodeFromPath as findProgramNodeFromPath2, getLastNodeFromPath as getLastNodeFromPath6 } from "@codama/visitors-core"; function getInstructionAccountTypeParamFragment(scope) { const { instructionAccountPath, allowAccountMeta, linkables } = scope; const instructionAccountNode = getLastNodeFromPath6(instructionAccountPath); const instructionNode = findInstructionNodeFromPath(instructionAccountPath); const programNode = findProgramNodeFromPath2(instructionAccountPath); const typeParam = `TAccount${pascalCase3(instructionAccountNode.name)}`; const accountMeta = allowAccountMeta ? fragment` | ${use("type AccountMeta", "solanaInstructions")}<string>` : void 0; if (instructionNode.optionalAccountStrategy === "omitted" && instructionAccountNode.isOptional) { return fragment`${typeParam} extends string${accountMeta} | undefined = undefined`; } const defaultAddress = getDefaultAddress(instructionAccountNode.defaultValue, programNode.publicKey, linkables); return fragment`${typeParam} extends string${accountMeta} = ${defaultAddress}`; } 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"; } } // src/fragments/instructionByteDelta.ts import { assertIsNode, camelCase as camelCase4, isNode as isNode7 } from "@codama/nodes"; import { mapFragmentContent as mapFragmentContent2 } from "@codama/renderers-core"; import { getLastNodeFromPath as getLastNodeFromPath7, pipe as pipe4 } from "@codama/visitors-core"; function getInstructionByteDeltaFragment(scope) { const { byteDeltas } = getLastNodeFromPath7(scope.instructionPath); const fragments = (byteDeltas ?? []).flatMap((c) => getByteDeltaFragment(c, scope)); if (fragments.length === 0) return; return mergeFragments( fragments, (c) => `// Bytes created or reallocated by the instruction. const byteDelta: number = [${c.join(",")}].reduce((a, b) => a + b, 0);` ); } function getByteDeltaFragment(byteDelta, scope) { let bytesFragment = (() => { if (isNode7(byteDelta.value, "numberValueNode")) { return getNumberValueNodeFragment(byteDelta); } if (isNode7(byteDelta.value, "argumentValueNode")) { return getArgumentValueNodeFragment(byteDelta); } if (isNode7(byteDelta.value, "accountLinkNode")) { return getAccountLinkNodeFragment(byteDelta, scope); } if (isNode7(byteDelta.value, "resolverValueNode")) { return getResolverValueNodeFragment(byteDelta, scope); } return null; })(); if (bytesFragment === null) return []; if (byteDelta.withHeader) { bytesFragment = fragment`${bytesFragment} + ${use("BASE_ACCOUNT_SIZE", "solanaAccounts")}`; } if (byteDelta.subtract) { bytesFragment = pipe4(bytesFragment, (f) => mapFragmentContent2(f, (c) => `- (${c})`)); } return [bytesFragment]; } function getNumberValueNodeFragment(byteDelta) { assertIsNode(byteDelta.value, "numberValueNode"); return fragment`${byteDelta.value.number}`; } function getArgumentValueNodeFragment(byteDelta) { assertIsNode(byteDelta.value, "argumentValueNode"); const argumentName = camelCase4(byteDelta.value.name); return fragment`Number(args.${argumentName})`; } function getAccountLinkNodeFragment(byteDelta, scope) { assertIsNode(byteDelta.value, "accountLinkNode"); const functionName = use( scope.nameApi.accountGetSizeFunction(byteDelta.value.name), scope.getImportFrom(byteDelta.value) ); return fragment`${functionName}()`; } function getResolverValueNodeFragment(byteDelta, scope) { 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 = use( scope.nameApi.resolverFunction(byteDelta.value.name), scope.getImportFrom(byteDelta.value) ); return pipe4( fragment`${awaitKeyword}${functionName}(resolverScope)`, (f) => addFragmentFeatures(f, ["instruction:resolverScopeVariable"]) ); } // src/fragments/instructionData.ts import { structTypeNodeFromInstructionArgumentNodes as structTypeNodeFromInstructionArgumentNodes2 } from "@codama/nodes"; import { getLastNodeFromPath as getLastNodeFromPath8 } from "@codama/visitors-core"; function getInstructionDataFragment(scope) { const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope; const instructionNode = getLastNodeFromPath8(instructionPath); if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) return; const instructionDataName = nameApi.instructionDataType(instructionNode.name); return getTypeWithCodecFragment({ manifest: dataArgsManifest, name: instructionDataName, nameApi, node: structTypeNodeFromInstructionArgumentNodes2(instructionNode.arguments), size: scope.size }); } // src/fragments/instructionExtraArgs.ts import { mapFragmentContent as mapFragmentContent3 } from "@codama/renderers-core"; import { getLastNodeFromPath as getLastNodeFromPath9 } from "@codama/visitors-core"; function getInstructionExtraArgsFragment(scope) { const { instructionPath, extraArgsManifest, nameApi } = scope; const instructionNode = getLastNodeFromPath9(instructionPath); if ((instructionNode.extraArguments ?? []).length === 0) return; const instructionExtraName = nameApi.instructionExtraType(instructionNode.name); const looseName = nameApi.dataArgsType(instructionExtraName); return mapFragmentContent3(extraArgsManifest.looseType, (c) => `export type ${looseName} = ${c};`); } // src/fragments/instructionFunction.ts import { camelCase as camelCase9, isNode as isNode12, isNodeFilter as isNodeFilter4, pascalCase as pascalCase5 } from "@codama/nodes"; import { mapFragmentContent as mapFragmentContent7 } from "@codama/renderers-core"; import { findProgramNodeFromPath as findProgramNodeFromPath3, getLastNodeFromPath as getLastNodeFromPath13, pipe as pipe8 } from "@codama/visitors-core"; // src/fragments/instructionInputResolved.ts import { camelCase as camelCase6, isNode as isNode9, parseOptionalAccountStrategy } from "@codama/nodes"; import { mapFragmentContent as mapFragmentContent5 } from "@codama/renderers-core"; import { getLastNodeFromPath as getLastNodeFromPath10 } from "@codama/visitors-core"; // src/fragments/instructionInputDefault.ts import { camelCase as camelCase5, isNode as isNode8 } from "@codama/nodes"; import { mapFragmentContent as mapFragmentContent4, setFragmentContent } from "@codama/renderers-core"; import { pipe as pipe5, visit as visit4 } from "@codama/visitors-core"; 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 = camelCase5(input.name); if (input.kind === "instructionAccountNode" && isNode8(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};\naccounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}`; } return fragment`args.${inputName} = ${renderedValue};`; }; switch (defaultValue.kind) { case "accountValueNode": const name = camelCase5(defaultValue.name); if (input.kind === "instructionAccountNode" && input.resolvedIsSigner && !input.isSigner) { return pipe5( defaultFragment(`expectTransactionSigner(accounts.${name}.value).address`), (f) => addFragmentImports(f, "shared", ["expectTransactionSigner"]) );