UNPKG

@codama/visitors-core

Version:

Core visitors for the Codama framework

1,241 lines (1,230 loc) 79.6 kB
import { REGISTERED_NODE_KINDS, pascalCase, assertIsNode, rootNode, removeNullAndAssertIsNodeFilter, programNode, pdaNode, PDA_SEED_NODES, accountNode, instructionNode, DISCRIMINATOR_NODES, INSTRUCTION_INPUT_VALUE_NODES, instructionAccountNode, TYPE_NODES, instructionArgumentNode, instructionRemainingAccountsNode, instructionByteDeltaNode, instructionStatusNode, definedTypeNode, COUNT_NODES, arrayTypeNode, enumTypeNode, ENUM_VARIANT_TYPE_NODES, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, mapTypeNode, assertIsNestedTypeNode, optionTypeNode, zeroableOptionTypeNode, remainderOptionTypeNode, booleanTypeNode, setTypeNode, structTypeNode, VALUE_NODES, structFieldTypeNode, tupleTypeNode, amountTypeNode, dateTimeTypeNode, solAmountTypeNode, prefixedCountNode, arrayValueNode, constantValueNode, enumValueNode, mapValueNode, mapEntryValueNode, setValueNode, someValueNode, structValueNode, structFieldValueNode, tupleValueNode, constantPdaSeedNode, variablePdaSeedNode, resolverValueNode, conditionalValueNode, pdaValueNode, pdaSeedValueNode, fixedSizeTypeNode, sizePrefixTypeNode, preOffsetTypeNode, postOffsetTypeNode, sentinelTypeNode, hiddenPrefixTypeNode, hiddenSuffixTypeNode, constantDiscriminatorNode, accountLinkNode, definedTypeLinkNode, instructionLinkNode, instructionAccountLinkNode, instructionArgumentLinkNode, pdaLinkNode, isNode, getAllPrograms, REGISTERED_TYPE_NODE_KINDS, isScalarEnum, accountValueNode, argumentValueNode, getAllInstructionArguments, camelCase } from '@codama/nodes'; import { CodamaError, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE, CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY } from '@codama/errors'; import stringify from 'json-stable-stringify'; // src/bottomUpTransformerVisitor.ts function visit(node, visitor) { const key = getVisitFunctionName(node.kind); return visitor[key](node); } function visitOrElse(node, visitor, fallback) { const key = getVisitFunctionName(node.kind); return (key in visitor ? visitor[key] : fallback)(node); } function getVisitFunctionName(nodeKind) { if (!REGISTERED_NODE_KINDS.includes(nodeKind)) { throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: nodeKind }); } return `visit${pascalCase(nodeKind.slice(0, -4))}`; } // src/staticVisitor.ts function staticVisitor(fn, options = {}) { const keys = options.keys ?? REGISTERED_NODE_KINDS; const visitor = {}; keys.forEach((key) => { visitor[getVisitFunctionName(key)] = fn.bind(visitor); }); return visitor; } // src/identityVisitor.ts function identityVisitor(options = {}) { const keys = options.keys ?? REGISTERED_NODE_KINDS; const visitor = staticVisitor((node) => Object.freeze({ ...node }), { keys }); const visit2 = (v) => (node) => keys.includes(node.kind) ? visit(node, v) : Object.freeze({ ...node }); if (keys.includes("rootNode")) { visitor.visitRoot = function visitRoot(node) { const program = visit2(this)(node.program); if (program === null) return null; assertIsNode(program, "programNode"); return rootNode( program, node.additionalPrograms.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("programNode")) ); }; } if (keys.includes("programNode")) { visitor.visitProgram = function visitProgram(node) { return programNode({ ...node, accounts: node.accounts.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("accountNode")), definedTypes: node.definedTypes.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("definedTypeNode")), errors: node.errors.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("errorNode")), instructions: node.instructions.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionNode")), pdas: node.pdas.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("pdaNode")) }); }; } if (keys.includes("pdaNode")) { visitor.visitPda = function visitPda(node) { return pdaNode({ ...node, seeds: node.seeds.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(PDA_SEED_NODES)) }); }; } if (keys.includes("accountNode")) { visitor.visitAccount = function visitAccount(node) { const data = visit2(this)(node.data); if (data === null) return null; assertIsNode(data, "structTypeNode"); const pda = node.pda ? visit2(this)(node.pda) ?? void 0 : void 0; if (pda) assertIsNode(pda, "pdaLinkNode"); return accountNode({ ...node, data, pda }); }; } if (keys.includes("instructionNode")) { visitor.visitInstruction = function visitInstruction(node) { const status = node.status ? visit2(this)(node.status) ?? void 0 : void 0; if (status) assertIsNode(status, "instructionStatusNode"); return instructionNode({ ...node, accounts: node.accounts.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionAccountNode")), arguments: node.arguments.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionArgumentNode")), byteDeltas: node.byteDeltas ? node.byteDeltas.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionByteDeltaNode")) : void 0, discriminators: node.discriminators ? node.discriminators.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(DISCRIMINATOR_NODES)) : void 0, extraArguments: node.extraArguments ? node.extraArguments.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionArgumentNode")) : void 0, remainingAccounts: node.remainingAccounts ? node.remainingAccounts.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionRemainingAccountsNode")) : void 0, status, subInstructions: node.subInstructions ? node.subInstructions.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("instructionNode")) : void 0 }); }; } if (keys.includes("instructionAccountNode")) { visitor.visitInstructionAccount = function visitInstructionAccount(node) { const defaultValue = node.defaultValue ? visit2(this)(node.defaultValue) ?? void 0 : void 0; if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES); return instructionAccountNode({ ...node, defaultValue }); }; } if (keys.includes("instructionArgumentNode")) { visitor.visitInstructionArgument = function visitInstructionArgument(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const defaultValue = node.defaultValue ? visit2(this)(node.defaultValue) ?? void 0 : void 0; if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES); return instructionArgumentNode({ ...node, defaultValue, type }); }; } if (keys.includes("instructionRemainingAccountsNode")) { visitor.visitInstructionRemainingAccounts = function visitInstructionRemainingAccounts(node) { const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, ["argumentValueNode", "resolverValueNode"]); return instructionRemainingAccountsNode(value, { ...node }); }; } if (keys.includes("instructionByteDeltaNode")) { visitor.visitInstructionByteDelta = function visitInstructionByteDelta(node) { const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, ["numberValueNode", "accountLinkNode", "argumentValueNode", "resolverValueNode"]); return instructionByteDeltaNode(value, { ...node }); }; } if (keys.includes("instructionStatusNode")) { visitor.visitInstructionStatus = function visitInstructionStatus(node) { return instructionStatusNode(node.lifecycle, node.message); }; } if (keys.includes("definedTypeNode")) { visitor.visitDefinedType = function visitDefinedType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return definedTypeNode({ ...node, type }); }; } if (keys.includes("arrayTypeNode")) { visitor.visitArrayType = function visitArrayType(node) { const size = visit2(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const item = visit2(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return arrayTypeNode(item, size); }; } if (keys.includes("enumTypeNode")) { visitor.visitEnumType = function visitEnumType(node) { return enumTypeNode( node.variants.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(ENUM_VARIANT_TYPE_NODES)), { size: node.size } ); }; } if (keys.includes("enumStructVariantTypeNode")) { visitor.visitEnumStructVariantType = function visitEnumStructVariantType(node) { const newStruct = visit2(this)(node.struct); if (!newStruct) { return enumEmptyVariantTypeNode(node.name); } assertIsNode(newStruct, "structTypeNode"); if (newStruct.fields.length === 0) { return enumEmptyVariantTypeNode(node.name); } return enumStructVariantTypeNode(node.name, newStruct); }; } if (keys.includes("enumTupleVariantTypeNode")) { visitor.visitEnumTupleVariantType = function visitEnumTupleVariantType(node) { const newTuple = visit2(this)(node.tuple); if (!newTuple) { return enumEmptyVariantTypeNode(node.name); } assertIsNode(newTuple, "tupleTypeNode"); if (newTuple.items.length === 0) { return enumEmptyVariantTypeNode(node.name); } return enumTupleVariantTypeNode(node.name, newTuple); }; } if (keys.includes("mapTypeNode")) { visitor.visitMapType = function visitMapType(node) { const size = visit2(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const key = visit2(this)(node.key); if (key === null) return null; assertIsNode(key, TYPE_NODES); const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, TYPE_NODES); return mapTypeNode(key, value, size); }; } if (keys.includes("optionTypeNode")) { visitor.visitOptionType = function visitOptionType(node) { const prefix = visit2(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, "numberTypeNode"); const item = visit2(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return optionTypeNode(item, { ...node, prefix }); }; } if (keys.includes("zeroableOptionTypeNode")) { visitor.visitZeroableOptionType = function visitZeroableOptionType(node) { const item = visit2(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); const zeroValue = node.zeroValue ? visit2(this)(node.zeroValue) ?? void 0 : void 0; if (zeroValue) assertIsNode(zeroValue, "constantValueNode"); return zeroableOptionTypeNode(item, zeroValue); }; } if (keys.includes("remainderOptionTypeNode")) { visitor.visitRemainderOptionType = function visitRemainderOptionType(node) { const item = visit2(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return remainderOptionTypeNode(item); }; } if (keys.includes("booleanTypeNode")) { visitor.visitBooleanType = function visitBooleanType(node) { const size = visit2(this)(node.size); if (size === null) return null; assertIsNestedTypeNode(size, "numberTypeNode"); return booleanTypeNode(size); }; } if (keys.includes("setTypeNode")) { visitor.visitSetType = function visitSetType(node) { const size = visit2(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const item = visit2(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return setTypeNode(item, size); }; } if (keys.includes("structTypeNode")) { visitor.visitStructType = function visitStructType(node) { const fields = node.fields.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("structFieldTypeNode")); return structTypeNode(fields); }; } if (keys.includes("structFieldTypeNode")) { visitor.visitStructFieldType = function visitStructFieldType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const defaultValue = node.defaultValue ? visit2(this)(node.defaultValue) ?? void 0 : void 0; if (defaultValue) assertIsNode(defaultValue, VALUE_NODES); return structFieldTypeNode({ ...node, defaultValue, type }); }; } if (keys.includes("tupleTypeNode")) { visitor.visitTupleType = function visitTupleType(node) { const items = node.items.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(TYPE_NODES)); return tupleTypeNode(items); }; } if (keys.includes("amountTypeNode")) { visitor.visitAmountType = function visitAmountType(node) { const number = visit2(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, "numberTypeNode"); return amountTypeNode(number, node.decimals, node.unit); }; } if (keys.includes("dateTimeTypeNode")) { visitor.visitDateTimeType = function visitDateTimeType(node) { const number = visit2(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, "numberTypeNode"); return dateTimeTypeNode(number); }; } if (keys.includes("solAmountTypeNode")) { visitor.visitSolAmountType = function visitSolAmountType(node) { const number = visit2(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, "numberTypeNode"); return solAmountTypeNode(number); }; } if (keys.includes("prefixedCountNode")) { visitor.visitPrefixedCount = function visitPrefixedCount(node) { const prefix = visit2(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, "numberTypeNode"); return prefixedCountNode(prefix); }; } if (keys.includes("arrayValueNode")) { visitor.visitArrayValue = function visitArrayValue(node) { return arrayValueNode(node.items.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes("constantValueNode")) { visitor.visitConstantValue = function visitConstantValue(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return constantValueNode(type, value); }; } if (keys.includes("enumValueNode")) { visitor.visitEnumValue = function visitEnumValue(node) { const enumLink = visit2(this)(node.enum); if (enumLink === null) return null; assertIsNode(enumLink, ["definedTypeLinkNode"]); const value = node.value ? visit2(this)(node.value) ?? void 0 : void 0; if (value) assertIsNode(value, ["structValueNode", "tupleValueNode"]); return enumValueNode(enumLink, node.variant, value); }; } if (keys.includes("mapValueNode")) { visitor.visitMapValue = function visitMapValue(node) { return mapValueNode( node.entries.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("mapEntryValueNode")) ); }; } if (keys.includes("mapEntryValueNode")) { visitor.visitMapEntryValue = function visitMapEntryValue(node) { const key = visit2(this)(node.key); if (key === null) return null; assertIsNode(key, VALUE_NODES); const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return mapEntryValueNode(key, value); }; } if (keys.includes("setValueNode")) { visitor.visitSetValue = function visitSetValue(node) { return setValueNode(node.items.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes("someValueNode")) { visitor.visitSomeValue = function visitSomeValue(node) { const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return someValueNode(value); }; } if (keys.includes("structValueNode")) { visitor.visitStructValue = function visitStructValue(node) { return structValueNode( node.fields.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("structFieldValueNode")) ); }; } if (keys.includes("structFieldValueNode")) { visitor.visitStructFieldValue = function visitStructFieldValue(node) { const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return structFieldValueNode(node.name, value); }; } if (keys.includes("tupleValueNode")) { visitor.visitTupleValue = function visitTupleValue(node) { return tupleValueNode(node.items.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes("constantPdaSeedNode")) { visitor.visitConstantPdaSeed = function visitConstantPdaSeed(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, [...VALUE_NODES, "programIdValueNode"]); return constantPdaSeedNode(type, value); }; } if (keys.includes("variablePdaSeedNode")) { visitor.visitVariablePdaSeed = function visitVariablePdaSeed(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return variablePdaSeedNode(node.name, type, node.docs); }; } if (keys.includes("resolverValueNode")) { visitor.visitResolverValue = function visitResolverValue(node) { const dependsOn = (node.dependsOn ?? []).map(visit2(this)).filter(removeNullAndAssertIsNodeFilter(["accountValueNode", "argumentValueNode"])); return resolverValueNode(node.name, { ...node, dependsOn: dependsOn.length === 0 ? void 0 : dependsOn }); }; } if (keys.includes("conditionalValueNode")) { visitor.visitConditionalValue = function visitConditionalValue(node) { const condition = visit2(this)(node.condition); if (condition === null) return null; assertIsNode(condition, ["resolverValueNode", "accountValueNode", "argumentValueNode"]); const value = node.value ? visit2(this)(node.value) ?? void 0 : void 0; if (value) assertIsNode(value, VALUE_NODES); const ifTrue = node.ifTrue ? visit2(this)(node.ifTrue) ?? void 0 : void 0; if (ifTrue) assertIsNode(ifTrue, INSTRUCTION_INPUT_VALUE_NODES); const ifFalse = node.ifFalse ? visit2(this)(node.ifFalse) ?? void 0 : void 0; if (ifFalse) assertIsNode(ifFalse, INSTRUCTION_INPUT_VALUE_NODES); if (!ifTrue && !ifFalse) return null; return conditionalValueNode({ condition, ifFalse, ifTrue, value }); }; } if (keys.includes("pdaValueNode")) { visitor.visitPdaValue = function visitPdaValue(node) { const pda = visit2(this)(node.pda); if (pda === null) return null; assertIsNode(pda, ["pdaLinkNode", "pdaNode"]); const seeds = node.seeds.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("pdaSeedValueNode")); return pdaValueNode(pda, seeds); }; } if (keys.includes("pdaSeedValueNode")) { visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { const value = visit2(this)(node.value); if (value === null) return null; assertIsNode(value, [...VALUE_NODES, "accountValueNode", "argumentValueNode"]); return pdaSeedValueNode(node.name, value); }; } if (keys.includes("fixedSizeTypeNode")) { visitor.visitFixedSizeType = function visitFixedSizeType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return fixedSizeTypeNode(type, node.size); }; } if (keys.includes("sizePrefixTypeNode")) { visitor.visitSizePrefixType = function visitSizePrefixType(node) { const prefix = visit2(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, "numberTypeNode"); const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return sizePrefixTypeNode(type, prefix); }; } if (keys.includes("preOffsetTypeNode")) { visitor.visitPreOffsetType = function visitPreOffsetType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return preOffsetTypeNode(type, node.offset, node.strategy); }; } if (keys.includes("postOffsetTypeNode")) { visitor.visitPostOffsetType = function visitPostOffsetType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return postOffsetTypeNode(type, node.offset, node.strategy); }; } if (keys.includes("sentinelTypeNode")) { visitor.visitSentinelType = function visitSentinelType(node) { const sentinel = visit2(this)(node.sentinel); if (sentinel === null) return null; assertIsNode(sentinel, "constantValueNode"); const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return sentinelTypeNode(type, sentinel); }; } if (keys.includes("hiddenPrefixTypeNode")) { visitor.visitHiddenPrefixType = function visitHiddenPrefixType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const prefix = node.prefix.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("constantValueNode")); if (prefix.length === 0) return type; return hiddenPrefixTypeNode(type, prefix); }; } if (keys.includes("hiddenSuffixTypeNode")) { visitor.visitHiddenSuffixType = function visitHiddenSuffixType(node) { const type = visit2(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const suffix = node.suffix.map(visit2(this)).filter(removeNullAndAssertIsNodeFilter("constantValueNode")); if (suffix.length === 0) return type; return hiddenSuffixTypeNode(type, suffix); }; } if (keys.includes("constantDiscriminatorNode")) { visitor.visitConstantDiscriminator = function visitConstantDiscriminator(node) { const constant = visit2(this)(node.constant); if (constant === null) return null; assertIsNode(constant, "constantValueNode"); return constantDiscriminatorNode(constant, node.offset); }; } if (keys.includes("accountLinkNode")) { visitor.visitAccountLink = function visitAccountLink(node) { const program = node.program ? visit2(this)(node.program) ?? void 0 : void 0; if (program) assertIsNode(program, "programLinkNode"); return accountLinkNode(node.name, program); }; } if (keys.includes("definedTypeLinkNode")) { visitor.visitDefinedTypeLink = function visitDefinedTypeLink(node) { const program = node.program ? visit2(this)(node.program) ?? void 0 : void 0; if (program) assertIsNode(program, "programLinkNode"); return definedTypeLinkNode(node.name, program); }; } if (keys.includes("instructionLinkNode")) { visitor.visitInstructionLink = function visitInstructionLink(node) { const program = node.program ? visit2(this)(node.program) ?? void 0 : void 0; if (program) assertIsNode(program, "programLinkNode"); return instructionLinkNode(node.name, program); }; } if (keys.includes("instructionAccountLinkNode")) { visitor.visitInstructionAccountLink = function visitInstructionAccountLink(node) { const instruction = node.instruction ? visit2(this)(node.instruction) ?? void 0 : void 0; if (instruction) assertIsNode(instruction, "instructionLinkNode"); return instructionAccountLinkNode(node.name, instruction); }; } if (keys.includes("instructionArgumentLinkNode")) { visitor.visitInstructionArgumentLink = function visitInstructionArgumentLink(node) { const instruction = node.instruction ? visit2(this)(node.instruction) ?? void 0 : void 0; if (instruction) assertIsNode(instruction, "instructionLinkNode"); return instructionArgumentLinkNode(node.name, instruction); }; } if (keys.includes("pdaLinkNode")) { visitor.visitPdaLink = function visitPdaLink(node) { const program = node.program ? visit2(this)(node.program) ?? void 0 : void 0; if (program) assertIsNode(program, "programLinkNode"); return pdaLinkNode(node.name, program); }; } return visitor; } function interceptVisitor(visitor, interceptor) { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap((key) => { const castedKey = key; if (!registeredVisitFunctions.includes(castedKey)) { return []; } return [ [ castedKey, function interceptedVisitNode(node) { const baseFunction = visitor[castedKey]; return interceptor(node, baseFunction.bind(this)); } ] ]; }) ); } var getNodeSelectorFunction = (selector) => { if (typeof selector === "function") return selector; const checkNode = (node, nodeSelector) => { if (nodeSelector === "*") return true; const matches = nodeSelector.match(/^(?:\[([^\]]+)\])?(.*)?$/); if (!matches) return false; const [, kinds, name] = matches; const kindArray = kinds ? kinds.split("|").map(camelCase) : []; if (kindArray.length > 0 && !kindArray.includes(node.kind)) { return false; } if (name && (!("name" in node) || camelCase(name) !== node.name)) { return false; } return true; }; const checkPath = (path, nodeSelectors2) => { if (nodeSelectors2.length === 0) return true; if (path.length === 0) return false; const lastNode = path.pop(); const lastNodeSelector = nodeSelectors2.pop(); return checkNode(lastNode, lastNodeSelector) ? checkPath(path, nodeSelectors2) : checkPath(path, [...nodeSelectors2, lastNodeSelector]); }; const checkInitialPath = (path, nodeSelectors2) => { if (nodeSelectors2.length === 0 || path.length === 0) return false; const lastNode = path.pop(); const lastNodeSelector = nodeSelectors2.pop(); return checkNode(lastNode, lastNodeSelector) && checkPath(path, nodeSelectors2); }; const nodeSelectors = selector.split("."); return (path) => checkInitialPath([...path], [...nodeSelectors]); }; var getConjunctiveNodeSelectorFunction = (selector) => { const selectors = Array.isArray(selector) ? selector : [selector]; const selectorFunctions = selectors.map(getNodeSelectorFunction); return (path) => selectorFunctions.every((fn) => fn(path)); }; function getLastNodeFromPath(path) { return path[path.length - 1]; } function findFirstNodeFromPath(path, kind) { return path.find((node) => isNode(node, kind)); } function findLastNodeFromPath(path, kind) { for (let index = path.length - 1; index >= 0; index--) { const node = path[index]; if (isNode(node, kind)) return node; } return void 0; } function findProgramNodeFromPath(path) { return findLastNodeFromPath(path, "programNode"); } function findInstructionNodeFromPath(path) { return findLastNodeFromPath(path, "instructionNode"); } function getNodePathUntilLastNode(path, kind) { const lastIndex = (() => { for (let index = path.length - 1; index >= 0; index--) { const node = path[index]; if (isNode(node, kind)) return index; } return -1; })(); if (lastIndex === -1) return void 0; return path.slice(0, lastIndex + 1); } function isFilledNodePath(path) { return !!path && path.length > 0; } function isNodePath(path, kind) { return isNode(isFilledNodePath(path) ? getLastNodeFromPath(path) : null, kind); } function assertIsNodePath(path, kind) { assertIsNode(isFilledNodePath(path) ? getLastNodeFromPath(path) : null, kind); } function nodePathToStringArray(path) { return path.map((node) => { return "name" in node ? `[${node.kind}]${node.name}` : `[${node.kind}]`; }); } function nodePathToString(path) { return nodePathToStringArray(path).join(" > "); } // src/NodeStack.ts var NodeStack = class _NodeStack { /** * Contains all the node paths saved during the traversal. * * - The very last path is the current path which is being * used during the traversal. * - The other paths can be used to save and restore the * current path when jumping to different parts of the tree. * * There must at least be one path in the stack at all times. */ stack; constructor(...stack) { this.stack = stack.length === 0 ? [[]] : [...stack.map((nodes) => [...nodes])]; } get currentPath() { return this.stack[this.stack.length - 1]; } push(node) { this.currentPath.push(node); } pop() { return this.currentPath.pop(); } peek() { return this.isEmpty() ? void 0 : this.currentPath[this.currentPath.length - 1]; } pushPath(newPath = []) { this.stack.push([...newPath]); } popPath() { if (this.stack.length <= 1) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, { path: [...this.stack[this.stack.length - 1]] }); } return [...this.stack.pop()]; } getPath(kind) { const path = [...this.currentPath]; if (kind) { assertIsNodePath(path, kind); } return path; } isEmpty() { return this.currentPath.length === 0; } clone() { return new _NodeStack(...this.stack); } toString() { return nodePathToString(this.getPath()); } }; // src/pipe.ts function pipe(init, ...fns) { return fns.reduce((acc, fn) => fn(acc), init); } // src/recordNodeStackVisitor.ts function recordNodeStackVisitor(visitor, stack) { return interceptVisitor(visitor, (node, next) => { stack.push(node); const newNode = next(node); stack.pop(); return newNode; }); } // src/bottomUpTransformerVisitor.ts function bottomUpTransformerVisitor(transformers, options = {}) { const transformerFunctions = transformers.map((transformer) => { if (typeof transformer === "function") return transformer; return (node, stack2) => getConjunctiveNodeSelectorFunction(transformer.select)(stack2.getPath(REGISTERED_NODE_KINDS)) ? transformer.transform(node, stack2) : node; }); const stack = options.stack ?? new NodeStack(); return pipe( identityVisitor(options), (v) => interceptVisitor(v, (node, next) => { return transformerFunctions.reduce( (acc, transformer) => acc === null ? null : transformer(acc, stack), next(node) ); }), (v) => recordNodeStackVisitor(v, stack) ); } function mapVisitor(visitor, map) { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap((key) => { const castedKey = key; if (!registeredVisitFunctions.includes(castedKey)) { return []; } return [ [ castedKey, (node) => map(visitor[castedKey](node)) ] ]; }) ); } // src/consoleLogVisitor.ts function consoleLogVisitor(visitor) { return mapVisitor(visitor, (value) => console.log(value)); } function topDownTransformerVisitor(transformers, options = {}) { const transformerFunctions = transformers.map((transformer) => { if (typeof transformer === "function") return transformer; return (node, stack2) => getConjunctiveNodeSelectorFunction(transformer.select)(stack2.getPath(REGISTERED_NODE_KINDS)) ? transformer.transform(node, stack2) : node; }); const stack = options.stack ?? new NodeStack(); return pipe( identityVisitor(options), (v) => interceptVisitor(v, (node, next) => { const appliedNode = transformerFunctions.reduce( (acc, transformer) => acc === null ? null : transformer(acc, stack), node ); if (appliedNode === null) return null; return next(appliedNode); }), (v) => recordNodeStackVisitor(v, stack) ); } // src/deleteNodesVisitor.ts function deleteNodesVisitor(selectors, options) { return topDownTransformerVisitor( selectors.map( (selector) => ({ select: selector, transform: () => null }) ), options ); } function extendVisitor(visitor, overrides) { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); const overriddenFunctions = Object.fromEntries( Object.keys(overrides).flatMap((key) => { if (!registeredVisitFunctions.includes(key)) { return []; } const castedKey = key; if (!visitor[castedKey]) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, { visitFunction: castedKey }); } return [ [ castedKey, function extendedVisitNode(node) { const extendedFunction = overrides[castedKey]; const nextFunction = visitor[castedKey]; return extendedFunction.bind(this)(node, { next: nextFunction.bind(this), self: this }); } ] ]; }) ); return { ...visitor, ...overriddenFunctions }; } function mergeVisitor(leafValue, merge, options = {}) { const keys = options.keys ?? REGISTERED_NODE_KINDS; const visitor = staticVisitor(leafValue, { keys }); const visit2 = (v) => (node) => keys.includes(node.kind) ? [visit(node, v)] : []; if (keys.includes("rootNode")) { visitor.visitRoot = function visitRoot(node) { return merge(node, getAllPrograms(node).flatMap(visit2(this))); }; } if (keys.includes("programNode")) { visitor.visitProgram = function visitProgram(node) { return merge(node, [ ...node.pdas.flatMap(visit2(this)), ...node.accounts.flatMap(visit2(this)), ...node.instructions.flatMap(visit2(this)), ...node.definedTypes.flatMap(visit2(this)), ...node.errors.flatMap(visit2(this)) ]); }; } if (keys.includes("pdaNode")) { visitor.visitPda = function visitPda(node) { return merge(node, node.seeds.flatMap(visit2(this))); }; } if (keys.includes("accountNode")) { visitor.visitAccount = function visitAccount(node) { return merge(node, [ ...visit2(this)(node.data), ...node.pda ? visit2(this)(node.pda) : [], ...(node.discriminators ?? []).flatMap(visit2(this)) ]); }; } if (keys.includes("instructionNode")) { visitor.visitInstruction = function visitInstruction(node) { return merge(node, [ ...node.status ? visit2(this)(node.status) : [], ...node.accounts.flatMap(visit2(this)), ...node.arguments.flatMap(visit2(this)), ...(node.extraArguments ?? []).flatMap(visit2(this)), ...(node.remainingAccounts ?? []).flatMap(visit2(this)), ...(node.byteDeltas ?? []).flatMap(visit2(this)), ...(node.discriminators ?? []).flatMap(visit2(this)), ...(node.subInstructions ?? []).flatMap(visit2(this)) ]); }; } if (keys.includes("instructionAccountNode")) { visitor.visitInstructionAccount = function visitInstructionAccount(node) { return merge(node, [...node.defaultValue ? visit2(this)(node.defaultValue) : []]); }; } if (keys.includes("instructionArgumentNode")) { visitor.visitInstructionArgument = function visitInstructionArgument(node) { return merge(node, [ ...visit2(this)(node.type), ...node.defaultValue ? visit2(this)(node.defaultValue) : [] ]); }; } if (keys.includes("instructionRemainingAccountsNode")) { visitor.visitInstructionRemainingAccounts = function visitInstructionRemainingAccounts(node) { return merge(node, visit2(this)(node.value)); }; } if (keys.includes("instructionByteDeltaNode")) { visitor.visitInstructionByteDelta = function visitInstructionByteDelta(node) { return merge(node, visit2(this)(node.value)); }; } if (keys.includes("instructionStatusNode")) { visitor.visitInstructionStatus = function visitInstructionStatus(node) { return merge(node, []); }; } if (keys.includes("definedTypeNode")) { visitor.visitDefinedType = function visitDefinedType(node) { return merge(node, visit2(this)(node.type)); }; } if (keys.includes("arrayTypeNode")) { visitor.visitArrayType = function visitArrayType(node) { return merge(node, [...visit2(this)(node.count), ...visit2(this)(node.item)]); }; } if (keys.includes("enumTypeNode")) { visitor.visitEnumType = function visitEnumType(node) { return merge(node, [...visit2(this)(node.size), ...node.variants.flatMap(visit2(this))]); }; } if (keys.includes("enumStructVariantTypeNode")) { visitor.visitEnumStructVariantType = function visitEnumStructVariantType(node) { return merge(node, visit2(this)(node.struct)); }; } if (keys.includes("enumTupleVariantTypeNode")) { visitor.visitEnumTupleVariantType = function visitEnumTupleVariantType(node) { return merge(node, visit2(this)(node.tuple)); }; } if (keys.includes("mapTypeNode")) { visitor.visitMapType = function visitMapType(node) { return merge(node, [...visit2(this)(node.count), ...visit2(this)(node.key), ...visit2(this)(node.value)]); }; } if (keys.includes("optionTypeNode")) { visitor.visitOptionType = function visitOptionType(node) { return merge(node, [...visit2(this)(node.prefix), ...visit2(this)(node.item)]); }; } if (keys.includes("zeroableOptionTypeNode")) { visitor.visitZeroableOptionType = function visitZeroableOptionType(node) { return merge(node, [...visit2(this)(node.item), ...node.zeroValue ? visit2(this)(node.zeroValue) : []]); }; } if (keys.includes("remainderOptionTypeNode")) { visitor.visitRemainderOptionType = function visitRemainderOptionType(node) { return merge(node, visit2(this)(node.item)); }; } if (keys.includes("booleanTypeNode")) { visitor.visitBooleanType = function visitBooleanType(node) { return merge(node, visit2(this)(node.size)); }; } if (keys.includes("setTypeNode")) { visitor.visitSetType = function visitSetType(node) { return merge(node, [...visit2(this)(node.count), ...visit2(this)(node.item)]); }; } if (keys.includes("structTypeNode")) { visitor.visitStructType = function visitStructType(node) { return merge(node, node.fields.flatMap(visit2(this))); }; } if (keys.includes("structFieldTypeNode")) { visitor.visitStructFieldType = function visitStructFieldType(node) { return merge(node, [ ...visit2(this)(node.type), ...node.defaultValue ? visit2(this)(node.defaultValue) : [] ]); }; } if (keys.includes("tupleTypeNode")) { visitor.visitTupleType = function visitTupleType(node) { return merge(node, node.items.flatMap(visit2(this))); }; } if (keys.includes("amountTypeNode")) { visitor.visitAmountType = function visitAmountType(node) { return merge(node, visit2(this)(node.number)); }; } if (keys.includes("dateTimeTypeNode")) { visitor.visitDateTimeType = function visitDateTimeType(node) { return merge(node, visit2(this)(node.number)); }; } if (keys.includes("solAmountTypeNode")) { visitor.visitSolAmountType = function visitSolAmountType(node) { return merge(node, visit2(this)(node.number)); }; } if (keys.includes("prefixedCountNode")) { visitor.visitPrefixedCount = function visitPrefixedCount(node) { return merge(node, visit2(this)(node.prefix)); }; } if (keys.includes("arrayValueNode")) { visitor.visitArrayValue = function visitArrayValue(node) { return merge(node, node.items.flatMap(visit2(this))); }; } if (keys.includes("constantValueNode")) { visitor.visitConstantValue = function visitConstantValue(node) { return merge(node, [...visit2(this)(node.type), ...visit2(this)(node.value)]); }; } if (keys.includes("enumValueNode")) { visitor.visitEnumValue = function visitEnumValue(node) { return merge(node, [...visit2(this)(node.enum), ...node.value ? visit2(this)(node.value) : []]); }; } if (keys.includes("mapValueNode")) { visitor.visitMapValue = function visitMapValue(node) { return merge(node, node.entries.flatMap(visit2(this))); }; } if (keys.includes("mapEntryValueNode")) { visitor.visitMapEntryValue = function visitMapEntryValue(node) { return merge(node, [...visit2(this)(node.key), ...visit2(this)(node.value)]); }; } if (keys.includes("setValueNode")) { visitor.visitSetValue = function visitSetValue(node) { return merge(node, node.items.flatMap(visit2(this))); }; } if (keys.includes("someValueNode")) { visitor.visitSomeValue = function visitSomeValue(node) { return merge(node, visit2(this)(node.value)); }; } if (keys.includes("structValueNode")) { visitor.visitStructValue = function visitStructValue(node) { return merge(node, node.fields.flatMap(visit2(this))); }; } if (keys.includes("structFieldValueNode")) { visitor.visitStructFieldValue = function visitStructFieldValue(node) { return merge(node, visit2(this)(node.value)); }; } if (keys.includes("tupleValueNode")) { visitor.visitTupleValue = function visitTupleValue(node) { return merge(node, node.items.flatMap(visit2(this))); }; } if (keys.includes("constantPdaSeedNode")) { visitor.visitConstantPdaSeed = function visitConstantPdaSeed(node) { return merge(node, [...visit2(this)(node.type), ...visit2(this)(node.value)]); }; } if (keys.includes("variablePdaSeedNode")) { visitor.visitVariablePdaSeed = function visitVariablePdaSeed(node) { return merge(node, visit2(this)(node.type)); }; } if (keys.includes("resolverValueNode")) { visitor.visitResolverValue = function visitResolverValue(node) { return merge(node, (node.dependsOn ?? []).flatMap(visit2(this))); }; } if (keys.includes("conditionalValueNode")) { visitor.visitConditionalValue = function visitConditionalValue(node) { return merge(node, [ ...visit2(this)(node.condition), ...node.value ? visit2(this)(node.value) : [], ...node.ifTrue ? visit2(this)(node.ifTrue) : [], ...node.ifFalse ? visit2(this)(node.ifFalse) : [] ]); }; } if (keys.includes("pdaValueNode")) { visitor.visitPdaValue = function visitPdaValue(node) { return merge(node, [...visit2(this)(node.pda), ...node.seeds.flatMap(visit2(this))]); }; } if (keys.includes("pdaSeedValueNode")) { visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { return merge(node, visit2(this)(node.value)); }; } if (keys.includes("fixedSizeTypeNode")) { visitor.visitFixedSizeType = function visitFixedSizeType(node) { return merge(node, visit2(this)(node.type)); }; } if (keys.includes("sizePrefixTypeNode")) { visitor.visitSizePrefixType = function visitSizePrefixType(node) { return merge(node, [...visit2(this)(node.prefix), ...visit2(this)(node.type)]); }; } if (keys.includes("preOffsetTypeNode")) { visitor.visitPreOffsetType = function visitPreOffsetType(node) { return merge(node, visit2(this)(node.type)); }; } if (keys.includes("postOffsetTypeNode")) { visitor.visitPostOffsetType = function visitPostOffsetType(node) { return merge(node, visit2(this)(node.type)); }; } if (keys.includes("sentinelTypeNode")) { visitor.visitSentinelType = function visitSentinelType(node) { return merge(node, [...visit2(this)(node.sentinel), ...visit2(this)(node.type)]); }; } if (keys.includes("hiddenPrefixTypeNode")) { visitor.visitHiddenPrefixType = function visitHiddenPrefixType(node) { return merge(node, [...node.prefix.flatMap(visit2(this)), ...visit2(this)(node.type)]); }; } if (keys.includes("hiddenSuffixTypeNode")) { visitor.visitHiddenSuffixType = function visitHiddenSuffixType(node) { return merge(node, [...visit2(this)(node.type), ...node.suffix.flatMap(visit2(this))]); }; } if (keys.includes("constantDiscriminatorNode")) { visitor.visitConstantDiscriminator = function visitConstantDiscriminator(node) { return merge(node, visit2(this)(node.constant)); }; } if (keys.includes("accountLinkNode")) { visitor.visitAccountLink = function visitAccountLink(node) { return merge(node, node.program ? visit2(this)(node.program) : []); }; } if (keys.includes("definedTypeLinkNode")) { visitor.visitDefinedTypeLink = function visitDefinedTypeLink(node) { return merge(node, node.program ? visit2(this)(node.program) : []); }; } if (keys.includes("instructionLinkNode")) { visitor.visitInstructionLink = function visitInstructionLink(node) { return merge(node, node.program ? visit2(this)(node.program) : []); }; } if (keys.includes("instructionAccountLinkNode")) { visitor.visitInstructionAccountLink = function visitInstructionAccountLink(node) { return merge(node, node.instruction ? visit2(this)(node.instruction) : []); }; } if (keys.includes("instructionArgumentLinkNode")) { visitor.visitInstructionArgumentLink = function visitInstructionArgumentLink(node) { return merge(node, node.instruction ? visit2(this)(node.instruction) : []); }; } if (keys.includes("pdaLinkNode")) { visitor.visitPdaLink = function visitPdaLink(node) { return merge(node, node.program ? visit2(this)(node.program) : []); }; } return visitor; } // src/getByteSizeVisitor.ts function getByteSizeVisitor(linkables, options = {}) { const stack = options.stack ?? new NodeStack(); const visitedDefinedTypes = /* @__PURE__ */ new Map(); const definedTypeStack = []; const sumSizes = (values) => values.reduce((all, one) => all === null || one === null ? null : all + one, 0); const baseVisitor = mergeVisitor( () => null, (_, values) => sumSizes(values), { keys: [ ...REGISTERED_TYPE_NODE_KINDS, "accountNode", "constantValueNode", "definedTypeLinkNode", "definedTypeNode", "instructionArgumentNode", "instructionNode" ] } ); return pipe( baseVisitor, (v) => extendVisitor(v, { visitAccount(node, { self }) { return visit(node.data, self); }, visitArrayType(node, { self }) { return getArrayLikeSize(node.count, visit(node.item, self), self); }, visitConstantValue(node, { self }) { const typeSize = visit(node.type, self); if (typeSize !== null) return typeSize; if (isNode(node.value, "bytesValueNode") && node.value.encoding === "base16") { return Math.ceil(node.value.data.length / 2); } if (isNode(node.type, "stringTypeNode") && node.type.encoding === "base16" && isNode(node.value, "stringValueNode")) { return Math.ceil(node.value.string.length / 2); } return null; }, visitDefinedType(node, { self }) { if (visitedDefinedTypes.has(node.name)) { return visitedDefinedTypes.get(node.name); } definedTypeStack.push(node.name); const child = visit(node.type, self); definedTypeStack.pop(); visitedDefinedTypes.set(node.name, child); return child; }, visitDefinedTypeLink(node, { self }) { const linkedDefinedPath = linkables.getPath(stack.getPath(node.kind)); if (!linkedDefinedPath) return null; const linkedDefinedType = getLastNodeFromPath(linkedDefinedPath); if (definedTypeStack.includes(linkedDefinedType.name)) return null; stack.pushPath(linkedDefinedPath); const result = visit(linkedDefinedType, self); stack.popPath(); return result; }, visitEnumEmptyVariantType() { return 0; }, visitEnumType(node, { self }) { const prefix = visit(node.size, self); if (prefix === null) return null; if (isScalarEnum(node)) return prefix; const variantSizes = node.variants.map((v2) => visit(v2, self)); const allVariantHaveTheSameFixedSize = variantSizes.every((one, _, all) => one === all[0]); return allVariantHaveTheSameFixedSize && variantSizes.length > 0 && variantSizes[0] !== null ? variantSizes[0] + prefix : null; }, visitFixedSizeType(node) { return node.size; }, visitInstruction(node, { self }) {