UNPKG

@codama/visitors-core

Version:

Core visitors for the Codama framework

1 lines 159 kB
{"version":3,"sources":["../src/identityVisitor.ts","../src/staticVisitor.ts","../src/visitor.ts","../src/interceptVisitor.ts","../src/NodeSelector.ts","../src/NodeStack.ts","../src/NodePath.ts","../src/pipe.ts","../src/recordNodeStackVisitor.ts","../src/bottomUpTransformerVisitor.ts","../src/mapVisitor.ts","../src/consoleLogVisitor.ts","../src/topDownTransformerVisitor.ts","../src/deleteNodesVisitor.ts","../src/extendVisitor.ts","../src/getByteSizeVisitor.ts","../src/mergeVisitor.ts","../src/getDebugStringVisitor.ts","../src/getResolvedInstructionInputsVisitor.ts","../src/singleNodeVisitor.ts","../src/getUniqueHashStringVisitor.ts","../src/nonNullableIdentityVisitor.ts","../src/removeDocsVisitor.ts","../src/interceptFirstVisitVisitor.ts","../src/LinkableDictionary.ts","../src/recordLinkablesVisitor.ts","../src/voidVisitor.ts","../src/tapVisitor.ts"],"sourcesContent":["import {\n accountLinkNode,\n accountNode,\n amountTypeNode,\n arrayTypeNode,\n arrayValueNode,\n assertIsNestedTypeNode,\n assertIsNode,\n booleanTypeNode,\n conditionalValueNode,\n constantDiscriminatorNode,\n constantPdaSeedNode,\n constantValueNode,\n COUNT_NODES,\n dateTimeTypeNode,\n definedTypeLinkNode,\n definedTypeNode,\n DISCRIMINATOR_NODES,\n ENUM_VARIANT_TYPE_NODES,\n enumEmptyVariantTypeNode,\n enumStructVariantTypeNode,\n enumTupleVariantTypeNode,\n enumTypeNode,\n enumValueNode,\n fixedSizeTypeNode,\n hiddenPrefixTypeNode,\n hiddenSuffixTypeNode,\n INSTRUCTION_INPUT_VALUE_NODES,\n instructionAccountLinkNode,\n instructionAccountNode,\n instructionArgumentLinkNode,\n instructionArgumentNode,\n instructionByteDeltaNode,\n instructionLinkNode,\n instructionNode,\n instructionRemainingAccountsNode,\n mapEntryValueNode,\n mapTypeNode,\n mapValueNode,\n Node,\n NodeKind,\n optionTypeNode,\n PDA_SEED_NODES,\n pdaLinkNode,\n pdaNode,\n pdaSeedValueNode,\n pdaValueNode,\n postOffsetTypeNode,\n prefixedCountNode,\n preOffsetTypeNode,\n programNode,\n REGISTERED_NODE_KINDS,\n remainderOptionTypeNode,\n removeNullAndAssertIsNodeFilter,\n resolverValueNode,\n rootNode,\n sentinelTypeNode,\n setTypeNode,\n setValueNode,\n sizePrefixTypeNode,\n solAmountTypeNode,\n someValueNode,\n structFieldTypeNode,\n structFieldValueNode,\n structTypeNode,\n structValueNode,\n tupleTypeNode,\n tupleValueNode,\n TYPE_NODES,\n VALUE_NODES,\n variablePdaSeedNode,\n zeroableOptionTypeNode,\n} from '@codama/nodes';\n\nimport { staticVisitor } from './staticVisitor';\nimport { visit as baseVisit, Visitor } from './visitor';\n\nexport function identityVisitor<TNodeKind extends NodeKind = NodeKind>(\n options: { keys?: TNodeKind[] } = {},\n): Visitor<Node | null, TNodeKind> {\n const keys: NodeKind[] = options.keys ?? (REGISTERED_NODE_KINDS as TNodeKind[]);\n const visitor = staticVisitor(node => Object.freeze({ ...node }), { keys }) as Visitor<Node | null>;\n const visit =\n (v: Visitor<Node | null>) =>\n (node: Node): Node | null =>\n keys.includes(node.kind) ? baseVisit(node, v) : Object.freeze({ ...node });\n\n if (keys.includes('rootNode')) {\n visitor.visitRoot = function visitRoot(node) {\n const program = visit(this)(node.program);\n if (program === null) return null;\n assertIsNode(program, 'programNode');\n return rootNode(\n program,\n node.additionalPrograms.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('programNode')),\n );\n };\n }\n\n if (keys.includes('programNode')) {\n visitor.visitProgram = function visitProgram(node) {\n return programNode({\n ...node,\n accounts: node.accounts.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('accountNode')),\n definedTypes: node.definedTypes\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('definedTypeNode')),\n errors: node.errors.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('errorNode')),\n instructions: node.instructions\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionNode')),\n pdas: node.pdas.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('pdaNode')),\n });\n };\n }\n\n if (keys.includes('pdaNode')) {\n visitor.visitPda = function visitPda(node) {\n return pdaNode({\n ...node,\n seeds: node.seeds.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(PDA_SEED_NODES)),\n });\n };\n }\n\n if (keys.includes('accountNode')) {\n visitor.visitAccount = function visitAccount(node) {\n const data = visit(this)(node.data);\n if (data === null) return null;\n assertIsNode(data, 'structTypeNode');\n const pda = node.pda ? (visit(this)(node.pda) ?? undefined) : undefined;\n if (pda) assertIsNode(pda, 'pdaLinkNode');\n return accountNode({ ...node, data, pda });\n };\n }\n\n if (keys.includes('instructionNode')) {\n visitor.visitInstruction = function visitInstruction(node) {\n return instructionNode({\n ...node,\n accounts: node.accounts\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionAccountNode')),\n arguments: node.arguments\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionArgumentNode')),\n byteDeltas: node.byteDeltas\n ? node.byteDeltas\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionByteDeltaNode'))\n : undefined,\n discriminators: node.discriminators\n ? node.discriminators.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(DISCRIMINATOR_NODES))\n : undefined,\n extraArguments: node.extraArguments\n ? node.extraArguments\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionArgumentNode'))\n : undefined,\n remainingAccounts: node.remainingAccounts\n ? node.remainingAccounts\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter('instructionRemainingAccountsNode'))\n : undefined,\n subInstructions: node.subInstructions\n ? node.subInstructions.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('instructionNode'))\n : undefined,\n });\n };\n }\n\n if (keys.includes('instructionAccountNode')) {\n visitor.visitInstructionAccount = function visitInstructionAccount(node) {\n const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined;\n if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES);\n return instructionAccountNode({ ...node, defaultValue });\n };\n }\n\n if (keys.includes('instructionArgumentNode')) {\n visitor.visitInstructionArgument = function visitInstructionArgument(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined;\n if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES);\n return instructionArgumentNode({ ...node, defaultValue, type });\n };\n }\n\n if (keys.includes('instructionRemainingAccountsNode')) {\n visitor.visitInstructionRemainingAccounts = function visitInstructionRemainingAccounts(node) {\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, ['argumentValueNode', 'resolverValueNode']);\n return instructionRemainingAccountsNode(value, { ...node });\n };\n }\n\n if (keys.includes('instructionByteDeltaNode')) {\n visitor.visitInstructionByteDelta = function visitInstructionByteDelta(node) {\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, ['numberValueNode', 'accountLinkNode', 'argumentValueNode', 'resolverValueNode']);\n return instructionByteDeltaNode(value, { ...node });\n };\n }\n\n if (keys.includes('definedTypeNode')) {\n visitor.visitDefinedType = function visitDefinedType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return definedTypeNode({ ...node, type });\n };\n }\n\n if (keys.includes('arrayTypeNode')) {\n visitor.visitArrayType = function visitArrayType(node) {\n const size = visit(this)(node.count);\n if (size === null) return null;\n assertIsNode(size, COUNT_NODES);\n const item = visit(this)(node.item);\n if (item === null) return null;\n assertIsNode(item, TYPE_NODES);\n return arrayTypeNode(item, size);\n };\n }\n\n if (keys.includes('enumTypeNode')) {\n visitor.visitEnumType = function visitEnumType(node) {\n return enumTypeNode(\n node.variants.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(ENUM_VARIANT_TYPE_NODES)),\n { size: node.size },\n );\n };\n }\n\n if (keys.includes('enumStructVariantTypeNode')) {\n visitor.visitEnumStructVariantType = function visitEnumStructVariantType(node) {\n const newStruct = visit(this)(node.struct);\n if (!newStruct) {\n return enumEmptyVariantTypeNode(node.name);\n }\n assertIsNode(newStruct, 'structTypeNode');\n if (newStruct.fields.length === 0) {\n return enumEmptyVariantTypeNode(node.name);\n }\n return enumStructVariantTypeNode(node.name, newStruct);\n };\n }\n\n if (keys.includes('enumTupleVariantTypeNode')) {\n visitor.visitEnumTupleVariantType = function visitEnumTupleVariantType(node) {\n const newTuple = visit(this)(node.tuple);\n if (!newTuple) {\n return enumEmptyVariantTypeNode(node.name);\n }\n assertIsNode(newTuple, 'tupleTypeNode');\n if (newTuple.items.length === 0) {\n return enumEmptyVariantTypeNode(node.name);\n }\n return enumTupleVariantTypeNode(node.name, newTuple);\n };\n }\n\n if (keys.includes('mapTypeNode')) {\n visitor.visitMapType = function visitMapType(node) {\n const size = visit(this)(node.count);\n if (size === null) return null;\n assertIsNode(size, COUNT_NODES);\n const key = visit(this)(node.key);\n if (key === null) return null;\n assertIsNode(key, TYPE_NODES);\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, TYPE_NODES);\n return mapTypeNode(key, value, size);\n };\n }\n\n if (keys.includes('optionTypeNode')) {\n visitor.visitOptionType = function visitOptionType(node) {\n const prefix = visit(this)(node.prefix);\n if (prefix === null) return null;\n assertIsNestedTypeNode(prefix, 'numberTypeNode');\n const item = visit(this)(node.item);\n if (item === null) return null;\n assertIsNode(item, TYPE_NODES);\n return optionTypeNode(item, { ...node, prefix });\n };\n }\n\n if (keys.includes('zeroableOptionTypeNode')) {\n visitor.visitZeroableOptionType = function visitZeroableOptionType(node) {\n const item = visit(this)(node.item);\n if (item === null) return null;\n assertIsNode(item, TYPE_NODES);\n const zeroValue = node.zeroValue ? (visit(this)(node.zeroValue) ?? undefined) : undefined;\n if (zeroValue) assertIsNode(zeroValue, 'constantValueNode');\n return zeroableOptionTypeNode(item, zeroValue);\n };\n }\n\n if (keys.includes('remainderOptionTypeNode')) {\n visitor.visitRemainderOptionType = function visitRemainderOptionType(node) {\n const item = visit(this)(node.item);\n if (item === null) return null;\n assertIsNode(item, TYPE_NODES);\n return remainderOptionTypeNode(item);\n };\n }\n\n if (keys.includes('booleanTypeNode')) {\n visitor.visitBooleanType = function visitBooleanType(node) {\n const size = visit(this)(node.size);\n if (size === null) return null;\n assertIsNestedTypeNode(size, 'numberTypeNode');\n return booleanTypeNode(size);\n };\n }\n\n if (keys.includes('setTypeNode')) {\n visitor.visitSetType = function visitSetType(node) {\n const size = visit(this)(node.count);\n if (size === null) return null;\n assertIsNode(size, COUNT_NODES);\n const item = visit(this)(node.item);\n if (item === null) return null;\n assertIsNode(item, TYPE_NODES);\n return setTypeNode(item, size);\n };\n }\n\n if (keys.includes('structTypeNode')) {\n visitor.visitStructType = function visitStructType(node) {\n const fields = node.fields.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('structFieldTypeNode'));\n return structTypeNode(fields);\n };\n }\n\n if (keys.includes('structFieldTypeNode')) {\n visitor.visitStructFieldType = function visitStructFieldType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined;\n if (defaultValue) assertIsNode(defaultValue, VALUE_NODES);\n return structFieldTypeNode({ ...node, defaultValue, type });\n };\n }\n\n if (keys.includes('tupleTypeNode')) {\n visitor.visitTupleType = function visitTupleType(node) {\n const items = node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(TYPE_NODES));\n return tupleTypeNode(items);\n };\n }\n\n if (keys.includes('amountTypeNode')) {\n visitor.visitAmountType = function visitAmountType(node) {\n const number = visit(this)(node.number);\n if (number === null) return null;\n assertIsNestedTypeNode(number, 'numberTypeNode');\n return amountTypeNode(number, node.decimals, node.unit);\n };\n }\n\n if (keys.includes('dateTimeTypeNode')) {\n visitor.visitDateTimeType = function visitDateTimeType(node) {\n const number = visit(this)(node.number);\n if (number === null) return null;\n assertIsNestedTypeNode(number, 'numberTypeNode');\n return dateTimeTypeNode(number);\n };\n }\n\n if (keys.includes('solAmountTypeNode')) {\n visitor.visitSolAmountType = function visitSolAmountType(node) {\n const number = visit(this)(node.number);\n if (number === null) return null;\n assertIsNestedTypeNode(number, 'numberTypeNode');\n return solAmountTypeNode(number);\n };\n }\n\n if (keys.includes('prefixedCountNode')) {\n visitor.visitPrefixedCount = function visitPrefixedCount(node) {\n const prefix = visit(this)(node.prefix);\n if (prefix === null) return null;\n assertIsNestedTypeNode(prefix, 'numberTypeNode');\n return prefixedCountNode(prefix);\n };\n }\n\n if (keys.includes('arrayValueNode')) {\n visitor.visitArrayValue = function visitArrayValue(node) {\n return arrayValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES)));\n };\n }\n\n if (keys.includes('constantValueNode')) {\n visitor.visitConstantValue = function visitConstantValue(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, VALUE_NODES);\n return constantValueNode(type, value);\n };\n }\n\n if (keys.includes('enumValueNode')) {\n visitor.visitEnumValue = function visitEnumValue(node) {\n const enumLink = visit(this)(node.enum);\n if (enumLink === null) return null;\n assertIsNode(enumLink, ['definedTypeLinkNode']);\n const value = node.value ? (visit(this)(node.value) ?? undefined) : undefined;\n if (value) assertIsNode(value, ['structValueNode', 'tupleValueNode']);\n return enumValueNode(enumLink, node.variant, value);\n };\n }\n\n if (keys.includes('mapValueNode')) {\n visitor.visitMapValue = function visitMapValue(node) {\n return mapValueNode(\n node.entries.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('mapEntryValueNode')),\n );\n };\n }\n\n if (keys.includes('mapEntryValueNode')) {\n visitor.visitMapEntryValue = function visitMapEntryValue(node) {\n const key = visit(this)(node.key);\n if (key === null) return null;\n assertIsNode(key, VALUE_NODES);\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, VALUE_NODES);\n return mapEntryValueNode(key, value);\n };\n }\n\n if (keys.includes('setValueNode')) {\n visitor.visitSetValue = function visitSetValue(node) {\n return setValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES)));\n };\n }\n\n if (keys.includes('someValueNode')) {\n visitor.visitSomeValue = function visitSomeValue(node) {\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, VALUE_NODES);\n return someValueNode(value);\n };\n }\n\n if (keys.includes('structValueNode')) {\n visitor.visitStructValue = function visitStructValue(node) {\n return structValueNode(\n node.fields.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('structFieldValueNode')),\n );\n };\n }\n\n if (keys.includes('structFieldValueNode')) {\n visitor.visitStructFieldValue = function visitStructFieldValue(node) {\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, VALUE_NODES);\n return structFieldValueNode(node.name, value);\n };\n }\n\n if (keys.includes('tupleValueNode')) {\n visitor.visitTupleValue = function visitTupleValue(node) {\n return tupleValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES)));\n };\n }\n\n if (keys.includes('constantPdaSeedNode')) {\n visitor.visitConstantPdaSeed = function visitConstantPdaSeed(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, [...VALUE_NODES, 'programIdValueNode']);\n return constantPdaSeedNode(type, value);\n };\n }\n\n if (keys.includes('variablePdaSeedNode')) {\n visitor.visitVariablePdaSeed = function visitVariablePdaSeed(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return variablePdaSeedNode(node.name, type, node.docs);\n };\n }\n\n if (keys.includes('resolverValueNode')) {\n visitor.visitResolverValue = function visitResolverValue(node) {\n const dependsOn = (node.dependsOn ?? [])\n .map(visit(this))\n .filter(removeNullAndAssertIsNodeFilter(['accountValueNode', 'argumentValueNode']));\n return resolverValueNode(node.name, {\n ...node,\n dependsOn: dependsOn.length === 0 ? undefined : dependsOn,\n });\n };\n }\n\n if (keys.includes('conditionalValueNode')) {\n visitor.visitConditionalValue = function visitConditionalValue(node) {\n const condition = visit(this)(node.condition);\n if (condition === null) return null;\n assertIsNode(condition, ['resolverValueNode', 'accountValueNode', 'argumentValueNode']);\n const value = node.value ? (visit(this)(node.value) ?? undefined) : undefined;\n if (value) assertIsNode(value, VALUE_NODES);\n const ifTrue = node.ifTrue ? (visit(this)(node.ifTrue) ?? undefined) : undefined;\n if (ifTrue) assertIsNode(ifTrue, INSTRUCTION_INPUT_VALUE_NODES);\n const ifFalse = node.ifFalse ? (visit(this)(node.ifFalse) ?? undefined) : undefined;\n if (ifFalse) assertIsNode(ifFalse, INSTRUCTION_INPUT_VALUE_NODES);\n if (!ifTrue && !ifFalse) return null;\n return conditionalValueNode({ condition, ifFalse, ifTrue, value });\n };\n }\n\n if (keys.includes('pdaValueNode')) {\n visitor.visitPdaValue = function visitPdaValue(node) {\n const pda = visit(this)(node.pda);\n if (pda === null) return null;\n assertIsNode(pda, ['pdaLinkNode', 'pdaNode']);\n const seeds = node.seeds.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('pdaSeedValueNode'));\n return pdaValueNode(pda, seeds);\n };\n }\n\n if (keys.includes('pdaSeedValueNode')) {\n visitor.visitPdaSeedValue = function visitPdaSeedValue(node) {\n const value = visit(this)(node.value);\n if (value === null) return null;\n assertIsNode(value, [...VALUE_NODES, 'accountValueNode', 'argumentValueNode']);\n return pdaSeedValueNode(node.name, value);\n };\n }\n\n if (keys.includes('fixedSizeTypeNode')) {\n visitor.visitFixedSizeType = function visitFixedSizeType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return fixedSizeTypeNode(type, node.size);\n };\n }\n\n if (keys.includes('sizePrefixTypeNode')) {\n visitor.visitSizePrefixType = function visitSizePrefixType(node) {\n const prefix = visit(this)(node.prefix);\n if (prefix === null) return null;\n assertIsNestedTypeNode(prefix, 'numberTypeNode');\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return sizePrefixTypeNode(type, prefix);\n };\n }\n\n if (keys.includes('preOffsetTypeNode')) {\n visitor.visitPreOffsetType = function visitPreOffsetType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return preOffsetTypeNode(type, node.offset, node.strategy);\n };\n }\n\n if (keys.includes('postOffsetTypeNode')) {\n visitor.visitPostOffsetType = function visitPostOffsetType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return postOffsetTypeNode(type, node.offset, node.strategy);\n };\n }\n\n if (keys.includes('sentinelTypeNode')) {\n visitor.visitSentinelType = function visitSentinelType(node) {\n const sentinel = visit(this)(node.sentinel);\n if (sentinel === null) return null;\n assertIsNode(sentinel, 'constantValueNode');\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n return sentinelTypeNode(type, sentinel);\n };\n }\n\n if (keys.includes('hiddenPrefixTypeNode')) {\n visitor.visitHiddenPrefixType = function visitHiddenPrefixType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const prefix = node.prefix.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('constantValueNode'));\n if (prefix.length === 0) return type;\n return hiddenPrefixTypeNode(type, prefix);\n };\n }\n\n if (keys.includes('hiddenSuffixTypeNode')) {\n visitor.visitHiddenSuffixType = function visitHiddenSuffixType(node) {\n const type = visit(this)(node.type);\n if (type === null) return null;\n assertIsNode(type, TYPE_NODES);\n const suffix = node.suffix.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('constantValueNode'));\n if (suffix.length === 0) return type;\n return hiddenSuffixTypeNode(type, suffix);\n };\n }\n\n if (keys.includes('constantDiscriminatorNode')) {\n visitor.visitConstantDiscriminator = function visitConstantDiscriminator(node) {\n const constant = visit(this)(node.constant);\n if (constant === null) return null;\n assertIsNode(constant, 'constantValueNode');\n return constantDiscriminatorNode(constant, node.offset);\n };\n }\n\n if (keys.includes('accountLinkNode')) {\n visitor.visitAccountLink = function visitAccountLink(node) {\n const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined;\n if (program) assertIsNode(program, 'programLinkNode');\n return accountLinkNode(node.name, program);\n };\n }\n\n if (keys.includes('definedTypeLinkNode')) {\n visitor.visitDefinedTypeLink = function visitDefinedTypeLink(node) {\n const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined;\n if (program) assertIsNode(program, 'programLinkNode');\n return definedTypeLinkNode(node.name, program);\n };\n }\n\n if (keys.includes('instructionLinkNode')) {\n visitor.visitInstructionLink = function visitInstructionLink(node) {\n const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined;\n if (program) assertIsNode(program, 'programLinkNode');\n return instructionLinkNode(node.name, program);\n };\n }\n\n if (keys.includes('instructionAccountLinkNode')) {\n visitor.visitInstructionAccountLink = function visitInstructionAccountLink(node) {\n const instruction = node.instruction ? (visit(this)(node.instruction) ?? undefined) : undefined;\n if (instruction) assertIsNode(instruction, 'instructionLinkNode');\n return instructionAccountLinkNode(node.name, instruction);\n };\n }\n\n if (keys.includes('instructionArgumentLinkNode')) {\n visitor.visitInstructionArgumentLink = function visitInstructionArgumentLink(node) {\n const instruction = node.instruction ? (visit(this)(node.instruction) ?? undefined) : undefined;\n if (instruction) assertIsNode(instruction, 'instructionLinkNode');\n return instructionArgumentLinkNode(node.name, instruction);\n };\n }\n\n if (keys.includes('pdaLinkNode')) {\n visitor.visitPdaLink = function visitPdaLink(node) {\n const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined;\n if (program) assertIsNode(program, 'programLinkNode');\n return pdaLinkNode(node.name, program);\n };\n }\n\n return visitor as Visitor<Node, TNodeKind>;\n}\n","import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes';\n\nimport { getVisitFunctionName, Visitor } from './visitor';\n\nexport function staticVisitor<TReturn, TNodeKind extends NodeKind = NodeKind>(\n fn: (node: Node) => TReturn,\n options: { keys?: TNodeKind[] } = {},\n): Visitor<TReturn, TNodeKind> {\n const keys = options.keys ?? (REGISTERED_NODE_KINDS as TNodeKind[]);\n const visitor = {} as Visitor<TReturn>;\n keys.forEach(key => {\n visitor[getVisitFunctionName(key)] = fn.bind(visitor);\n });\n return visitor;\n}\n","import { CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CodamaError } from '@codama/errors';\nimport { type GetNodeFromKind, type Node, type NodeKind, pascalCase, REGISTERED_NODE_KINDS } from '@codama/nodes';\n\nexport type Visitor<TReturn, TNodeKind extends NodeKind = NodeKind> = {\n [K in TNodeKind as GetVisitorFunctionName<K>]: (node: GetNodeFromKind<K>) => TReturn;\n};\n\nexport type GetVisitorFunctionName<T extends Node['kind']> = T extends `${infer TWithoutNode}Node`\n ? `visit${Capitalize<TWithoutNode>}`\n : never;\n\nexport function visit<TReturn, TNode extends Node>(node: TNode, visitor: Visitor<TReturn, TNode['kind']>): TReturn {\n const key = getVisitFunctionName(node.kind) as GetVisitorFunctionName<TNode['kind']>;\n return (visitor[key] as (typeof visitor)[typeof key] & ((node: TNode) => TReturn))(node);\n}\n\nexport function visitOrElse<TReturn, TNode extends Node, TNodeKind extends NodeKind>(\n node: TNode,\n visitor: Visitor<TReturn, TNodeKind>,\n fallback: (node: TNode) => TReturn,\n): TReturn {\n const key = getVisitFunctionName<TNode['kind']>(node.kind);\n return (key in visitor ? (visitor[key] as (node: TNode) => TReturn) : fallback)(node);\n}\n\nexport function getVisitFunctionName<TNodeKind extends NodeKind>(nodeKind: TNodeKind) {\n if (!REGISTERED_NODE_KINDS.includes(nodeKind)) {\n throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: nodeKind });\n }\n\n return `visit${pascalCase(nodeKind.slice(0, -4))}` as GetVisitorFunctionName<TNodeKind>;\n}\n","import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes';\n\nimport { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor';\n\nexport type VisitorInterceptor<TReturn> = <TNode extends Node>(node: TNode, next: (node: TNode) => TReturn) => TReturn;\n\nexport function interceptVisitor<TReturn, TNodeKind extends NodeKind>(\n visitor: Visitor<TReturn, TNodeKind>,\n interceptor: VisitorInterceptor<TReturn>,\n): Visitor<TReturn, TNodeKind> {\n const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName);\n\n return Object.fromEntries(\n Object.keys(visitor).flatMap(key => {\n const castedKey = key as GetVisitorFunctionName<TNodeKind>;\n if (!registeredVisitFunctions.includes(castedKey)) {\n return [];\n }\n\n return [\n [\n castedKey,\n function interceptedVisitNode<TNode extends Node>(this: Visitor<TReturn, TNodeKind>, node: TNode) {\n const baseFunction = visitor[castedKey] as (node: TNode) => TReturn;\n return interceptor<TNode>(node, baseFunction.bind(this));\n },\n ],\n ];\n }),\n ) as Visitor<TReturn, TNodeKind>;\n}\n","import { camelCase, CamelCaseString, Node } from '@codama/nodes';\n\nimport { NodePath } from './NodePath';\n\nexport type NodeSelector = NodeSelectorFunction | NodeSelectorPath;\n\n/**\n * A string that can be used to select a node in a Codama tree.\n * - `*` matches any node.\n * - `someText` matches the name of a node, if any.\n * - `[someNode]` matches a node of the given kind.\n * - `[someNode|someOtherNode]` matches a node with any of the given kind.\n * - `[someNode]someText` matches both the kind and the name of a node.\n * - `a.b.c` matches a node `c` such that its ancestors contains `a` and `b` in order (but not necessarily subsequent).\n */\nexport type NodeSelectorPath = string;\n\nexport type NodeSelectorFunction = (path: NodePath) => boolean;\n\nexport const getNodeSelectorFunction = (selector: NodeSelector): NodeSelectorFunction => {\n if (typeof selector === 'function') return selector;\n\n const checkNode = (node: Node, nodeSelector: string): boolean => {\n if (nodeSelector === '*') return true;\n const matches = nodeSelector.match(/^(?:\\[([^\\]]+)\\])?(.*)?$/);\n if (!matches) return false;\n const [, kinds, name] = matches;\n\n // Check kinds.\n const kindArray = kinds ? kinds.split('|').map(camelCase) : [];\n if (kindArray.length > 0 && !kindArray.includes(node.kind as CamelCaseString)) {\n return false;\n }\n\n // Check names.\n if (name && (!('name' in node) || camelCase(name) !== node.name)) {\n return false;\n }\n\n return true;\n };\n\n const checkPath = (path: Node[], nodeSelectors: string[]): boolean => {\n if (nodeSelectors.length === 0) return true;\n if (path.length === 0) return false;\n const lastNode = path.pop() as Node;\n const lastNodeSelector = nodeSelectors.pop() as string;\n return checkNode(lastNode, lastNodeSelector)\n ? checkPath(path, nodeSelectors)\n : checkPath(path, [...nodeSelectors, lastNodeSelector]);\n };\n\n const checkInitialPath = (path: Node[], nodeSelectors: string[]): boolean => {\n if (nodeSelectors.length === 0 || path.length === 0) return false;\n const lastNode = path.pop() as Node;\n const lastNodeSelector = nodeSelectors.pop() as string;\n return checkNode(lastNode, lastNodeSelector) && checkPath(path, nodeSelectors);\n };\n\n const nodeSelectors = selector.split('.');\n return path => checkInitialPath([...path], [...nodeSelectors]);\n};\n\nexport const getConjunctiveNodeSelectorFunction = (selector: NodeSelector | NodeSelector[]): NodeSelectorFunction => {\n const selectors = Array.isArray(selector) ? selector : [selector];\n const selectorFunctions = selectors.map(getNodeSelectorFunction);\n return path => selectorFunctions.every(fn => fn(path));\n};\n","import { CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, CodamaError } from '@codama/errors';\nimport { GetNodeFromKind, Node, NodeKind } from '@codama/nodes';\n\nimport { assertIsNodePath, NodePath, nodePathToString } from './NodePath';\n\ntype MutableNodePath = Node[];\n\nexport class NodeStack {\n /**\n * Contains all the node paths saved during the traversal.\n *\n * - The very last path is the current path which is being\n * used during the traversal.\n * - The other paths can be used to save and restore the\n * current path when jumping to different parts of the tree.\n *\n * There must at least be one path in the stack at all times.\n */\n private readonly stack: [...MutableNodePath[], MutableNodePath];\n\n constructor(...stack: readonly [...(readonly NodePath[]), NodePath] | readonly []) {\n this.stack =\n stack.length === 0\n ? [[]]\n : ([...stack.map(nodes => [...nodes])] as [...MutableNodePath[], MutableNodePath]);\n }\n\n private get currentPath(): MutableNodePath {\n return this.stack[this.stack.length - 1];\n }\n\n public push(node: Node): void {\n this.currentPath.push(node);\n }\n\n public pop(): Node | undefined {\n return this.currentPath.pop();\n }\n\n public peek(): Node | undefined {\n return this.isEmpty() ? undefined : this.currentPath[this.currentPath.length - 1];\n }\n\n public pushPath(newPath: NodePath = []): void {\n this.stack.push([...newPath]);\n }\n\n public popPath(): NodePath {\n if (this.stack.length <= 1) {\n throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, {\n path: [...this.stack[this.stack.length - 1]],\n });\n }\n return [...this.stack.pop()!];\n }\n\n public getPath(): NodePath;\n public getPath<TKind extends NodeKind>(kind: TKind | TKind[]): NodePath<GetNodeFromKind<TKind>>;\n public getPath<TKind extends NodeKind>(kind?: TKind | TKind[]): NodePath {\n const path = [...this.currentPath];\n if (kind) {\n assertIsNodePath(path, kind);\n }\n return path;\n }\n\n public isEmpty(): boolean {\n return this.currentPath.length === 0;\n }\n\n public clone(): NodeStack {\n return new NodeStack(...this.stack);\n }\n\n public toString(): string {\n return nodePathToString(this.getPath());\n }\n}\n","import { assertIsNode, GetNodeFromKind, InstructionNode, isNode, Node, NodeKind, ProgramNode } from '@codama/nodes';\n\nexport type NodePath<TNode extends Node | undefined = undefined> = TNode extends undefined\n ? readonly Node[]\n : readonly [...(readonly Node[]), TNode];\n\nexport function getLastNodeFromPath<TNode extends Node>(path: NodePath<TNode>): TNode {\n return path[path.length - 1] as TNode;\n}\n\nexport function findFirstNodeFromPath<TKind extends NodeKind>(\n path: NodePath,\n kind: TKind | TKind[],\n): GetNodeFromKind<TKind> | undefined {\n return path.find(node => isNode(node, kind));\n}\n\nexport function findLastNodeFromPath<TKind extends NodeKind>(\n path: NodePath,\n kind: TKind | TKind[],\n): GetNodeFromKind<TKind> | undefined {\n for (let index = path.length - 1; index >= 0; index--) {\n const node = path[index];\n if (isNode(node, kind)) return node;\n }\n return undefined;\n}\n\nexport function findProgramNodeFromPath(path: NodePath): ProgramNode | undefined {\n return findLastNodeFromPath(path, 'programNode');\n}\n\nexport function findInstructionNodeFromPath(path: NodePath): InstructionNode | undefined {\n return findLastNodeFromPath(path, 'instructionNode');\n}\n\nexport function getNodePathUntilLastNode<TKind extends NodeKind>(\n path: NodePath,\n kind: TKind | TKind[],\n): NodePath<GetNodeFromKind<TKind>> | undefined {\n const lastIndex = (() => {\n for (let index = path.length - 1; index >= 0; index--) {\n const node = path[index];\n if (isNode(node, kind)) return index;\n }\n return -1;\n })();\n if (lastIndex === -1) return undefined;\n return path.slice(0, lastIndex + 1) as unknown as NodePath<GetNodeFromKind<TKind>>;\n}\n\nexport function isFilledNodePath(path: NodePath | null | undefined): path is NodePath<Node> {\n return !!path && path.length > 0;\n}\n\nexport function isNodePath<TKind extends NodeKind>(\n path: NodePath | null | undefined,\n kind: TKind | TKind[],\n): path is NodePath<GetNodeFromKind<TKind>> {\n return isNode(isFilledNodePath(path) ? getLastNodeFromPath<Node>(path) : null, kind);\n}\n\nexport function assertIsNodePath<TKind extends NodeKind>(\n path: NodePath | null | undefined,\n kind: TKind | TKind[],\n): asserts path is NodePath<GetNodeFromKind<TKind>> {\n assertIsNode(isFilledNodePath(path) ? getLastNodeFromPath<Node>(path) : null, kind);\n}\n\nexport function nodePathToStringArray(path: NodePath): string[] {\n return path.map((node): string => {\n return 'name' in node ? `[${node.kind}]${node.name}` : `[${node.kind}]`;\n });\n}\n\nexport function nodePathToString(path: NodePath): string {\n return nodePathToStringArray(path).join(' > ');\n}\n","/**\n * Copied from @solana/functional.\n * @see https://github.com/anza-xyz/kit/blob/main/packages/functional/src/pipe.ts\n *\n * ---\n *\n * General pipe function.\n * Provide an initial value and a list of functions to pipe it through.\n *\n * Following common implementations of pipe functions that use TypeScript,\n * this function supports a maximum arity of 10 for type safety.\n * @see https://github.com/ramda/ramda/blob/master/source/pipe.js\n * @see https://github.com/darky/rocket-pipes/blob/master/index.ts\n *\n * Note you can use nested pipes to extend this limitation, like so:\n * ```typescript\n * const myValue = pipe(\n * pipe(\n * 1,\n * (x) => x + 1,\n * (x) => x * 2,\n * (x) => x - 1,\n * ),\n * (y) => y / 3,\n * (y) => y + 1,\n * );\n * ```\n * @param init The initial value\n * @param fns Any number of functions to pipe the value through\n * @returns The final value with all functions applied\n */\nexport function pipe<TInitial>(init: TInitial): TInitial;\nexport function pipe<TInitial, R1>(init: TInitial, init_r1: (init: TInitial) => R1): R1;\nexport function pipe<TInitial, R1, R2>(init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2): R2;\nexport function pipe<TInitial, R1, R2, R3>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n): R3;\nexport function pipe<TInitial, R1, R2, R3, R4>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n): R4;\nexport function pipe<TInitial, R1, R2, R3, R4, R5>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n): R5;\nexport function pipe<TInitial, R1, R2, R3, R4, R5, R6>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n r5_r6: (r5: R5) => R6,\n): R6;\nexport function pipe<TInitial, R1, R2, R3, R4, R5, R6, R7>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n r5_r6: (r5: R5) => R6,\n r6_r7: (r6: R6) => R7,\n): R7;\nexport function pipe<TInitial, R1, R2, R3, R4, R5, R6, R7, R8>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n r5_r6: (r5: R5) => R6,\n r6_r7: (r6: R6) => R7,\n r7_r8: (r7: R7) => R8,\n): R8;\nexport function pipe<TInitial, R1, R2, R3, R4, R5, R6, R7, R8, R9>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n r5_r6: (r5: R5) => R6,\n r6_r7: (r6: R6) => R7,\n r7_r8: (r7: R7) => R8,\n r8_r9: (r8: R8) => R9,\n): R9;\nexport function pipe<TInitial, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10>(\n init: TInitial,\n init_r1: (init: TInitial) => R1,\n r1_r2: (r1: R1) => R2,\n r2_r3: (r2: R2) => R3,\n r3_r4: (r3: R3) => R4,\n r4_r5: (r4: R4) => R5,\n r5_r6: (r5: R5) => R6,\n r6_r7: (r6: R6) => R7,\n r7_r8: (r7: R7) => R8,\n r8_r9: (r8: R8) => R9,\n r9_r10: (r9: R9) => R10,\n): R10;\nexport function pipe<TInitial>(init: TInitial, ...fns: CallableFunction[]) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call\n return fns.reduce((acc, fn) => fn(acc), init);\n}\n","import { NodeKind } from '@codama/nodes';\n\nimport { interceptVisitor } from './interceptVisitor';\nimport { NodeStack } from './NodeStack';\nimport { Visitor } from './visitor';\n\nexport function recordNodeStackVisitor<TReturn, TNodeKind extends NodeKind>(\n visitor: Visitor<TReturn, TNodeKind>,\n stack: NodeStack,\n): Visitor<TReturn, TNodeKind> {\n return interceptVisitor(visitor, (node, next) => {\n stack.push(node);\n const newNode = next(node);\n stack.pop();\n return newNode;\n });\n}\n","import { Node, NodeKind } from '@codama/nodes';\n\nimport { identityVisitor } from './identityVisitor';\nimport { interceptVisitor } from './interceptVisitor';\nimport { getConjunctiveNodeSelectorFunction, NodeSelector } from './NodeSelector';\nimport { NodeStack } from './NodeStack';\nimport { pipe } from './pipe';\nimport { recordNodeStackVisitor } from './recordNodeStackVisitor';\nimport { Visitor } from './visitor';\n\nexport type BottomUpNodeTransformer = (node: Node, stack: NodeStack) => Node | null;\n\nexport type BottomUpNodeTransformerWithSelector = {\n select: NodeSelector | NodeSelector[];\n transform: BottomUpNodeTransformer;\n};\n\nexport function bottomUpTransformerVisitor<TNodeKind extends NodeKind = NodeKind>(\n transformers: (BottomUpNodeTransformer | BottomUpNodeTransformerWithSelector)[],\n options: { keys?: TNodeKind[]; stack?: NodeStack } = {},\n): Visitor<Node | null, TNodeKind> {\n const transformerFunctions = transformers.map((transformer): BottomUpNodeTransformer => {\n if (typeof transformer === 'function') return transformer;\n return (node, stack) =>\n getConjunctiveNodeSelectorFunction(transformer.select)(stack.getPath())\n ? transformer.transform(node, stack)\n : node;\n });\n\n const stack = options.stack ?? new NodeStack();\n return pipe(\n identityVisitor(options),\n v =>\n interceptVisitor(v, (node, next) => {\n return transformerFunctions.reduce(\n (acc, transformer) => (acc === null ? null : transformer(acc, stack)),\n next(node),\n );\n }),\n v => recordNodeStackVisitor(v, stack),\n );\n}\n","import { GetNodeFromKind, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes';\n\nimport { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor';\n\nexport function mapVisitor<TReturnFrom, TReturnTo, TNodeKind extends NodeKind>(\n visitor: Visitor<TReturnFrom, TNodeKind>,\n map: (from: TReturnFrom) => TReturnTo,\n): Visitor<TReturnTo, TNodeKind> {\n const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName);\n return Object.fromEntries(\n Object.keys(visitor).flatMap(key => {\n const castedKey = key as GetVisitorFunctionName<TNodeKind>;\n if (!registeredVisitFunctions.includes(castedKey)) {\n return [];\n }\n\n return [\n [\n castedKey,\n (node: GetNodeFromKind<TNodeKind>) =>\n map((visitor[castedKey] as (node: GetNodeFromKind<TNodeKind>) => TReturnFrom)(node)),\n ],\n ];\n }),\n ) as unknown as Visitor<TReturnTo, TNodeKind>;\n}\n","import { NodeKind } from '@codama/nodes';\n\nimport { mapVisitor } from './mapVisitor';\nimport { Visitor } from './visitor';\n\nexport function consoleLogVisitor<TNodeKind extends NodeKind = NodeKind>(\n visitor: Visitor<string, TNodeKind>,\n): Visitor<void, TNodeKind> {\n return mapVisitor(visitor, value => console.log(value));\n}\n","import { Node, NodeKind } from '@codama/nodes';\n\nimport { identityVisitor } from './identityVisitor';\nimport { interceptVisitor } from './interceptVisitor';\nimport { getConjunctiveNodeSelectorFunction, NodeSelector } from './NodeSelector';\nimport { NodeStack } from './NodeStack';\nimport { pipe } from './pipe';\nimport { recordNodeStackVisitor } from './recordNodeStackVisitor';\nimport { Visitor } from './visitor';\n\nexport type TopDownNodeTransformer = <TNode extends Node>(node: TNode, stack: NodeStack) => TNode | null;\n\nexport type TopDownNodeTransformerWithSelector = {\n select: NodeSelector | NodeSelector[];\n transform: TopDownNodeTransformer;\n};\n\nexport function topDownTransformerVisitor<TNodeKind extends NodeKind = NodeKind>(\n transformers: (TopDownNodeTransformer | TopDownNodeTransformerWithSelector)[],\n options: { keys?: TNodeKind[]; stack?: NodeStack } = {},\n): Visitor<Node | null, TNodeKind> {\n const transformerFunctions = transformers.map((transformer): TopDownNodeTransformer => {\n if (typeof transformer === 'function') return transformer;\n return (node, stack) =>\n getConjunctiveNodeSelectorFunction(transformer.select)(stack.getPath())\n ? transformer.transform(node, stack)\n : node;\n });\n\n const stack = options.stack ?? new NodeStack();\n return pipe(\n identityVisitor(options),\n v =>\n interceptVisitor(v, (node, next) => {\n const appliedNode = transformerFunctions.reduce(\n (acc, transformer) => (acc === null ? null : transformer(acc, stack)),\n node as Parameters<typeof next>[0] |