UNPKG

@codama/renderers-js

Version:

JavaScript renderer compatible with the Solana Kit library

1 lines 298 kB
{"version":3,"sources":["../src/utils/importMap.ts","../src/utils/nameTransformers.ts","../src/utils/fragment.ts","../src/utils/typeManifest.ts","../src/visitors/getRenderMapVisitor.ts","../src/fragments/accountFetchHelpers.ts","../src/utils/async.ts","../src/utils/codecs.ts","../src/utils/customData.ts","../src/utils/linkOverrides.ts","../src/fragments/accountPage.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/discriminatorConstants.ts","../src/fragments/discriminatorCondition.ts","../src/fragments/errorPage.ts","../src/fragments/indexPage.ts","../src/fragments/instructionAccountMeta.ts","../src/fragments/instructionAccountTypeParam.ts","../src/fragments/instructionByteDelta.ts","../src/fragments/instructionData.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/instructionPage.ts","../src/fragments/instructionParseFunction.ts","../src/fragments/instructionType.ts","../src/fragments/pdaFunction.ts","../src/fragments/pdaPage.ts","../src/fragments/programAccounts.ts","../src/fragments/programConstant.ts","../src/fragments/programInstructions.ts","../src/fragments/programPage.ts","../src/fragments/rootIndexPage.ts","../src/fragments/sharedPage.ts","../src/fragments/typeDiscriminatedUnionHelpers.ts","../src/fragments/typePage.ts","../src/visitors/getTypeManifestVisitor.ts","../src/visitors/renderVisitor.ts"],"sourcesContent":["const 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\ntype ImportInput = string;\ntype Module = string;\ntype UsedIdentifier = string;\ntype ImportInfo = Readonly<{\n importedIdentifier: string;\n isType: boolean;\n usedIdentifier: UsedIdentifier;\n}>;\n\nexport type ImportMap = ReadonlyMap<Module, ReadonlyMap<UsedIdentifier, ImportInfo>>;\n\nexport function createImportMap(): ImportMap {\n return Object.freeze(new Map());\n}\n\nexport function parseImportInput(input: ImportInput): ImportInfo {\n const matches = input.match(/^(type )?([^ ]+)(?: as (.+))?$/);\n if (!matches) return Object.freeze({ importedIdentifier: input, isType: false, usedIdentifier: input });\n\n const [_, isType, name, alias] = matches;\n return Object.freeze({\n importedIdentifier: name,\n isType: !!isType,\n usedIdentifier: alias ?? name,\n });\n}\n\nexport function addToImportMap(importMap: ImportMap, module: Module, imports: ImportInput[]): ImportMap {\n const parsedImports = imports.map(parseImportInput).map(i => [i.usedIdentifier, i] as const);\n return mergeImportMaps([importMap, new Map([[module, new Map(parsedImports)]])]);\n}\n\nexport function removeFromImportMap(\n importMap: ImportMap,\n module: Module,\n usedIdentifiers: UsedIdentifier[],\n): ImportMap {\n const newMap = new Map(importMap);\n const newModuleMap = new Map(newMap.get(module));\n usedIdentifiers.forEach(usedIdentifier => {\n newModuleMap.delete(usedIdentifier);\n });\n if (newModuleMap.size === 0) {\n newMap.delete(module);\n } else {\n newMap.set(module, newModuleMap);\n }\n return Object.freeze(newMap);\n}\n\nexport function mergeImportMaps(importMaps: ImportMap[]): ImportMap {\n if (importMaps.length === 0) return createImportMap();\n if (importMaps.length === 1) return importMaps[0];\n const mergedMap = new Map(importMaps[0]);\n for (const map of importMaps.slice(1)) {\n for (const [module, imports] of map) {\n const mergedModuleMap = (mergedMap.get(module) ?? new Map()) as Map<UsedIdentifier, ImportInfo>;\n for (const [usedIdentifier, importInfo] of imports) {\n const existingImportInfo = mergedModuleMap.get(usedIdentifier);\n // If two identical imports exist such that\n // one is a type import and the other is not,\n // then we must only keep the non-type import.\n const shouldOverwriteTypeOnly =\n existingImportInfo &&\n existingImportInfo.importedIdentifier === importInfo.importedIdentifier &&\n existingImportInfo.isType &&\n !importInfo.isType;\n if (!existingImportInfo || shouldOverwriteTypeOnly) {\n mergedModuleMap.set(usedIdentifier, importInfo);\n }\n }\n mergedMap.set(module, mergedModuleMap);\n }\n }\n return Object.freeze(mergedMap);\n}\n\nexport function importMapToString(\n importMap: ImportMap,\n dependencyMap: Record<string, string> = {},\n useGranularImports = false,\n): string {\n const resolvedMap = resolveImportMapModules(importMap, dependencyMap, useGranularImports);\n\n return [...resolvedMap.entries()]\n .sort(([a], [b]) => {\n const relative = Number(a.startsWith('.')) - Number(b.startsWith('.'));\n // Relative imports go last.\n if (relative !== 0) return relative;\n // Otherwise, sort alphabetically.\n return a.localeCompare(b);\n })\n .map(([module, imports]) => {\n const innerImports = [...imports.values()]\n .map(importInfoToString)\n .sort((a, b) => a.localeCompare(b))\n .join(', ');\n return `import { ${innerImports} } from '${module}';`;\n })\n .join('\\n');\n}\n\nfunction resolveImportMapModules(\n importMap: ImportMap,\n dependencyMap: Record<string, string>,\n useGranularImports: boolean,\n): ImportMap {\n const dependencyMapWithDefaults = {\n ...(useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP),\n ...DEFAULT_INTERNAL_MODULE_MAP,\n ...dependencyMap,\n };\n\n return mergeImportMaps(\n [...importMap.entries()].map(([module, imports]) => {\n const resolvedModule = dependencyMapWithDefaults[module] ?? module;\n return new Map([[resolvedModule, imports]]);\n }),\n );\n}\n\nfunction importInfoToString({ importedIdentifier, isType, usedIdentifier }: ImportInfo): string {\n const alias = importedIdentifier !== usedIdentifier ? ` as ${usedIdentifier}` : '';\n return `${isType ? 'type ' : ''}${importedIdentifier}${alias}`;\n}\n","import { camelCase, capitalize, kebabCase, pascalCase, snakeCase, titleCase } from '@codama/nodes';\n\nexport type NameTransformerHelpers = {\n camelCase: (name: string) => string;\n capitalize: (name: string) => string;\n kebabCase: (name: string) => string;\n pascalCase: (name: string) => string;\n snakeCase: (name: string) => string;\n titleCase: (name: string) => string;\n};\n\nexport type NameTransformer = (name: string, helpers: NameTransformerHelpers) => string;\n\nexport type NameTransformerKey =\n | 'accountDecodeFunction'\n | 'accountFetchAllFunction'\n | 'accountFetchAllMaybeFunction'\n | 'accountFetchFromSeedsFunction'\n | 'accountFetchFunction'\n | 'accountFetchMaybeFromSeedsFunction'\n | 'accountFetchMaybeFunction'\n | 'accountGetSizeFunction'\n | 'codecFunction'\n | 'constant'\n | 'constantFunction'\n | 'dataArgsType'\n | 'dataType'\n | 'decoderFunction'\n | 'discriminatedUnionDiscriminator'\n | 'discriminatedUnionFunction'\n | 'discriminatedUnionVariant'\n | 'encoderFunction'\n | 'enumVariant'\n | 'instructionAsyncFunction'\n | 'instructionAsyncInputType'\n | 'instructionDataType'\n | 'instructionExtraType'\n | 'instructionParsedType'\n | 'instructionParseFunction'\n | 'instructionSyncFunction'\n | 'instructionSyncInputType'\n | 'instructionType'\n | 'isDiscriminatedUnionFunction'\n | 'pdaFindFunction'\n | 'pdaSeedsType'\n | 'programAccountsEnum'\n | 'programAccountsEnumVariant'\n | 'programAccountsIdentifierFunction'\n | 'programAddressConstant'\n | 'programErrorConstant'\n | 'programErrorConstantPrefix'\n | 'programErrorMessagesMap'\n | 'programErrorUnion'\n | 'programGetErrorMessageFunction'\n | 'programInstructionsEnum'\n | 'programInstructionsEnumVariant'\n | 'programInstructionsIdentifierFunction'\n | 'programInstructionsParsedUnionType'\n | 'programIsErrorFunction'\n | 'resolverFunction';\n\nexport type NameTransformers = Record<NameTransformerKey, NameTransformer>;\n\nexport type NameApi = Record<NameTransformerKey, (name: string) => string>;\n\nexport function getNameApi(transformers: NameTransformers): NameApi {\n const helpers = {\n camelCase,\n capitalize,\n kebabCase,\n pascalCase,\n snakeCase,\n titleCase,\n };\n return Object.fromEntries(\n Object.entries(transformers).map(([key, transformer]) => [key, (name: string) => transformer(name, helpers)]),\n ) as NameApi;\n}\n\nexport const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {\n accountDecodeFunction: name => `decode${pascalCase(name)}`,\n accountFetchAllFunction: name => `fetchAll${pascalCase(name)}`,\n accountFetchAllMaybeFunction: name => `fetchAllMaybe${pascalCase(name)}`,\n accountFetchFromSeedsFunction: name => `fetch${pascalCase(name)}FromSeeds`,\n accountFetchFunction: name => `fetch${pascalCase(name)}`,\n accountFetchMaybeFromSeedsFunction: name => `fetchMaybe${pascalCase(name)}FromSeeds`,\n accountFetchMaybeFunction: name => `fetchMaybe${pascalCase(name)}`,\n accountGetSizeFunction: name => `get${pascalCase(name)}Size`,\n codecFunction: name => `get${pascalCase(name)}Codec`,\n constant: name => snakeCase(name).toUpperCase(),\n constantFunction: name => `get${pascalCase(name)}Bytes`,\n dataArgsType: name => `${pascalCase(name)}Args`,\n dataType: name => `${pascalCase(name)}`,\n decoderFunction: name => `get${pascalCase(name)}Decoder`,\n discriminatedUnionDiscriminator: () => '__kind',\n discriminatedUnionFunction: name => `${camelCase(name)}`,\n discriminatedUnionVariant: name => `${pascalCase(name)}`,\n encoderFunction: name => `get${pascalCase(name)}Encoder`,\n enumVariant: name => `${pascalCase(name)}`,\n instructionAsyncFunction: name => `get${pascalCase(name)}InstructionAsync`,\n instructionAsyncInputType: name => `${pascalCase(name)}AsyncInput`,\n instructionDataType: name => `${pascalCase(name)}InstructionData`,\n instructionExtraType: name => `${pascalCase(name)}InstructionExtra`,\n instructionParseFunction: name => `parse${pascalCase(name)}Instruction`,\n instructionParsedType: name => `Parsed${pascalCase(name)}Instruction`,\n instructionSyncFunction: name => `get${pascalCase(name)}Instruction`,\n instructionSyncInputType: name => `${pascalCase(name)}Input`,\n instructionType: name => `${pascalCase(name)}Instruction`,\n isDiscriminatedUnionFunction: name => `is${pascalCase(name)}`,\n pdaFindFunction: name => `find${pascalCase(name)}Pda`,\n pdaSeedsType: name => `${pascalCase(name)}Seeds`,\n programAccountsEnum: name => `${pascalCase(name)}Account`,\n programAccountsEnumVariant: name => `${pascalCase(name)}`,\n programAccountsIdentifierFunction: name => `identify${pascalCase(name)}Account`,\n programAddressConstant: name => `${snakeCase(name).toUpperCase()}_PROGRAM_ADDRESS`,\n programErrorConstant: name => snakeCase(name).toUpperCase(),\n programErrorConstantPrefix: name => `${snakeCase(name).toUpperCase()}_ERROR__`,\n programErrorMessagesMap: name => `${camelCase(name)}ErrorMessages`,\n programErrorUnion: name => `${pascalCase(name)}Error`,\n programGetErrorMessageFunction: name => `get${pascalCase(name)}ErrorMessage`,\n programInstructionsEnum: name => `${pascalCase(name)}Instruction`,\n programInstructionsEnumVariant: name => `${pascalCase(name)}`,\n programInstructionsIdentifierFunction: name => `identify${pascalCase(name)}Instruction`,\n programInstructionsParsedUnionType: name => `Parsed${pascalCase(name)}Instruction`,\n programIsErrorFunction: name => `is${pascalCase(name)}Error`,\n resolverFunction: name => `${camelCase(name)}`,\n};\n","import { Docs } from '@codama/nodes';\nimport { BaseFragment, createFragmentTemplate } from '@codama/renderers-core';\n\nimport {\n addToImportMap,\n createImportMap,\n ImportMap,\n importMapToString,\n mergeImportMaps,\n parseImportInput,\n removeFromImportMap,\n} from './importMap';\nimport { RenderScope } from './options';\n\nexport type FragmentFeature = 'instruction:resolverScopeVariable';\n\nexport type Fragment = BaseFragment &\n Readonly<{\n features: ReadonlySet<FragmentFeature>;\n imports: ImportMap;\n }>;\n\nfunction createFragment(content: string): Fragment {\n return Object.freeze({ content, features: new Set<FragmentFeature>(), imports: createImportMap() });\n}\n\nfunction isFragment(value: unknown): value is Fragment {\n return typeof value === 'object' && value !== null && 'content' in value;\n}\n\nexport function fragment(template: TemplateStringsArray, ...items: unknown[]): Fragment {\n return createFragmentTemplate(template, items, isFragment, mergeFragments);\n}\n\nexport function mergeFragments(fragments: (Fragment | undefined)[], mergeContent: (contents: string[]) => string) {\n const filteredFragments = fragments.filter((f): f is Fragment => f !== undefined);\n return Object.freeze({\n content: mergeContent(filteredFragments.map(fragment => fragment.content)),\n features: new Set(filteredFragments.flatMap(f => [...f.features])),\n imports: mergeImportMaps(filteredFragments.map(f => f.imports)),\n });\n}\n\nexport function use(importInput: string, module: string): Fragment {\n const importInfo = parseImportInput(importInput);\n return addFragmentImports(createFragment(importInfo.usedIdentifier), module, [importInput]);\n}\n\nexport function mergeFragmentImports(fragment: Fragment, importMaps: ImportMap[]): Fragment {\n return Object.freeze({ ...fragment, imports: mergeImportMaps([fragment.imports, ...importMaps]) });\n}\n\nexport function addFragmentImports(fragment: Fragment, module: string, importInputs: string[]): Fragment {\n return Object.freeze({ ...fragment, imports: addToImportMap(fragment.imports, module, importInputs) });\n}\n\nexport function removeFragmentImports(fragment: Fragment, module: string, usedIdentifiers: string[]): Fragment {\n return Object.freeze({ ...fragment, imports: removeFromImportMap(fragment.imports, module, usedIdentifiers) });\n}\n\nexport function addFragmentFeatures(fragment: Fragment, features: FragmentFeature[]): Fragment {\n return Object.freeze({ ...fragment, features: new Set([...fragment.features, ...features]) });\n}\n\nexport function getExportAllFragment(module: string): Fragment {\n return fragment`export * from '${module}';`;\n}\n\nexport function getDocblockFragment(lines: Docs, withLineJump = false): Fragment | undefined {\n const lineJump = withLineJump ? '\\n' : '';\n if (lines.length === 0) return;\n if (lines.length === 1) return fragment`/** ${lines[0]} */${lineJump}`;\n const prefixedLines = lines.map(line => (line ? ` * ${line}` : ' *'));\n return fragment`/**\\n${prefixedLines.join('\\n')}\\n */${lineJump}`;\n}\n\nexport function getPageFragment(\n page: Fragment,\n scope: Pick<RenderScope, 'dependencyMap' | 'useGranularImports'>,\n): Fragment {\n const header = getDocblockFragment([\n 'This code was AUTOGENERATED using the Codama library.',\n 'Please DO NOT EDIT THIS FILE, instead use visitors',\n 'to add features, then rerun Codama to update it.',\n '',\n '@see https://github.com/codama-idl/codama',\n ]);\n const imports =\n page.imports.size === 0\n ? undefined\n : fragment`${importMapToString(page.imports, scope.dependencyMap, scope.useGranularImports)}`;\n return mergeFragments([header, imports, page], cs => cs.join('\\n\\n'));\n}\n","import { Fragment, fragment, mergeFragments } from './fragment';\n\nexport type TypeManifest = Readonly<{\n decoder: Fragment;\n encoder: Fragment;\n isEnum: boolean;\n looseType: Fragment;\n strictType: Fragment;\n value: Fragment;\n}>;\n\nexport function typeManifest(input: Partial<TypeManifest> = {}): TypeManifest {\n return Object.freeze({\n decoder: fragment``,\n encoder: fragment``,\n isEnum: false,\n looseType: fragment``,\n strictType: fragment``,\n value: fragment``,\n ...input,\n });\n}\n\nexport function mergeTypeManifests(\n manifests: TypeManifest[],\n options: {\n mergeCodecs?: (renders: string[]) => string;\n mergeTypes?: (renders: string[]) => string;\n mergeValues?: (renders: string[]) => string;\n } = {},\n): TypeManifest {\n const { mergeTypes, mergeCodecs, mergeValues } = options;\n const merge = (fragmentFn: (m: TypeManifest) => Fragment, mergeFn?: (r: string[]) => string) =>\n mergeFn ? mergeFragments(manifests.map(fragmentFn), mergeFn) : fragment``;\n return Object.freeze({\n decoder: merge(m => m.decoder, mergeCodecs),\n encoder: merge(m => m.encoder, mergeCodecs),\n isEnum: false,\n looseType: merge(m => m.looseType, mergeTypes),\n strictType: merge(m => m.strictType, mergeTypes),\n value: merge(m => m.value, mergeValues),\n });\n}\n","import {\n camelCase,\n CamelCaseString,\n getAllAccounts,\n getAllDefinedTypes,\n getAllInstructionsWithSubs,\n getAllPdas,\n getAllPrograms,\n} from '@codama/nodes';\nimport { createRenderMap, mergeRenderMaps } from '@codama/renderers-core';\nimport {\n extendVisitor,\n getByteSizeVisitor,\n getResolvedInstructionInputsVisitor,\n LinkableDictionary,\n NodeStack,\n pipe,\n recordLinkablesOnFirstVisitVisitor,\n recordNodeStackVisitor,\n staticVisitor,\n visit,\n} from '@codama/visitors-core';\n\nimport {\n getAccountPageFragment,\n getErrorPageFragment,\n getIndexPageFragment,\n getInstructionPageFragment,\n getPdaPageFragment,\n getProgramPageFragment,\n getRootIndexPageFragment,\n getSharedPageFragment,\n getTypePageFragment,\n} from '../fragments';\nimport {\n DEFAULT_NAME_TRANSFORMERS,\n Fragment,\n getDefinedTypeNodesToExtract,\n getImportFromFactory,\n getNameApi,\n getPageFragment,\n GetRenderMapOptions,\n parseCustomDataOptions,\n RenderScope,\n} from '../utils';\nimport { getTypeManifestVisitor } from './getTypeManifestVisitor';\n\nexport function getRenderMapVisitor(options: GetRenderMapOptions = {}) {\n const linkables = new LinkableDictionary();\n const stack = new NodeStack();\n\n const customAccountData = parseCustomDataOptions(options.customAccountData ?? [], 'AccountData');\n const customInstructionData = parseCustomDataOptions(options.customInstructionData ?? [], 'InstructionData');\n const renderScopeWithTypeManifestVisitor: Omit<RenderScope, 'typeManifestVisitor'> = {\n asyncResolvers: (options.asyncResolvers ?? []).map(camelCase),\n customAccountData,\n customInstructionData,\n dependencyMap: options.dependencyMap ?? {},\n getImportFrom: getImportFromFactory(options.linkOverrides ?? {}, customAccountData, customInstructionData),\n linkables,\n nameApi: getNameApi({ ...DEFAULT_NAME_TRANSFORMERS, ...options.nameTransformers }),\n nonScalarEnums: (options.nonScalarEnums ?? []).map(camelCase),\n renderParentInstructions: options.renderParentInstructions ?? false,\n useGranularImports: options.useGranularImports ?? false,\n };\n\n const typeManifestVisitor = getTypeManifestVisitor({ ...renderScopeWithTypeManifestVisitor, stack });\n const renderScope: RenderScope = { ...renderScopeWithTypeManifestVisitor, typeManifestVisitor };\n\n const internalNodes = (options.internalNodes ?? []).map(camelCase);\n const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();\n const byteSizeVisitor = getByteSizeVisitor(linkables, { stack });\n const asPage = <TFragment extends Fragment | undefined>(\n fragment: TFragment,\n dependencyMap: Record<string, string> = {},\n ): TFragment => {\n if (!fragment) return undefined as TFragment;\n return getPageFragment(fragment, {\n ...renderScope,\n dependencyMap: { ...renderScope.dependencyMap, ...dependencyMap },\n }) as TFragment;\n };\n\n return pipe(\n staticVisitor(() => createRenderMap(), {\n keys: ['rootNode', 'programNode', 'pdaNode', 'accountNode', 'definedTypeNode', 'instructionNode'],\n }),\n v =>\n extendVisitor(v, {\n visitAccount(node) {\n return createRenderMap(\n `accounts/${camelCase(node.name)}.ts`,\n asPage(\n getAccountPageFragment({\n ...renderScope,\n accountPath: stack.getPath('accountNode'),\n size: visit(node, byteSizeVisitor),\n }),\n ),\n );\n },\n\n visitDefinedType(node) {\n return createRenderMap(\n `types/${camelCase(node.name)}.ts`,\n asPage(getTypePageFragment({ ...renderScope, node, size: visit(node, byteSizeVisitor) }), {\n generatedTypes: '.',\n }),\n );\n },\n\n visitInstruction(node) {\n return createRenderMap(\n `instructions/${camelCase(node.name)}.ts`,\n asPage(\n getInstructionPageFragment({\n ...renderScope,\n instructionPath: stack.getPath('instructionNode'),\n resolvedInputs: visit(node, resolvedInstructionInputVisitor),\n size: visit(node, byteSizeVisitor),\n }),\n ),\n );\n },\n\n visitPda(node) {\n return createRenderMap(\n `pdas/${camelCase(node.name)}.ts`,\n asPage(getPdaPageFragment({ ...renderScope, pdaPath: stack.getPath('pdaNode') })),\n );\n },\n\n visitProgram(node, { self }) {\n const customDataDefinedType = [\n ...getDefinedTypeNodesToExtract(node.accounts, customAccountData),\n ...getDefinedTypeNodesToExtract(node.instructions, customInstructionData),\n ];\n const scope = { ...renderScope, programNode: node };\n\n return mergeRenderMaps([\n createRenderMap({\n [`programs/${camelCase(node.name)}.ts`]: asPage(getProgramPageFragment(scope)),\n [`errors/${camelCase(node.name)}.ts`]:\n node.errors.length > 0 ? asPage(getErrorPageFragment(scope)) : undefined,\n }),\n ...node.pdas.map(p => visit(p, self)),\n ...node.accounts.map(a => visit(a, self)),\n ...node.definedTypes.map(t => visit(t, self)),\n ...customDataDefinedType.map(t => visit(t, self)),\n ...getAllInstructionsWithSubs(node, { leavesOnly: !renderScope.renderParentInstructions }).map(\n i => visit(i, self),\n ),\n ]);\n },\n\n visitRoot(node, { self }) {\n const isNotInternal = (n: { name: CamelCaseString }) => !internalNodes.includes(n.name);\n const programsToExport = getAllPrograms(node).filter(isNotInternal);\n const programsWithErrorsToExport = programsToExport.filter(p => p.errors.length > 0);\n const pdasToExport = getAllPdas(node);\n const accountsToExport = getAllAccounts(node).filter(isNotInternal);\n const instructionsToExport = getAllInstructionsWithSubs(node, {\n leavesOnly: !renderScope.renderParentInstructions,\n }).filter(isNotInternal);\n const definedTypesToExport = getAllDefinedTypes(node).filter(isNotInternal);\n const hasAnythingToExport =\n programsToExport.length > 0 ||\n accountsToExport.length > 0 ||\n instructionsToExport.length > 0 ||\n definedTypesToExport.length > 0;\n\n const scope = {\n ...renderScope,\n accountsToExport,\n definedTypesToExport,\n instructionsToExport,\n pdasToExport,\n programsToExport,\n };\n\n return mergeRenderMaps([\n createRenderMap({\n ['accounts/index.ts']: asPage(getIndexPageFragment(accountsToExport)),\n ['errors/index.ts']: asPage(getIndexPageFragment(programsWithErrorsToExport)),\n ['index.ts']: asPage(getRootIndexPageFragment(scope)),\n ['instructions/index.ts']: asPage(getIndexPageFragment(instructionsToExport)),\n ['pdas/index.ts']: asPage(getIndexPageFragment(pdasToExport)),\n ['programs/index.ts']: asPage(getIndexPageFragment(programsToExport)),\n ['shared/index.ts']: hasAnythingToExport ? asPage(getSharedPageFragment()) : undefined,\n ['types/index.ts']: asPage(getIndexPageFragment(definedTypesToExport)),\n }),\n ...getAllPrograms(node).map(p => visit(p, self)),\n ]);\n },\n }),\n v => recordNodeStackVisitor(v, stack),\n v => recordLinkablesOnFirstVisitVisitor(v, linkables),\n );\n}\n","import { AccountNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath, pipe } from '@codama/visitors-core';\n\nimport { addFragmentImports, Fragment, fragment, RenderScope, TypeManifest } from '../utils';\n\nexport function getAccountFetchHelpersFragment(\n scope: Pick<RenderScope, '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 decodeFunction = nameApi.accountDecodeFunction(accountNode.name);\n const fetchAllFunction = nameApi.accountFetchAllFunction(accountNode.name);\n const fetchAllMaybeFunction = nameApi.accountFetchAllMaybeFunction(accountNode.name);\n const fetchFunction = nameApi.accountFetchFunction(accountNode.name);\n const fetchMaybeFunction = nameApi.accountFetchMaybeFunction(accountNode.name);\n\n const hasCustomData = customAccountData.has(accountNode.name);\n const accountType = hasCustomData ? typeManifest.strictType : nameApi.dataType(accountNode.name);\n const decoderFunction = hasCustomData ? typeManifest.decoder : `${nameApi.decoderFunction(accountNode.name)}()`;\n\n return pipe(\n fragment`export function ${decodeFunction}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): Account<${accountType}, TAddress>;\nexport function ${decodeFunction}<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): MaybeAccount<${accountType}, TAddress>;\nexport function ${decodeFunction}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>): Account<${accountType}, TAddress> | MaybeAccount<${accountType}, TAddress> {\n return decodeAccount(encodedAccount as MaybeEncodedAccount<TAddress>, ${decoderFunction});\n}\n\nexport async function ${fetchFunction}<TAddress extends string = string>(\n rpc: Parameters<typeof fetchEncodedAccount>[0],\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n): Promise<Account<${accountType}, TAddress>> {\n const maybeAccount = await ${fetchMaybeFunction}(rpc, address, config);\n assertAccountExists(maybeAccount);\n return maybeAccount;\n}\n\nexport async function ${fetchMaybeFunction}<TAddress extends string = string>(\n rpc: Parameters<typeof fetchEncodedAccount>[0],\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n): Promise<MaybeAccount<${accountType}, TAddress>> {\n const maybeAccount = await fetchEncodedAccount(rpc, address, config);\n return ${decodeFunction}(maybeAccount);\n}\n\nexport async function ${fetchAllFunction}(\n rpc: Parameters<typeof fetchEncodedAccounts>[0],\n addresses: Array<Address>,\n config?: FetchAccountsConfig,\n): Promise<Account<${accountType}>[]> {\n const maybeAccounts = await ${fetchAllMaybeFunction}(rpc, addresses, config);\n assertAccountsExist(maybeAccounts);\n return maybeAccounts;\n}\n\nexport async function ${fetchAllMaybeFunction}(\n rpc: Parameters<typeof fetchEncodedAccounts>[0],\n addresses: Array<Address>,\n config?: FetchAccountsConfig,\n): Promise<MaybeAccount<${accountType}>[]> {\n const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);\n return maybeAccounts.map((maybeAccount) => ${decodeFunction}(maybeAccount));\n}`,\n f => addFragmentImports(f, 'solanaAddresses', ['type Address']),\n f =>\n addFragmentImports(f, '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}\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 { AccountNode, resolveNestedTypeNode } from '@codama/nodes';\nimport { findProgramNodeFromPath, getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core';\n\nimport { Fragment, mergeFragments, RenderScope } from '../utils';\nimport { getAccountFetchHelpersFragment } from './accountFetchHelpers';\nimport { getAccountPdaHelpersFragment } from './accountPdaHelpers';\nimport { getAccountSizeHelpersFragment } from './accountSizeHelpers';\nimport { getAccountTypeFragment } from './accountType';\nimport { getDiscriminatorConstantsFragment } from './discriminatorConstants';\n\nexport function getAccountPageFragment(\n scope: Pick<RenderScope, 'customAccountData' | 'linkables' | 'nameApi' | 'typeManifestVisitor'> & {\n accountPath: NodePath<AccountNode>;\n size: number | null;\n },\n): Fragment {\n const node = getLastNodeFromPath(scope.accountPath);\n if (!findProgramNodeFromPath(scope.accountPath)) {\n throw new Error('Account must be visited inside a program.');\n }\n\n const typeManifest = visit(node, scope.typeManifestVisitor);\n const fields = resolveNestedTypeNode(node.data).fields;\n return mergeFragments(\n [\n getDiscriminatorConstantsFragment({\n ...scope,\n discriminatorNodes: node.discriminators ?? [],\n fields,\n prefix: node.name,\n }),\n getAccountTypeFragment({ ...scope, typeManifest }),\n getAccountFetchHelpersFragment({ ...scope, typeManifest }),\n getAccountSizeHelpersFragment(scope),\n getAccountPdaHelpersFragment({ ...scope, typeManifest }),\n ],\n cs => cs.join('\\n\\n'),\n );\n}\n","import { AccountNode, isNodeFilter } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath, pipe } from '@codama/visitors-core';\n\nimport { addFragmentImports, Fragment, fragment, RenderScope, TypeManifest } from '../utils';\n\nexport function getAccountPdaHelpersFragment(\n scope: Pick<RenderScope, 'customAccountData' | 'linkables' | 'nameApi'> & {\n accountPath: NodePath<AccountNode>;\n typeManifest: TypeManifest;\n },\n): Fragment | undefined {\n const { accountPath, nameApi, linkables, customAccountData, typeManifest } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : undefined;\n if (!pdaNode) return;\n\n const accountType = customAccountData.has(accountNode.name)\n ? typeManifest.strictType\n : 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 const fetchFromSeedsFunction = nameApi.accountFetchFromSeedsFunction(accountNode.name);\n const fetchMaybeFromSeedsFunction = nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name);\n const fetchMaybeFunction = nameApi.accountFetchMaybeFunction(accountNode.name);\n\n return pipe(\n fragment`export async function ${fetchFromSeedsFunction}(\n rpc: Parameters<typeof fetchEncodedAccount>[0],\n ${hasVariableSeeds ? `seeds: ${pdaSeedsType},` : ''}\n config: FetchAccountConfig & { programAddress?: Address } = {},\n): Promise<Account<${accountType}>> {\n const maybeAccount = await ${fetchMaybeFromSeedsFunction}(rpc, ${hasVariableSeeds ? 'seeds, ' : ''}config);\n assertAccountExists(maybeAccount);\n return maybeAccount;\n}\n\nexport async function ${fetchMaybeFromSeedsFunction}(\n rpc: Parameters<typeof fetchEncodedAccount>[0],\n ${hasVariableSeeds ? `seeds: ${pdaSeedsType},` : ''}\n config: FetchAccountConfig & { programAddress?: Address } = {},\n): Promise<MaybeAccount<${accountType}>> {\n const { programAddress, ...fetchConfig } = config;\n const [address] = await ${findPdaFunction}(${hasVariableSeeds ? 'seeds, ' : ''}{ programAddress });\n return await ${fetchMaybeFunction}(rpc, address, fetchConfig);\n}`,\n f => addFragmentImports(f, importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]),\n f => addFragmentImports(f, 'solanaAddresses', ['type Address']),\n f =>\n addFragmentImports(f, 'solanaAccounts', [\n 'type Account',\n 'assertAccountExists',\n 'type FetchAccountConfig',\n 'type MaybeAccount',\n ]),\n );\n}\n","import { AccountNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport { Fragment, fragment, RenderScope } from '../utils';\n\nexport function getAccountSizeHelpersFragment(\n scope: Pick<RenderScope, 'nameApi'> & { accountPath: NodePath<AccountNode> },\n): Fragment | undefined {\n const { accountPath, nameApi } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n if (accountNode.size == null) return;\n\n const getSizeFunction = nameApi.accountGetSizeFunction(accountNode.name);\n return fragment`export function ${getSizeFunction}(): number {\n return ${accountNode.size};\n}`;\n}\n","import { AccountNode, resolveNestedTypeNode } from '@codama/nodes';\nimport { getLastNodeFromPath, NodePath } from '@codama/visitors-core';\n\nimport { Fragment, RenderScope, TypeManifest } from '../utils';\nimport { getTypeWithCodecFragment } from './typeWithCodec';\n\nexport function getAccountTypeFragment(\n scope: Pick<RenderScope, 'customAccountData' | 'nameApi'> & {\n accountPath: NodePath<AccountNode>;\n size: number | null;\n typeManifest: TypeManifest;\n },\n): Fragment | undefined {\n const { accountPath, typeManifest, nameApi, customAccountData } = scope;\n const accountNode = getLastNodeFromPath(accountPath);\n if (customAccountData.has(accountNode.name)) return;\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 { Fragment, fragment, getDocblockFragment, RenderScope, TypeManifest } from '../utils';\n\nexport function getTypeFragment(\n scope: Pick<RenderScope, 'nameApi'> & {\n docs?: string[];\n manifest: TypeManifest;\n name: string;\n },\n): Fragment {\n const { name, manifest, nameApi, docs = [] } = scope;\n\n const docblock = getDocblockFragment(docs, true);\n const strictName = nameApi.dataType(name);\n const looseName = nameApi.dataArgsType(name);\n const aliasedLooseName = `export type ${looseName} = ${strictName};`;\n\n if (manifest.isEnum) {\n return fragment`${docblock}export enum ${strictName