UNPKG

@codama/renderers-js

Version:

JavaScript renderer compatible with the Solana Kit library

1 lines 276 kB
{"version":3,"sources":["../src/index.ts","../src/ImportMap.ts","../src/fragments/accountFetchHelpers.ts","../src/fragments/common.ts","../src/utils/async.ts","../src/utils/codecs.ts","../src/utils/customData.ts","../src/utils/linkOverrides.ts","../src/utils/render.ts","../src/fragments/accountPdaHelpers.ts","../src/fragments/accountSizeHelpers.ts","../src/fragments/accountType.ts","../src/fragments/type.ts","../src/fragments/typeDecoder.ts","../src/fragments/typeEncoder.ts","../src/fragments/typeCodec.ts","../src/fragments/typeWithCodec.ts","../src/fragments/discriminatorCondition.ts","../src/fragments/instructionAccountMeta.ts","../src/fragments/instructionAccountTypeParam.ts","../src/fragments/instructionByteDelta.ts","../src/fragments/instructionData.ts","../src/fragments/discriminatorConstants.ts","../src/fragments/instructionExtraArgs.ts","../src/fragments/instructionFunction.ts","../src/fragments/instructionInputResolved.ts","../src/fragments/instructionInputDefault.ts","../src/fragments/instructionInputType.ts","../src/fragments/instructionRemainingAccounts.ts","../src/fragments/instructionParseFunction.ts","../src/fragments/instructionType.ts","../src/fragments/pdaFunction.ts","../src/fragments/program.ts","../src/fragments/programAccounts.ts","../src/fragments/programErrors.ts","../src/fragments/programInstructions.ts","../src/fragments/typeDiscriminatedUnionHelpers.ts","../src/TypeManifest.ts","../src/getRenderMapVisitor.ts","../src/getTypeManifestVisitor.ts","../src/nameTransformers.ts","../src/renderVisitor.ts"],"sourcesContent":["export * from './ImportMap';\nexport * from './TypeManifest';\nexport * from './getRenderMapVisitor';\nexport * from './getTypeManifestVisitor';\nexport * from './nameTransformers';\nexport * from './renderVisitor';\n\nexport { renderVisitor as default } from './renderVisitor';\n","import { Fragment } from './fragments';\nimport { TypeManifest } from './TypeManifest';\n\nconst DEFAULT_EXTERNAL_MODULE_MAP: Record<string, string> = {\n solanaAccounts: '@solana/kit',\n solanaAddresses: '@solana/kit',\n solanaCodecsCore: '@solana/kit',\n solanaCodecsDataStructures: '@solana/kit',\n solanaCodecsNumbers: '@solana/kit',\n solanaCodecsStrings: '@solana/kit',\n solanaErrors: '@solana/kit',\n solanaInstructions: '@solana/kit',\n solanaOptions: '@solana/kit',\n solanaPrograms: '@solana/kit',\n solanaRpcTypes: '@solana/kit',\n solanaSigners: '@solana/kit',\n};\n\nconst DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP: Record<string, string> = {\n solanaAccounts: '@solana/accounts',\n solanaAddresses: '@solana/addresses',\n solanaCodecsCore: '@solana/codecs',\n solanaCodecsDataStructures: '@solana/codecs',\n solanaCodecsNumbers: '@solana/codecs',\n solanaCodecsStrings: '@solana/codecs',\n solanaErrors: '@solana/errors',\n solanaInstructions: '@solana/instructions',\n solanaOptions: '@solana/codecs',\n solanaPrograms: '@solana/programs',\n solanaRpcTypes: '@solana/rpc-types',\n solanaSigners: '@solana/signers',\n};\n\nconst DEFAULT_INTERNAL_MODULE_MAP: Record<string, string> = {\n errors: '../errors',\n generated: '..',\n generatedAccounts: '../accounts',\n generatedErrors: '../errors',\n generatedInstructions: '../instructions',\n generatedPdas: '../pdas',\n generatedPrograms: '../programs',\n generatedTypes: '../types',\n hooked: '../../hooked',\n shared: '../shared',\n types: '../types',\n};\n\nexport class ImportMap {\n protected readonly _imports: Map<string, Set<string>> = new Map();\n\n protected readonly _aliases: Map<string, Record<string, string>> = new Map();\n\n add(module: string, imports: Set<string> | string[] | string): ImportMap {\n const newImports = new Set(typeof imports === 'string' ? [imports] : imports);\n if (newImports.size === 0) return this;\n const currentImports = this._imports.get(module) ?? new Set();\n newImports.forEach(i => currentImports.add(i));\n this._imports.set(module, currentImports);\n return this;\n }\n\n remove(module: string, imports: Set<string> | string[] | string): ImportMap {\n const importsToRemove = new Set(typeof imports === 'string' ? [imports] : imports);\n if (importsToRemove.size === 0) return this;\n const currentImports = this._imports.get(module) ?? new Set();\n importsToRemove.forEach(i => currentImports.delete(i));\n if (currentImports.size === 0) {\n this._imports.delete(module);\n } else {\n this._imports.set(module, currentImports);\n }\n return this;\n }\n\n mergeWith(...others: (Fragment | ImportMap)[]): ImportMap {\n others.forEach(rawOther => {\n const other = 'imports' in rawOther ? rawOther.imports : rawOther;\n other._imports.forEach((imports, module) => {\n this.add(module, imports);\n });\n other._aliases.forEach((aliases, module) => {\n Object.entries(aliases).forEach(([name, alias]) => {\n this.addAlias(module, name, alias);\n });\n });\n });\n return this;\n }\n\n mergeWithManifest(manifest: TypeManifest): ImportMap {\n return this.mergeWith(manifest.strictType, manifest.looseType, manifest.encoder, manifest.decoder);\n }\n\n addAlias(module: string, name: string, alias: string): ImportMap {\n const currentAliases = this._aliases.get(module) ?? {};\n currentAliases[name] = alias;\n this._aliases.set(module, currentAliases);\n return this;\n }\n\n isEmpty(): boolean {\n return this._imports.size === 0;\n }\n\n resolve(dependencies: Record<string, string> = {}, useGranularImports = false): Map<string, Set<string>> {\n // Resolve aliases.\n const aliasedMap = new Map<string, Set<string>>(\n [...this._imports.entries()].map(([module, imports]) => {\n const aliasMap = this._aliases.get(module) ?? {};\n const joinedImports = [...imports].map(i => (aliasMap[i] ? `${i} as ${aliasMap[i]}` : i));\n return [module, new Set(joinedImports)];\n }),\n );\n\n // Resolve dependency mappings.\n const dependencyMap = {\n ...(useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP),\n ...DEFAULT_INTERNAL_MODULE_MAP,\n ...dependencies,\n };\n const resolvedMap = new Map<string, Set<string>>();\n aliasedMap.forEach((imports, module) => {\n const resolvedModule: string = dependencyMap[module] ?? module;\n const currentImports = resolvedMap.get(resolvedModule) ?? new Set();\n imports.forEach(i => currentImports.add(i));\n resolvedMap.set(resolvedModule, currentImports);\n });\n\n return resolvedMap;\n }\n\n toString(dependencies: Record<string, string> = {}, useGranularImports = false): string {\n return [...this.resolve(dependencies, useGranularImports).entries()]\n .sort(([a], [b]) => {\n const aIsRelative = a.startsWith('.');\n const bIsRelative = b.startsWith('.');\n if (aIsRelative && !bIsRelative) return 1;\n if (!aIsRelative && bIsRelative) return -1;\n return a.localeCompare(b);\n })\n .map(([module, imports]) => {\n const joinedImports = [...imports]\n .sort()\n .filter(i => {\n // import of a type can either be '<Type>' or 'type <Type>', so\n // we filter out 'type <Type>' variation if there is a '<Type>'\n const name = i.split(' ');\n if (name.length > 1) {\n return !imports.has(name[1]);\n }\n return true;\n })\n .join(', ');\n return `import { ${joinedImports} } from '${module}';`;\n })\n .join('\\n');\n }\n}\n","import { AccountNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragment, fragmentFromTemplate } from './common';\n\nexport function getAccountFetchHelpersFragment(\n scope: Pick<GlobalFragmentScope, 'customAccountData' | 'nameApi'> & {\n accountPath: NodePath<AccountNode>;\n typeManifest: TypeManifest;\n },\n): Fragment {\n const { accountPath, typeManifest, nameApi, customAccountData } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n const hasCustomData = customAccountData.has(accountNode.name);\n const accountTypeFragment = hasCustomData\n ? typeManifest.strictType.clone()\n : fragment(nameApi.dataType(accountNode.name));\n const decoderFunctionFragment = hasCustomData\n ? typeManifest.decoder.clone()\n : fragment(`${nameApi.decoderFunction(accountNode.name)}()`);\n\n return fragmentFromTemplate('accountFetchHelpers.njk', {\n accountType: accountTypeFragment.render,\n decodeFunction: nameApi.accountDecodeFunction(accountNode.name),\n decoderFunction: decoderFunctionFragment.render,\n fetchAllFunction: nameApi.accountFetchAllFunction(accountNode.name),\n fetchAllMaybeFunction: nameApi.accountFetchAllMaybeFunction(accountNode.name),\n fetchFunction: nameApi.accountFetchFunction(accountNode.name),\n fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),\n })\n .mergeImportsWith(accountTypeFragment, decoderFunctionFragment)\n .addImports('solanaAddresses', ['type Address'])\n .addImports('solanaAccounts', [\n 'type Account',\n 'assertAccountExists',\n 'assertAccountsExist',\n 'decodeAccount',\n 'type EncodedAccount',\n 'fetchEncodedAccount',\n 'fetchEncodedAccounts',\n 'type FetchAccountConfig',\n 'type FetchAccountsConfig',\n 'type MaybeAccount',\n 'type MaybeEncodedAccount',\n ]);\n}\n","import { join } from 'node:path';\n\nimport { ConfigureOptions } from 'nunjucks';\n\nimport { ImportMap } from '../ImportMap';\nimport { render } from '../utils';\n\nexport function fragment(render: string, imports?: ImportMap): Fragment {\n return new Fragment(render, imports);\n}\n\nexport function fragmentFromTemplate(fragmentFile: string, context?: object, options?: ConfigureOptions): Fragment {\n return fragment(render(join('fragments', fragmentFile), context, options));\n}\n\nexport function mergeFragments(fragments: Fragment[], mergeRenders: (renders: string[]) => string): Fragment {\n return new Fragment(\n mergeRenders(fragments.map(f => f.render)),\n new ImportMap().mergeWith(...fragments),\n new Set(fragments.flatMap(f => [...f.features])),\n );\n}\n\nexport class Fragment {\n public render: string;\n\n public imports: ImportMap;\n\n public features: Set<FragmentFeature>;\n\n constructor(render: string, imports?: ImportMap, features?: Set<FragmentFeature>) {\n this.render = render;\n this.imports = imports ? new ImportMap().mergeWith(imports) : new ImportMap();\n this.features = new Set([...(features ?? [])]);\n }\n\n setRender(render: string): this {\n this.render = render;\n return this;\n }\n\n mapRender(fn: (render: string) => string): this {\n this.render = fn(this.render);\n return this;\n }\n\n addImports(module: string, imports: Set<string> | string[] | string): this {\n this.imports.add(module, imports);\n return this;\n }\n\n removeImports(module: string, imports: Set<string> | string[] | string): this {\n this.imports.remove(module, imports);\n return this;\n }\n\n mergeImportsWith(...others: (Fragment | ImportMap)[]): this {\n this.imports.mergeWith(...others);\n return this;\n }\n\n addImportAlias(module: string, name: string, alias: string): this {\n this.imports.addAlias(module, name, alias);\n return this;\n }\n\n addFeatures(features: FragmentFeature | FragmentFeature[]): this {\n const featureArray = typeof features === 'string' ? [features] : features;\n featureArray.forEach(f => this.features.add(f));\n return this;\n }\n\n removeFeatures(features: FragmentFeature | FragmentFeature[]): this {\n const featureArray = typeof features === 'string' ? [features] : features;\n featureArray.forEach(f => this.features.delete(f));\n return this;\n }\n\n hasFeatures(features: FragmentFeature | FragmentFeature[]): boolean {\n const featureArray = typeof features === 'string' ? [features] : features;\n return featureArray.every(f => this.features.has(f));\n }\n\n mergeFeaturesWith(...others: Fragment[]): this {\n others.forEach(f => this.addFeatures([...f.features]));\n return this;\n }\n\n clone(): Fragment {\n return new Fragment(this.render).mergeImportsWith(this.imports);\n }\n\n toString(): string {\n return this.render;\n }\n}\n\nexport type FragmentFeature = 'instruction:resolverScopeVariable';\n","import {\n AccountValueNode,\n accountValueNode,\n ArgumentValueNode,\n argumentValueNode,\n CamelCaseString,\n InstructionAccountNode,\n InstructionArgumentNode,\n InstructionInputValueNode,\n InstructionNode,\n isNode,\n} from '@codama/nodes';\nimport { deduplicateInstructionDependencies, ResolvedInstructionInput } from '@codama/visitors-core';\n\nexport function hasAsyncFunction(\n instructionNode: InstructionNode,\n resolvedInputs: ResolvedInstructionInput[],\n asyncResolvers: string[],\n): boolean {\n const hasByteDeltasAsync = (instructionNode.byteDeltas ?? []).some(\n ({ value }) => isNode(value, 'resolverValueNode') && asyncResolvers.includes(value.name),\n );\n const hasRemainingAccountsAsync = (instructionNode.remainingAccounts ?? []).some(\n ({ value }) => isNode(value, 'resolverValueNode') && asyncResolvers.includes(value.name),\n );\n\n return hasAsyncDefaultValues(resolvedInputs, asyncResolvers) || hasByteDeltasAsync || hasRemainingAccountsAsync;\n}\n\nexport function hasAsyncDefaultValues(resolvedInputs: ResolvedInstructionInput[], asyncResolvers: string[]): boolean {\n return resolvedInputs.some(\n input => !!input.defaultValue && isAsyncDefaultValue(input.defaultValue, asyncResolvers),\n );\n}\n\nexport function isAsyncDefaultValue(defaultValue: InstructionInputValueNode, asyncResolvers: string[]): boolean {\n switch (defaultValue.kind) {\n case 'pdaValueNode':\n return true;\n case 'resolverValueNode':\n return asyncResolvers.includes(defaultValue.name);\n case 'conditionalValueNode':\n return (\n isAsyncDefaultValue(defaultValue.condition, asyncResolvers) ||\n (defaultValue.ifFalse == null ? false : isAsyncDefaultValue(defaultValue.ifFalse, asyncResolvers)) ||\n (defaultValue.ifTrue == null ? false : isAsyncDefaultValue(defaultValue.ifTrue, asyncResolvers))\n );\n default:\n return false;\n }\n}\n\nexport function getInstructionDependencies(\n input: InstructionAccountNode | InstructionArgumentNode | InstructionNode,\n asyncResolvers: string[],\n useAsync: boolean,\n): (AccountValueNode | ArgumentValueNode)[] {\n if (isNode(input, 'instructionNode')) {\n return deduplicateInstructionDependencies([\n ...input.accounts.flatMap(x => getInstructionDependencies(x, asyncResolvers, useAsync)),\n ...input.arguments.flatMap(x => getInstructionDependencies(x, asyncResolvers, useAsync)),\n ...(input.extraArguments ?? []).flatMap(x => getInstructionDependencies(x, asyncResolvers, useAsync)),\n ]);\n }\n\n if (!input.defaultValue) return [];\n\n const getNestedDependencies = (\n defaultValue: InstructionInputValueNode | undefined,\n ): (AccountValueNode | ArgumentValueNode)[] => {\n if (!defaultValue) return [];\n return getInstructionDependencies({ ...input, defaultValue }, asyncResolvers, useAsync);\n };\n\n if (isNode(input.defaultValue, ['accountValueNode', 'accountBumpValueNode'])) {\n return [accountValueNode(input.defaultValue.name)];\n }\n\n if (isNode(input.defaultValue, ['argumentValueNode'])) {\n return [argumentValueNode(input.defaultValue.name)];\n }\n\n if (isNode(input.defaultValue, 'pdaValueNode')) {\n const dependencies = new Map<CamelCaseString, AccountValueNode | ArgumentValueNode>();\n input.defaultValue.seeds.forEach(seed => {\n if (isNode(seed.value, ['accountValueNode', 'argumentValueNode'])) {\n dependencies.set(seed.value.name, { ...seed.value });\n }\n });\n return [...dependencies.values()];\n }\n\n if (isNode(input.defaultValue, 'resolverValueNode')) {\n const isSynchronousResolver = !asyncResolvers.includes(input.defaultValue.name);\n if (useAsync || isSynchronousResolver) {\n return input.defaultValue.dependsOn ?? [];\n }\n }\n\n if (isNode(input.defaultValue, 'conditionalValueNode')) {\n return deduplicateInstructionDependencies([\n ...getNestedDependencies(input.defaultValue.condition),\n ...getNestedDependencies(input.defaultValue.ifTrue),\n ...getNestedDependencies(input.defaultValue.ifFalse),\n ]);\n }\n\n return [];\n}\n","import { BytesValueNode } from '@codama/nodes';\nimport { getBase16Encoder, getBase58Encoder, getBase64Encoder, getUtf8Encoder } from '@solana/codecs-strings';\n\nexport function getBytesFromBytesValueNode(node: BytesValueNode): Uint8Array {\n switch (node.encoding) {\n case 'utf8':\n return getUtf8Encoder().encode(node.data) as Uint8Array;\n case 'base16':\n return getBase16Encoder().encode(node.data) as Uint8Array;\n case 'base58':\n return getBase58Encoder().encode(node.data) as Uint8Array;\n case 'base64':\n default:\n return getBase64Encoder().encode(node.data) as Uint8Array;\n }\n}\n","import {\n AccountNode,\n camelCase,\n CamelCaseString,\n DefinedTypeLinkNode,\n definedTypeLinkNode,\n DefinedTypeNode,\n definedTypeNode,\n InstructionNode,\n isNode,\n structTypeNodeFromInstructionArgumentNodes,\n} from '@codama/nodes';\n\nexport type CustomDataOptions =\n | string\n | {\n extract?: boolean;\n extractAs?: string;\n importAs?: string;\n importFrom?: string;\n name: string;\n };\n\nexport type ParsedCustomDataOptions = Map<\n CamelCaseString,\n {\n extract: boolean;\n extractAs: CamelCaseString;\n importAs: CamelCaseString;\n importFrom: string;\n linkNode: DefinedTypeLinkNode;\n }\n>;\n\nexport const parseCustomDataOptions = (\n customDataOptions: CustomDataOptions[],\n defaultSuffix: string,\n): ParsedCustomDataOptions =>\n new Map(\n customDataOptions.map(o => {\n const options = typeof o === 'string' ? { name: o } : o;\n const importAs = camelCase(options.importAs ?? `${options.name}${defaultSuffix}`);\n const importFrom = options.importFrom ?? 'hooked';\n return [\n camelCase(options.name),\n {\n extract: options.extract ?? false,\n extractAs: options.extractAs ? camelCase(options.extractAs) : importAs,\n importAs,\n importFrom,\n linkNode: definedTypeLinkNode(importAs),\n },\n ];\n }),\n );\n\nexport const getDefinedTypeNodesToExtract = (\n nodes: AccountNode[] | InstructionNode[],\n parsedCustomDataOptions: ParsedCustomDataOptions,\n): DefinedTypeNode[] =>\n nodes.flatMap(node => {\n const options = parsedCustomDataOptions.get(node.name);\n if (!options || !options.extract) return [];\n\n if (isNode(node, 'accountNode')) {\n return [definedTypeNode({ name: options.extractAs, type: { ...node.data } })];\n }\n\n return [\n definedTypeNode({\n name: options.extractAs,\n type: structTypeNodeFromInstructionArgumentNodes(node.arguments),\n }),\n ];\n });\n","import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from '@codama/errors';\nimport {\n AccountLinkNode,\n DefinedTypeLinkNode,\n InstructionLinkNode,\n PdaLinkNode,\n ProgramLinkNode,\n ResolverValueNode,\n} from '@codama/nodes';\n\nimport { ParsedCustomDataOptions } from './customData';\n\nexport type LinkOverrides = {\n accounts?: Record<string, string>;\n definedTypes?: Record<string, string>;\n instructions?: Record<string, string>;\n pdas?: Record<string, string>;\n programs?: Record<string, string>;\n resolvers?: Record<string, string>;\n};\n\ntype OverridableNodes =\n | AccountLinkNode\n | DefinedTypeLinkNode\n | InstructionLinkNode\n | PdaLinkNode\n | ProgramLinkNode\n | ResolverValueNode;\n\nexport type GetImportFromFunction = (node: OverridableNodes, fallback?: string) => string;\n\nexport function getImportFromFactory(\n overrides: LinkOverrides,\n customAccountData: ParsedCustomDataOptions,\n customInstructionData: ParsedCustomDataOptions,\n): GetImportFromFunction {\n const customDataOverrides = Object.fromEntries(\n [...customAccountData.values(), ...customInstructionData.values()].map(({ importFrom, importAs }) => [\n importAs,\n importFrom,\n ]),\n );\n const linkOverrides = {\n accounts: overrides.accounts ?? {},\n definedTypes: { ...customDataOverrides, ...overrides.definedTypes },\n instructions: overrides.instructions ?? {},\n pdas: overrides.pdas ?? {},\n programs: overrides.programs ?? {},\n resolvers: overrides.resolvers ?? {},\n };\n\n return (node: OverridableNodes) => {\n const kind = node.kind;\n switch (kind) {\n case 'accountLinkNode':\n return linkOverrides.accounts[node.name] ?? 'generatedAccounts';\n case 'definedTypeLinkNode':\n return linkOverrides.definedTypes[node.name] ?? 'generatedTypes';\n case 'instructionLinkNode':\n return linkOverrides.instructions[node.name] ?? 'generatedInstructions';\n case 'pdaLinkNode':\n return linkOverrides.pdas[node.name] ?? 'generatedPdas';\n case 'programLinkNode':\n return linkOverrides.programs[node.name] ?? 'generatedPrograms';\n case 'resolverValueNode':\n return linkOverrides.resolvers[node.name] ?? 'hooked';\n default:\n throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {\n expectedKinds: [\n 'AccountLinkNode',\n 'DefinedTypeLinkNode',\n 'InstructionLinkNode',\n 'PdaLinkNode',\n 'ProgramLinkNode',\n 'resolverValueNode',\n ],\n kind: kind satisfies never,\n node,\n });\n }\n };\n}\n","import { dirname as pathDirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { camelCase, kebabCase, pascalCase, snakeCase, titleCase } from '@codama/nodes';\nimport nunjucks, { ConfigureOptions as NunJucksOptions } from 'nunjucks';\n\nexport function jsDocblock(docs: string[]): string {\n if (docs.length <= 0) return '';\n if (docs.length === 1) return `/** ${docs[0]} */\\n`;\n const lines = docs.map(doc => ` * ${doc}`);\n return `/**\\n${lines.join('\\n')}\\n */\\n`;\n}\n\nexport const render = (template: string, context?: object, options?: NunJucksOptions): string => {\n // @ts-expect-error import.meta will be used in the right environment.\n const dirname = __ESM__ ? pathDirname(fileURLToPath(import.meta.url)) : __dirname;\n const templates = __TEST__ ? join(dirname, '..', '..', 'public', 'templates') : join(dirname, 'templates'); // Path to templates from bundled output file.\n const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options });\n env.addFilter('pascalCase', pascalCase);\n env.addFilter('camelCase', camelCase);\n env.addFilter('snakeCase', snakeCase);\n env.addFilter('kebabCase', kebabCase);\n env.addFilter('titleCase', titleCase);\n env.addFilter('jsDocblock', jsDocblock);\n return env.render(template, context);\n};\n","import { AccountNode, isNodeFilter } from '@codama/nodes';\nimport { findProgramNodeFromPath, getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport type { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragment, fragmentFromTemplate } from './common';\n\nexport function getAccountPdaHelpersFragment(\n scope: Pick<GlobalFragmentScope, 'customAccountData' | 'linkables' | 'nameApi'> & {\n accountPath: NodePath<AccountNode>;\n typeManifest: TypeManifest;\n },\n): Fragment {\n const { accountPath, nameApi, linkables, customAccountData, typeManifest } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n const programNode = findProgramNodeFromPath(accountPath)!;\n const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : undefined;\n if (!pdaNode) {\n return fragment('');\n }\n\n const accountTypeFragment = customAccountData.has(accountNode.name)\n ? typeManifest.strictType.clone()\n : fragment(nameApi.dataType(accountNode.name));\n\n // Here we cannot use the `getImportFrom` function because\n // we need to know the seeds of the PDA in order to know\n // if we need to render a `seeds` argument or not.\n const importFrom = 'generatedPdas';\n const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name);\n const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name);\n const hasVariableSeeds = pdaNode.seeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0;\n\n return fragmentFromTemplate('accountPdaHelpers.njk', {\n accountType: accountTypeFragment.render,\n fetchFromSeedsFunction: nameApi.accountFetchFromSeedsFunction(accountNode.name),\n fetchFunction: nameApi.accountFetchFunction(accountNode.name),\n fetchMaybeFromSeedsFunction: nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name),\n fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),\n findPdaFunction,\n hasVariableSeeds,\n pdaSeedsType,\n program: programNode,\n })\n .mergeImportsWith(accountTypeFragment)\n .addImports(importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction])\n .addImports('solanaAddresses', ['type Address'])\n .addImports('solanaAccounts', [\n 'type Account',\n 'assertAccountExists',\n 'type FetchAccountConfig',\n 'type MaybeAccount',\n ]);\n}\n","import { AccountNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { Fragment, fragment, fragmentFromTemplate } from './common';\n\nexport function getAccountSizeHelpersFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & { accountPath: NodePath<AccountNode> },\n): Fragment {\n const { accountPath, nameApi } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n if (accountNode.size == null) {\n return fragment('');\n }\n\n return fragmentFromTemplate('accountSizeHelpers.njk', {\n account: accountNode,\n getSizeFunction: nameApi.accountGetSizeFunction(accountNode.name),\n });\n}\n","import { AccountNode, resolveNestedTypeNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragment } from './common';\nimport { getTypeWithCodecFragment } from './typeWithCodec';\n\nexport function getAccountTypeFragment(\n scope: Pick<GlobalFragmentScope, 'customAccountData' | 'nameApi'> & {\n accountPath: NodePath<AccountNode>;\n size: number | null;\n typeManifest: TypeManifest;\n },\n): Fragment {\n const { accountPath, typeManifest, nameApi, customAccountData } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n\n if (customAccountData.has(accountNode.name)) {\n return fragment('');\n }\n\n return getTypeWithCodecFragment({\n manifest: typeManifest,\n name: accountNode.name,\n nameApi,\n node: resolveNestedTypeNode(accountNode.data),\n size: scope.size,\n });\n}\n","import type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragmentFromTemplate } from './common';\n\nexport function getTypeFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & {\n docs?: string[];\n manifest: TypeManifest;\n name: string;\n },\n): Fragment {\n const { name, manifest, nameApi, docs = [] } = scope;\n const typeFragment = fragmentFromTemplate('type.njk', {\n docs,\n looseName: nameApi.dataArgsType(name),\n manifest,\n strictName: nameApi.dataType(name),\n });\n\n if (!manifest.isEnum) {\n typeFragment.mergeImportsWith(manifest.strictType, manifest.looseType);\n }\n\n return typeFragment;\n}\n","import { isDataEnum, isNode, TypeNode } from '@codama/nodes';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragmentFromTemplate } from './common';\n\nexport function getTypeDecoderFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & {\n docs?: string[];\n manifest: Pick<TypeManifest, 'decoder'>;\n name: string;\n node: TypeNode;\n size: number | null;\n },\n): Fragment {\n const { name, node, manifest, nameApi, docs = [] } = scope;\n const decoderType = typeof scope.size === 'number' ? 'FixedSizeDecoder' : 'Decoder';\n const useTypeCast = isNode(node, 'enumTypeNode') && isDataEnum(node) && typeof scope.size === 'number';\n\n return fragmentFromTemplate('typeDecoder.njk', {\n decoderFunction: nameApi.decoderFunction(name),\n decoderType,\n docs,\n looseName: nameApi.dataArgsType(name),\n manifest,\n strictName: nameApi.dataType(name),\n useTypeCast,\n })\n .mergeImportsWith(manifest.decoder)\n .addImports('solanaCodecsCore', `type ${decoderType}`);\n}\n","import { isDataEnum, isNode, TypeNode } from '@codama/nodes';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragmentFromTemplate } from './common';\n\nexport function getTypeEncoderFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & {\n docs?: string[];\n manifest: Pick<TypeManifest, 'encoder'>;\n name: string;\n node: TypeNode;\n size: number | null;\n },\n): Fragment {\n const { name, node, manifest, nameApi, docs = [] } = scope;\n const encoderType = typeof scope.size === 'number' ? 'FixedSizeEncoder' : 'Encoder';\n const useTypeCast = isNode(node, 'enumTypeNode') && isDataEnum(node) && typeof scope.size === 'number';\n\n return fragmentFromTemplate('typeEncoder.njk', {\n docs,\n encoderFunction: nameApi.encoderFunction(name),\n encoderType,\n looseName: nameApi.dataArgsType(name),\n manifest,\n strictName: nameApi.dataType(name),\n useTypeCast,\n })\n .mergeImportsWith(manifest.encoder)\n .addImports('solanaCodecsCore', `type ${encoderType}`);\n}\n","import type { TypeNode } from '@codama/nodes';\n\nimport { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragmentFromTemplate, mergeFragments } from './common';\nimport { getTypeDecoderFragment } from './typeDecoder';\nimport { getTypeEncoderFragment } from './typeEncoder';\n\nexport function getTypeCodecFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & {\n codecDocs?: string[];\n decoderDocs?: string[];\n encoderDocs?: string[];\n manifest: Pick<TypeManifest, 'decoder' | 'encoder'>;\n name: string;\n node: TypeNode;\n size: number | null;\n },\n): Fragment {\n const { name, manifest, nameApi } = scope;\n const codecType = typeof scope.size === 'number' ? 'FixedSizeCodec' : 'Codec';\n return mergeFragments(\n [\n getTypeEncoderFragment({ ...scope, docs: scope.encoderDocs }),\n getTypeDecoderFragment({ ...scope, docs: scope.decoderDocs }),\n fragmentFromTemplate('typeCodec.njk', {\n codecFunction: nameApi.codecFunction(name),\n codecType,\n decoderFunction: nameApi.decoderFunction(name),\n docs: scope.codecDocs,\n encoderFunction: nameApi.encoderFunction(name),\n looseName: nameApi.dataArgsType(name),\n manifest,\n strictName: nameApi.dataType(name),\n }).addImports('solanaCodecsCore', [`type ${codecType}`, 'combineCodec']),\n ],\n renders => renders.join('\\n\\n'),\n );\n}\n","import type { TypeNode } from '@codama/nodes';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, mergeFragments } from './common';\nimport { getTypeFragment } from './type';\nimport { getTypeCodecFragment } from './typeCodec';\n\nexport function getTypeWithCodecFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi'> & {\n codecDocs?: string[];\n decoderDocs?: string[];\n encoderDocs?: string[];\n manifest: TypeManifest;\n name: string;\n node: TypeNode;\n size: number | null;\n typeDocs?: string[];\n },\n): Fragment {\n return mergeFragments([getTypeFragment({ ...scope, docs: scope.typeDocs }), getTypeCodecFragment(scope)], renders =>\n renders.join('\\n\\n'),\n );\n}\n","import {\n type ConstantDiscriminatorNode,\n constantDiscriminatorNode,\n constantValueNode,\n constantValueNodeFromBytes,\n type DiscriminatorNode,\n type FieldDiscriminatorNode,\n isNode,\n isNodeFilter,\n type ProgramNode,\n type SizeDiscriminatorNode,\n type StructTypeNode,\n} from '@codama/nodes';\nimport { visit } from '@codama/visitors-core';\nimport { getBase64Decoder } from '@solana/codecs-strings';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { Fragment, fragment, mergeFragments } from './common';\n\n/**\n * ```\n * if (data.length === 72) {\n * return splTokenAccounts.TOKEN;\n * }\n *\n * if (containsBytes(data, getU32Encoder().encode(42), offset)) {\n * return splTokenAccounts.TOKEN;\n * }\n *\n * if (containsBytes(data, new Uint8Array([1, 2, 3]), offset)) {\n * return splTokenAccounts.TOKEN;\n * }\n * ```\n */\nexport function getDiscriminatorConditionFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {\n dataName: string;\n discriminators: DiscriminatorNode[];\n ifTrue: string;\n programNode: ProgramNode;\n struct: StructTypeNode;\n },\n): Fragment {\n return mergeFragments(\n scope.discriminators.flatMap(discriminator => {\n if (isNode(discriminator, 'sizeDiscriminatorNode')) {\n return [getSizeConditionFragment(discriminator, scope)];\n }\n if (isNode(discriminator, 'constantDiscriminatorNode')) {\n return [getByteConditionFragment(discriminator, scope)];\n }\n if (isNode(discriminator, 'fieldDiscriminatorNode')) {\n return [getFieldConditionFragment(discriminator, scope)];\n }\n return [];\n }),\n r => r.join(' && '),\n ).mapRender(r => `if (${r}) { ${scope.ifTrue}; }`);\n}\n\nfunction getSizeConditionFragment(\n discriminator: SizeDiscriminatorNode,\n scope: Pick<GlobalFragmentScope, 'typeManifestVisitor'> & {\n dataName: string;\n },\n): Fragment {\n const { dataName } = scope;\n return fragment(`${dataName}.length === ${discriminator.size}`);\n}\n\nfunction getByteConditionFragment(\n discriminator: ConstantDiscriminatorNode,\n scope: Pick<GlobalFragmentScope, 'typeManifestVisitor'> & {\n dataName: string;\n },\n): Fragment {\n const { dataName, typeManifestVisitor } = scope;\n const constant = visit(discriminator.constant, typeManifestVisitor).value;\n return constant\n .mapRender(r => `containsBytes(${dataName}, ${r}, ${discriminator.offset})`)\n .addImports('solanaCodecsCore', 'containsBytes');\n}\n\nfunction getFieldConditionFragment(\n discriminator: FieldDiscriminatorNode,\n scope: Pick<GlobalFragmentScope, 'typeManifestVisitor'> & {\n dataName: string;\n struct: StructTypeNode;\n },\n): Fragment {\n const field = scope.struct.fields.find(f => f.name === discriminator.name);\n if (!field || !field.defaultValue) {\n // TODO: Coded error.\n throw new Error(\n `Field discriminator \"${discriminator.name}\" does not have a matching argument with default value.`,\n );\n }\n\n // This handles the case where a field uses an u8 array to represent its discriminator.\n // In this case, we can simplify the generated code by delegating to a constantDiscriminatorNode.\n if (\n isNode(field.type, 'arrayTypeNode') &&\n isNode(field.type.item, 'numberTypeNode') &&\n field.type.item.format === 'u8' &&\n isNode(field.type.count, 'fixedCountNode') &&\n isNode(field.defaultValue, 'arrayValueNode') &&\n field.defaultValue.items.every(isNodeFilter('numberValueNode'))\n ) {\n const base64Bytes = getBase64Decoder().decode(\n new Uint8Array(field.defaultValue.items.map(node => node.number)),\n );\n return getByteConditionFragment(\n constantDiscriminatorNode(constantValueNodeFromBytes('base64', base64Bytes), discriminator.offset),\n scope,\n );\n }\n\n return getByteConditionFragment(\n constantDiscriminatorNode(constantValueNode(field.type, field.defaultValue), discriminator.offset),\n scope,\n );\n}\n","import { InstructionAccountNode, pascalCase } from '@codama/nodes';\n\nimport { Fragment, fragment } from './common';\n\nexport function getInstructionAccountMetaFragment(instructionAccountNode: InstructionAccountNode): Fragment {\n const typeParam = `TAccount${pascalCase(instructionAccountNode.name)}`;\n\n // Writable, signer.\n if (instructionAccountNode.isSigner === true && instructionAccountNode.isWritable) {\n return fragment(`WritableSignerAccount<${typeParam}> & AccountSignerMeta<${typeParam}>`)\n .addImports('solanaInstructions', ['type WritableSignerAccount'])\n .addImports('solanaSigners', ['type AccountSignerMeta']);\n }\n\n // Readonly, signer.\n if (instructionAccountNode.isSigner === true) {\n return fragment(`ReadonlySignerAccount<${typeParam}> & AccountSignerMeta<${typeParam}>`)\n .addImports('solanaInstructions', ['type ReadonlySignerAccount'])\n .addImports('solanaSigners', ['type AccountSignerMeta']);\n }\n\n // Writable, non-signer or optional signer.\n if (instructionAccountNode.isWritable) {\n return fragment(`WritableAccount<${typeParam}>`).addImports('solanaInstructions', 'type WritableAccount');\n }\n\n // Readonly, non-signer or optional signer.\n return fragment(`ReadonlyAccount<${typeParam}>`).addImports('solanaInstructions', 'type ReadonlyAccount');\n}\n","import { InstructionAccountNode, InstructionInputValueNode, pascalCase } from '@codama/nodes';\nimport {\n findInstructionNodeFromPath,\n findProgramNodeFromPath,\n getLastNodeFromPath,\n LinkableDictionary,\n NodePath,\n} from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { ImportMap } from '../ImportMap';\nimport { Fragment, fragment } from './common';\n\nexport function getInstructionAccountTypeParamFragment(\n scope: Pick<GlobalFragmentScope, 'linkables'> & {\n allowAccountMeta: boolean;\n instructionAccountPath: NodePath<InstructionAccountNode>;\n },\n): Fragment {\n const { instructionAccountPath, allowAccountMeta, linkables } = scope;\n const instructionAccountNode = getLastNodeFromPath(instructionAccountPath);\n const instructionNode = findInstructionNodeFromPath(instructionAccountPath)!;\n const programNode = findProgramNodeFromPath(instructionAccountPath)!;\n const typeParam = `TAccount${pascalCase(instructionAccountNode.name)}`;\n const accountMeta = allowAccountMeta ? ' | AccountMeta<string>' : '';\n const imports = new ImportMap();\n if (allowAccountMeta) {\n imports.add('solanaInstructions', 'type AccountMeta');\n }\n\n if (instructionNode.optionalAccountStrategy === 'omitted' && instructionAccountNode.isOptional) {\n return fragment(`${typeParam} extends string${accountMeta} | undefined = undefined`, imports);\n }\n\n const defaultAddress = getDefaultAddress(instructionAccountNode.defaultValue, programNode.publicKey, linkables);\n\n return fragment(`${typeParam} extends string${accountMeta} = ${defaultAddress}`, imports);\n}\n\nfunction getDefaultAddress(\n defaultValue: InstructionInputValueNode | undefined,\n programId: string,\n linkables: LinkableDictionary,\n): string {\n switch (defaultValue?.kind) {\n case 'publicKeyValueNode':\n return `\"${defaultValue.publicKey}\"`;\n case 'programLinkNode':\n // eslint-disable-next-line no-case-declarations\n const programNode = linkables.get([defaultValue]);\n return programNode ? `\"${programNode.publicKey}\"` : 'string';\n case 'programIdValueNode':\n return `\"${programId}\"`;\n default:\n return 'string';\n }\n}\n","import { assertIsNode, camelCase, InstructionByteDeltaNode, InstructionNode, isNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { Fragment, fragment, mergeFragments } from './common';\n\nexport function getInstructionByteDeltaFragment(\n scope: Pick<GlobalFragmentScope, 'asyncResolvers' | 'getImportFrom' | 'nameApi'> & {\n instructionPath: NodePath<InstructionNode>;\n useAsync: boolean;\n },\n): Fragment {\n const { byteDeltas } = getLastNodeFromPath(scope.instructionPath);\n const fragments = (byteDeltas ?? []).flatMap(r => getByteDeltaFragment(r, scope));\n if (fragments.length === 0) return fragment('');\n return mergeFragments(\n fragments,\n r =>\n `// Bytes created or reallocated by the instruction.\\n` +\n `const byteDelta: number = [${r.join(',')}].reduce((a, b) => a + b, 0);`,\n );\n}\n\nfunction getByteDeltaFragment(\n byteDelta: InstructionByteDeltaNode,\n scope: Pick<GlobalFragmentScope, 'asyncResolvers' | 'getImportFrom' | 'nameApi'> & {\n useAsync: boolean;\n },\n): Fragment[] {\n const bytesFragment = ((): Fragment | null => {\n if (isNode(byteDelta.value, 'numberValueNode')) {\n return getNumberValueNodeFragment(byteDelta);\n }\n if (isNode(byteDelta.value, 'argumentValueNode')) {\n return getArgumentValueNodeFragment(byteDelta);\n }\n if (isNode(byteDelta.value, 'accountLinkNode')) {\n return getAccountLinkNodeFragment(byteDelta, scope);\n }\n if (isNode(byteDelta.value, 'resolverValueNode')) {\n return getResolverValueNodeFragment(byteDelta, scope);\n }\n return null;\n })();\n\n if (bytesFragment === null) return [];\n\n if (byteDelta.withHeader) {\n bytesFragment.mapRender(r => `${r} + BASE_ACCOUNT_SIZE`).addImports('solanaAccounts', 'BASE_ACCOUNT_SIZE');\n }\n\n if (byteDelta.subtract) {\n bytesFragment.mapRender(r => `- (${r})`);\n }\n\n return [bytesFragment];\n}\n\nfunction getNumberValueNodeFragment(byteDelta: InstructionByteDeltaNode): Fragment {\n assertIsNode(byteDelta.value, 'numberValueNode');\n return fragment(byteDelta.value.number.toString());\n}\n\nfunction getArgumentValueNodeFragment(byteDelta: InstructionByteDeltaNode): Fragment {\n assertIsNode(byteDelta.value, 'argumentValueNode');\n const argumentName = camelCase(byteDelta.value.name);\n return fragment(`Number(args.${argumentName})`);\n}\n\nfunction getAccountLinkNodeFragment(\n byteDelta: InstructionByteDeltaNode,\n scope: Pick<GlobalFragmentScope, 'getImportFrom' | 'nameApi'>,\n): Fragment {\n assertIsNode(byteDelta.value, 'accountLinkNode');\n const functionName = scope.nameApi.accountGetSizeFunction(byteDelta.value.name);\n return fragment(`${functionName}()`).addImports(scope.getImportFrom(byteDelta.value), functionName);\n}\n\nfunction getResolverValueNodeFragment(\n byteDelta: InstructionByteDeltaNode,\n scope: Pick<GlobalFragmentScope, 'asyncResolvers' | 'getImportFrom' | 'nameApi'> & {\n useAsync: boolean;\n },\n): Fragment | null {\n assertIsNode(byteDelta.value, 'resolverValueNode');\n const isAsync = scope.asyncResolvers.includes(byteDelta.value.name);\n if (!scope.useAsync && isAsync) return null;\n\n const awaitKeyword = scope.useAsync && isAsync ? 'await ' : '';\n const functionName = scope.nameApi.resolverFunction(byteDelta.value.name);\n return fragment(`${awaitKeyword}${functionName}(resolverScope)`)\n .addImports(scope.getImportFrom(byteDelta.value), functionName)\n .addFeatures(['instruction:resolverScopeVariable']);\n}\n","import { InstructionNode, structTypeNodeFromInstructionArgumentNodes } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { TypeManifest } from '../TypeManifest';\nimport { Fragment, fragment } from './common';\nimport { getTypeWithCodecFragment } from './typeWithCodec';\n\nexport function getInstructionDataFragment(\n scope: Pick<GlobalFragmentScope, 'customInstructionData' | 'nameApi'> & {\n dataArgsManifest: TypeManifest;\n instructionPath: NodePath<InstructionNode>;\n size: number | null;\n },\n): Fragment {\n const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope;\n const instructionNode = getLastNodeFromPath(instructionPath);\n if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) {\n return fragment('');\n }\n\n const instructionDataName = nameApi.instructionDataType(instructionNode.name);\n return getTypeWithCodecFragment({\n manifest: dataArgsManifest,\n name: instructionDataName,\n nameApi,\n node: structTypeNodeFromInstructionArgumentNodes(instructionNode.arguments),\n size: scope.size,\n });\n}\n","import {\n camelCase,\n ConstantDiscriminatorNode,\n DiscriminatorNode,\n FieldDiscriminatorNode,\n InstructionArgumentNode,\n isNode,\n isNodeFilter,\n StructFieldTypeNode,\n VALUE_NODES,\n} from '@codama/nodes';\nimport { visit } from '@codama/visitors-core';\n\nimport type { GlobalFragmentScope } from '../getRenderMapVisitor';\nimport { Fragment, mergeFragments } from './common';\n\nexport function getDiscriminatorConstantsFragment(\n scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {\n discriminatorNodes: DiscriminatorNode[];\n fields: InstructionArgumentNode[] | StructFieldTypeNode[];\n prefix: string;\n },\n): Fragment {\n const fragments = scope.discriminatorNodes\n .map(node => getDiscriminatorConstantFragment(node, scope))\n .filter(Boolean) as Fragment[];\n\n return mergeFragments(fragments, r => r.join('\\n\\n'));\n}\n\nexport function getDiscriminatorConstantFragment(\n discriminatorNode: DiscriminatorNode,\n scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {\n discriminatorNodes: DiscriminatorNode[];\n fields: InstructionArgumentNode[] | StructFieldTypeNode[];\n prefix: string;\n },\n): Fragment | nu