UNPKG

@codama/visitors

Version:

All visitors for the Codama framework

1,153 lines (1,148 loc) 47.7 kB
'use strict'; var visitorsCore = require('@codama/visitors-core'); var errors = require('@codama/errors'); var nodes = require('@codama/nodes'); // src/index.ts function addPdasVisitor(pdas) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(pdas).map(([uncasedProgramName, newPdas]) => { const programName = nodes.camelCase(uncasedProgramName); return { select: `[programNode]${programName}`, transform: (node) => { nodes.assertIsNode(node, "programNode"); const existingPdaNames = new Set((node.pdas ?? []).map((pda) => pda.name)); const newPdaNames = new Set(newPdas.map((pda) => pda.name)); const overlappingPdaNames = new Set([...existingPdaNames].filter((name) => newPdaNames.has(name))); if (overlappingPdaNames.size > 0) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, { duplicatedPdaNames: [...overlappingPdaNames], program: node, programName: node.name }); } return nodes.programNode({ ...node, pdas: [ ...node.pdas ?? [], ...newPdas.map(({ name, seeds, docs }) => nodes.pdaNode({ docs, name, seeds })) ] }); } }; }) ); } function flattenInstructionDataArgumentsVisitor() { return visitorsCore.bottomUpTransformerVisitor([ { select: "[instructionNode]", transform: (instruction) => { nodes.assertIsNode(instruction, "instructionNode"); return nodes.instructionNode({ ...instruction, arguments: flattenInstructionArguments(instruction.arguments ?? []) }); } } ]); } var flattenInstructionArguments = (nodes$1, options = "*") => { const camelCaseOptions = options === "*" ? options : options.map(nodes.camelCase); const shouldInline = (node) => options === "*" || camelCaseOptions.includes(nodes.camelCase(node.name)); const inlinedArguments = nodes$1.flatMap((node) => { if (nodes.isNode(node.type, "structTypeNode") && shouldInline(node)) { return (node.type.fields ?? []).map((field) => nodes.instructionArgumentNode({ ...field })); } return node; }); const inlinedFieldsNames = inlinedArguments.map((arg) => arg.name); const duplicates = inlinedFieldsNames.filter((e, i, a) => a.indexOf(e) !== i); const uniqueDuplicates = [...new Set(duplicates)]; const hasConflictingNames = uniqueDuplicates.length > 0; if (hasConflictingNames) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, { conflictingAttributes: uniqueDuplicates }); } return hasConflictingNames ? nodes$1 : inlinedArguments; }; // src/createSubInstructionsFromEnumArgsVisitor.ts function createSubInstructionsFromEnumArgsVisitor(map) { const linkables = new visitorsCore.LinkableDictionary(); const visitor = visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([selector, argNameInput]) => ({ select: ["[instructionNode]", selector], transform: (node, stack) => { nodes.assertIsNode(node, "instructionNode"); const argFields = node.arguments ?? []; const argName = nodes.camelCase(argNameInput); const argFieldIndex = argFields.findIndex((field) => field.name === argName); const argField = argFieldIndex >= 0 ? argFields[argFieldIndex] : null; if (!argField) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, { argumentName: argName, instruction: node, instructionName: node.name }); } let argType; if (nodes.isNode(argField.type, "enumTypeNode")) { argType = argField.type; } else if (nodes.isNode(argField.type, "definedTypeLinkNode") && linkables.has([...stack.getPath(), argField.type])) { const linkedType = linkables.get([...stack.getPath(), argField.type])?.type; nodes.assertIsNode(linkedType, "enumTypeNode"); argType = linkedType; } else { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, { argumentName: argName, instruction: node, instructionName: node.name }); } const subInstructions = (argType.variants ?? []).map((variant, index) => { const subName = nodes.camelCase(`${node.name} ${variant.name}`); const subFields = argFields.slice(0, argFieldIndex); subFields.push( nodes.instructionArgumentNode({ defaultValue: nodes.numberValueNode(index), defaultValueStrategy: "omitted", name: `${subName}Discriminator`, type: nodes.numberTypeNode("u8") }) ); if (nodes.isNode(variant, "enumStructVariantTypeNode")) { subFields.push( nodes.instructionArgumentNode({ ...argField, type: variant.struct }) ); } else if (nodes.isNode(variant, "enumTupleVariantTypeNode")) { subFields.push( nodes.instructionArgumentNode({ ...argField, type: variant.tuple }) ); } subFields.push(...argFields.slice(argFieldIndex + 1)); return nodes.instructionNode({ ...node, arguments: flattenInstructionArguments(subFields), name: subName }); }); return nodes.instructionNode({ ...node, subInstructions: [...node.subInstructions ?? [], ...subInstructions] }); } })) ); return visitorsCore.pipe(visitor, (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables)); } function deduplicateIdenticalDefinedTypesVisitor() { return visitorsCore.rootNodeVisitor((root) => { const typeMap = /* @__PURE__ */ new Map(); const allPrograms = nodes.getAllPrograms(root); allPrograms.forEach((program) => { (program.definedTypes ?? []).forEach((type) => { const typeWithProgram = { program, type }; const list = typeMap.get(type.name) ?? []; typeMap.set(type.name, [...list, typeWithProgram]); }); }); typeMap.forEach((list, name) => { if (list.length <= 1) { typeMap.delete(name); } }); const hashVisitor = visitorsCore.getUniqueHashStringVisitor({ removeDocs: true }); typeMap.forEach((list, name) => { const types = list.map((item) => visitorsCore.visit(item.type, hashVisitor)); const typesAreEqual = types.every((type, _, arr) => type === arr[0]); if (!typesAreEqual) { typeMap.delete(name); } }); const deleteSelectors = Array.from(typeMap.values()).flatMap((list) => { const sortedList = list.sort((a, b) => allPrograms.indexOf(a.program) - allPrograms.indexOf(b.program)); const [, ...sortedListTail] = sortedList; return sortedListTail; }).map(({ program, type }) => `[programNode]${program.name}.[definedTypeNode]${type.name}`); if (deleteSelectors.length > 0) { const newRoot = visitorsCore.visit(root, visitorsCore.deleteNodesVisitor(deleteSelectors)); nodes.assertIsNode(newRoot, "rootNode"); return newRoot; } return root; }); } function fillDefaultPdaSeedValuesVisitor(instructionPath, linkables, strictMode = false) { const instruction = visitorsCore.getLastNodeFromPath(instructionPath); return visitorsCore.pipe( visitorsCore.identityVisitor({ keys: nodes.INSTRUCTION_INPUT_VALUE_NODES }), (v) => visitorsCore.extendVisitor(v, { visitPdaValue(node, { next }) { const visitedNode = next(node); nodes.assertIsNode(visitedNode, "pdaValueNode"); const foundPda = nodes.isNode(visitedNode.pda, "pdaNode") ? visitedNode.pda : linkables.get([...instructionPath, visitedNode.pda]); if (!foundPda) return visitedNode; const seeds = addDefaultSeedValuesFromPdaWhenMissing(instruction, foundPda, visitedNode.seeds ?? []); if (strictMode && !allSeedsAreValid(instruction, foundPda, seeds)) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES, { instruction, instructionName: instruction.name, pda: foundPda, pdaName: foundPda.name }); } return nodes.pdaValueNode(visitedNode.pda, seeds); } }) ); } function addDefaultSeedValuesFromPdaWhenMissing(instruction, pda, existingSeeds) { const existingSeedNames = new Set(existingSeeds.map((seed) => seed.name)); const defaultSeeds = getDefaultSeedValuesFromPda(instruction, pda).filter( (seed) => !existingSeedNames.has(seed.name) ); return [...existingSeeds, ...defaultSeeds]; } function getDefaultSeedValuesFromPda(instruction, pda) { return (pda.seeds ?? []).flatMap((seed) => { if (!nodes.isNode(seed, "variablePdaSeedNode")) return []; const hasMatchingAccount = (instruction.accounts ?? []).some((a) => a.name === seed.name); if (nodes.isNode(seed.type, "publicKeyTypeNode") && hasMatchingAccount) { return [nodes.pdaSeedValueNode(seed.name, nodes.accountValueNode(seed.name))]; } const hasMatchingArgument = nodes.getAllInstructionArguments(instruction).some((a) => a.name === seed.name); if (hasMatchingArgument) { return [nodes.pdaSeedValueNode(seed.name, nodes.argumentValueNode(seed.name))]; } return []; }); } function allSeedsAreValid(instruction, foundPda, seeds) { const hasAllVariableSeeds = (foundPda.seeds ?? []).filter(nodes.isNodeFilter("variablePdaSeedNode")).length === seeds.length; const allAccountsName = (instruction.accounts ?? []).map((a) => a.name); const allArgumentsName = nodes.getAllInstructionArguments(instruction).map((a) => a.name); const validSeeds = seeds.every((seed) => { if (nodes.isNode(seed.value, "accountValueNode")) { return allAccountsName.includes(seed.value.name); } if (nodes.isNode(seed.value, "argumentValueNode")) { return allArgumentsName.includes(seed.value.name); } return true; }); return hasAllVariableSeeds && validSeeds; } function flattenStructVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([stack, options]) => ({ select: `${stack}.[structTypeNode]`, transform: (node) => flattenStruct(node, options) })) ); } var flattenStruct = (node, options = "*") => { nodes.assertIsNode(node, "structTypeNode"); const camelCaseOptions = options === "*" ? options : options.map(nodes.camelCase); const shouldInline = (field) => options === "*" || camelCaseOptions.includes(nodes.camelCase(field.name)); const inlinedFields = (node.fields ?? []).flatMap((field) => { if (nodes.isNode(field.type, "structTypeNode") && shouldInline(field)) { return field.type.fields ?? []; } return [field]; }); const inlinedFieldsNames = inlinedFields.map((arg) => arg.name); const duplicates = inlinedFieldsNames.filter((e, i, a) => a.indexOf(e) !== i); const uniqueDuplicates = [...new Set(duplicates)]; const hasConflictingNames = uniqueDuplicates.length > 0; if (hasConflictingNames) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, { conflictingAttributes: uniqueDuplicates }); } return hasConflictingNames ? node : nodes.structTypeNode(inlinedFields); }; function mergeHistograms(histograms) { const result = {}; histograms.forEach((histogram) => { Object.keys(histogram).forEach((key) => { const mainCaseKey = key; if (result[mainCaseKey] === void 0) { result[mainCaseKey] = histogram[mainCaseKey]; } else { result[mainCaseKey].total += histogram[mainCaseKey].total; result[mainCaseKey].inAccounts += histogram[mainCaseKey].inAccounts; result[mainCaseKey].inDefinedTypes += histogram[mainCaseKey].inDefinedTypes; result[mainCaseKey].inEvents += histogram[mainCaseKey].inEvents; result[mainCaseKey].inInstructionArgs += histogram[mainCaseKey].inInstructionArgs; result[mainCaseKey].directlyAsInstructionArgs += histogram[mainCaseKey].directlyAsInstructionArgs; } }); }); return result; } function getDefinedTypeHistogramVisitor() { const stack = new visitorsCore.NodeStack(); let mode = null; let stackLevel = 0; return visitorsCore.pipe( visitorsCore.mergeVisitor( () => ({}), (_, histograms) => mergeHistograms(histograms) ), (v) => visitorsCore.interceptVisitor(v, (node, next) => { stackLevel += 1; const newNode = next(node); stackLevel -= 1; return newNode; }), (v) => visitorsCore.extendVisitor(v, { visitAccount(node, { self }) { mode = "account"; stackLevel = 0; const histogram = visitorsCore.visit(node.data, self); mode = null; return histogram; }, visitDefinedType(node, { self }) { mode = "definedType"; stackLevel = 0; const histogram = visitorsCore.visit(node.type, self); mode = null; return histogram; }, visitDefinedTypeLink(node) { const program = visitorsCore.findProgramNodeFromPath(stack.getPath()); const key = program ? `${program.name}.${node.name}` : node.name; return { [key]: { directlyAsInstructionArgs: Number(mode === "instruction" && stackLevel <= 1), inAccounts: Number(mode === "account"), inDefinedTypes: Number(mode === "definedType"), inEvents: Number(mode === "event"), inInstructionArgs: Number(mode === "instruction"), total: 1 } }; }, visitEvent(node, { self }) { mode = "event"; stackLevel = 0; const histogram = visitorsCore.visit(node.data, self); mode = null; return histogram; }, visitInstruction(node, { self }) { mode = "instruction"; stackLevel = 0; const dataHistograms = (node.arguments ?? []).map((arg) => visitorsCore.visit(arg, self)); const extraHistograms = (node.extraArguments ?? []).map((arg) => visitorsCore.visit(arg, self)); mode = null; const subHistograms = (node.subInstructions ?? []).map((ix) => visitorsCore.visit(ix, self)); return mergeHistograms([...dataHistograms, ...extraHistograms, ...subHistograms]); } }), (v) => visitorsCore.recordNodeStackVisitor(v, stack) ); } function setAccountDiscriminatorFromFieldVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([selector, { field, value, offset }]) => ({ select: ["[accountNode]", selector], transform: (node) => { nodes.assertIsNode(node, "accountNode"); const accountData = nodes.resolveNestedTypeNode(node.data); const accountFields = accountData.fields ?? []; const fieldIndex = accountFields.findIndex((f) => f.name === field); if (fieldIndex < 0) { throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND, { account: node, missingField: nodes.camelCase(field), name: node.name }); } const fieldNode = accountFields[fieldIndex]; return nodes.accountNode({ ...node, data: nodes.transformNestedTypeNode( node.data, () => nodes.structTypeNode([ ...accountFields.slice(0, fieldIndex), nodes.structFieldTypeNode({ ...fieldNode, defaultValue: value, defaultValueStrategy: "omitted" }), ...accountFields.slice(fieldIndex + 1) ]) ), discriminators: [nodes.fieldDiscriminatorNode(field, offset), ...node.discriminators ?? []] }); } })) ); } function setFixedAccountSizesVisitor() { const linkables = new visitorsCore.LinkableDictionary(); const visitor = visitorsCore.topDownTransformerVisitor( [ { select: (path) => visitorsCore.isNodePath(path, "accountNode") && visitorsCore.getLastNodeFromPath(path).size === void 0, transform: (node, stack) => { nodes.assertIsNode(node, "accountNode"); const size = visitorsCore.visit(node.data, visitorsCore.getByteSizeVisitor(linkables, { stack })); if (size === null) return node; return nodes.accountNode({ ...node, size }); } } ], { keys: ["rootNode", "programNode", "accountNode"] } ); return visitorsCore.pipe(visitor, (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables)); } var getCommonInstructionAccountDefaultRules = () => [ { account: /^(payer|feePayer)$/, defaultValue: nodes.payerValueNode(), ignoreIfOptional: true }, { account: /^(authority)$/, defaultValue: nodes.identityValueNode(), ignoreIfOptional: true }, { account: /^(programId)$/, defaultValue: nodes.programIdValueNode(), ignoreIfOptional: true }, { account: /^(systemProgram|splSystemProgram)$/, defaultValue: nodes.publicKeyValueNode("11111111111111111111111111111111", "splSystem"), ignoreIfOptional: true }, { account: /^(tokenProgram|splTokenProgram)$/, defaultValue: nodes.publicKeyValueNode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "splToken"), ignoreIfOptional: true }, { account: /^(ataProgram|splAtaProgram)$/, defaultValue: nodes.publicKeyValueNode("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "splAssociatedToken"), ignoreIfOptional: true }, { account: /^(tokenMetadataProgram|mplTokenMetadataProgram)$/, defaultValue: nodes.publicKeyValueNode("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", "mplTokenMetadata"), ignoreIfOptional: true }, { account: /^(tokenAuth|mplTokenAuth|authorization|mplAuthorization|auth|mplAuth)RulesProgram$/, defaultValue: nodes.publicKeyValueNode("auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "mplTokenAuthRules"), ignoreIfOptional: true }, { account: /^(candyMachineProgram|mplCandyMachineProgram)$/, defaultValue: nodes.publicKeyValueNode("CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR", "mplCandyMachine"), ignoreIfOptional: true }, { account: /^(candyGuardProgram|mplCandyGuardProgram)$/, defaultValue: nodes.publicKeyValueNode("Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g", "mplCandyGuard"), ignoreIfOptional: true }, { account: /^(clockSysvar|sysvarClock)$/, defaultValue: nodes.publicKeyValueNode("SysvarC1ock11111111111111111111111111111111"), ignoreIfOptional: true }, { account: /^(epochScheduleSysvar|sysvarEpochSchedule)$/, defaultValue: nodes.publicKeyValueNode("SysvarEpochSchedu1e111111111111111111111111"), ignoreIfOptional: true }, { account: /^(instructions?Sysvar|sysvarInstructions?)(Account)?$/, defaultValue: nodes.publicKeyValueNode("Sysvar1nstructions1111111111111111111111111"), ignoreIfOptional: true }, { account: /^(recentBlockhashesSysvar|sysvarRecentBlockhashes)$/, defaultValue: nodes.publicKeyValueNode("SysvarRecentB1ockHashes11111111111111111111"), ignoreIfOptional: true }, { account: /^(rent|rentSysvar|sysvarRent)$/, defaultValue: nodes.publicKeyValueNode("SysvarRent111111111111111111111111111111111"), ignoreIfOptional: true }, { account: /^(rewardsSysvar|sysvarRewards)$/, defaultValue: nodes.publicKeyValueNode("SysvarRewards111111111111111111111111111111"), ignoreIfOptional: true }, { account: /^(slotHashesSysvar|sysvarSlotHashes)$/, defaultValue: nodes.publicKeyValueNode("SysvarS1otHashes111111111111111111111111111"), ignoreIfOptional: true }, { account: /^(slotHistorySysvar|sysvarSlotHistory)$/, defaultValue: nodes.publicKeyValueNode("SysvarS1otHistory11111111111111111111111111"), ignoreIfOptional: true }, { account: /^(stakeHistorySysvar|sysvarStakeHistory)$/, defaultValue: nodes.publicKeyValueNode("SysvarStakeHistory1111111111111111111111111"), ignoreIfOptional: true }, { account: /^(mplCoreProgram)$/, defaultValue: nodes.publicKeyValueNode("CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d", "mplCore"), ignoreIfOptional: true } ]; function setInstructionAccountDefaultValuesVisitor(rules) { const linkables = new visitorsCore.LinkableDictionary(); const stack = new visitorsCore.NodeStack(); const sortedRules = rules.sort((a, b) => { const ia = "instruction" in a; const ib = "instruction" in b; if (ia && ib || !a && !ib) return 0; return ia ? -1 : 1; }); function matchRule(instruction, account) { return sortedRules.find((rule) => { if ("instruction" in rule && rule.instruction && nodes.camelCase(rule.instruction) !== instruction.name) { return false; } return typeof rule.account === "string" ? nodes.camelCase(rule.account) === account.name : rule.account.test(account.name); }); } return visitorsCore.pipe( visitorsCore.nonNullableIdentityVisitor({ keys: ["rootNode", "programNode", "instructionNode"] }), (v) => visitorsCore.extendVisitor(v, { visitInstruction(node) { const instructionPath = stack.getPath("instructionNode"); const instructionAccounts = (node.accounts ?? []).map((account) => { const rule = matchRule(node, account); if (!rule) return account; if ((rule.ignoreIfOptional ?? false) && (account.isOptional || !!account.defaultValue)) { return account; } try { return { ...account, defaultValue: visitorsCore.visit( rule.defaultValue, fillDefaultPdaSeedValuesVisitor(instructionPath, linkables, true) ) }; } catch { return account; } }); return nodes.instructionNode({ ...node, accounts: instructionAccounts }); } }), (v) => visitorsCore.recordNodeStackVisitor(v, stack), (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables) ); } function setInstructionDiscriminatorsVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([selector, discriminator]) => ({ select: ["[instructionNode]", selector], transform: (node) => { nodes.assertIsNode(node, "instructionNode"); const discriminatorArgument = nodes.instructionArgumentNode({ defaultValue: discriminator.value, defaultValueStrategy: discriminator.strategy ?? "omitted", docs: discriminator.docs ?? [], name: discriminator.name ?? "discriminator", type: discriminator.type ?? nodes.numberTypeNode("u8") }); return nodes.instructionNode({ ...node, arguments: [discriminatorArgument, ...node.arguments ?? []], discriminators: [ nodes.fieldDiscriminatorNode(discriminator.name ?? "discriminator"), ...node.discriminators ?? [] ] }); } })) ); } function setNumberWrappersVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([selectorStack, wrapper]) => ({ select: `${selectorStack}.[numberTypeNode]`, transform: (node) => { nodes.assertIsNestedTypeNode(node, "numberTypeNode"); switch (wrapper.kind) { case "DateTime": return nodes.dateTimeTypeNode(node); case "SolAmount": return nodes.solAmountTypeNode(node); case "Amount": return nodes.amountTypeNode(node, wrapper.decimals, wrapper.unit); default: throw new errors.CodamaError(errors.CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER, { wrapper }); } } })) ); } function setStructDefaultValuesVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).flatMap(([stack, defaultValues]) => { const camelCasedDefaultValues = Object.fromEntries( Object.entries(defaultValues).map(([key, value]) => [nodes.camelCase(key), value]) ); return [ { select: `${stack}.[structTypeNode]`, transform: (node) => { nodes.assertIsNode(node, "structTypeNode"); const fields = (node.fields ?? []).map((field) => { const defaultValue = camelCasedDefaultValues[field.name]; if (defaultValue === void 0) return field; if (defaultValue === null) { return nodes.structFieldTypeNode({ ...field, defaultValue: void 0, defaultValueStrategy: void 0 }); } return nodes.structFieldTypeNode({ ...field, defaultValue: "kind" in defaultValue ? defaultValue : defaultValue.value, defaultValueStrategy: "kind" in defaultValue ? void 0 : defaultValue.strategy }); }); return nodes.structTypeNode(fields); } }, { select: ["[instructionNode]", stack], transform: (node) => { nodes.assertIsNode(node, "instructionNode"); const transformArguments = (arg) => { const defaultValue = camelCasedDefaultValues[arg.name]; if (defaultValue === void 0) return arg; if (defaultValue === null) { return nodes.instructionArgumentNode({ ...arg, defaultValue: void 0, defaultValueStrategy: void 0 }); } return nodes.instructionArgumentNode({ ...arg, defaultValue: "kind" in defaultValue ? defaultValue : defaultValue.value, defaultValueStrategy: "kind" in defaultValue ? void 0 : defaultValue.strategy }); }; return nodes.instructionNode({ ...node, arguments: (node.arguments ?? []).map(transformArguments), extraArguments: node.extraArguments ? node.extraArguments.map(transformArguments) : void 0 }); } } ]; }) ); } function transformDefinedTypesIntoAccountsVisitor(definedTypes) { return visitorsCore.pipe( visitorsCore.nonNullableIdentityVisitor({ keys: ["rootNode", "programNode"] }), (v) => visitorsCore.extendVisitor(v, { visitProgram(program) { const typesToExtract = (program.definedTypes ?? []).filter((node) => definedTypes.includes(node.name)); const newDefinedTypes = (program.definedTypes ?? []).filter((node) => !definedTypes.includes(node.name)); const newAccounts = typesToExtract.map((node) => { nodes.assertIsNode(node.type, "structTypeNode"); return nodes.accountNode({ ...node, data: node.type, discriminators: [], size: void 0 }); }); return nodes.programNode({ ...program, accounts: [...program.accounts ?? [], ...newAccounts], definedTypes: newDefinedTypes }); } }) ); } function transformU8ArraysToBytesVisitor(sizes = "*") { const hasRequiredSize = (count) => { if (!nodes.isNode(count, "fixedCountNode")) return false; return sizes === "*" || sizes.includes(count.value); }; return visitorsCore.pipe( visitorsCore.nonNullableIdentityVisitor(), (v) => visitorsCore.extendVisitor(v, { visitArrayType(node, { self }) { const child = visitorsCore.visit(node.item, self); nodes.assertIsNode(child, nodes.TYPE_NODES); if (nodes.isNode(child, "numberTypeNode") && child.format === "u8" && nodes.isNode(node.count, "fixedCountNode") && hasRequiredSize(node.count)) { return nodes.fixedSizeTypeNode(nodes.bytesTypeNode(), node.count.value); } return nodes.arrayTypeNode(child, node.count); } }) ); } function unwrapDefinedTypesVisitor(typesToInline = "*") { const linkables = new visitorsCore.LinkableDictionary(); const stack = new visitorsCore.NodeStack(); const typesToInlineCamelCased = (typesToInline === "*" ? [] : typesToInline).map((fullPath) => { if (!fullPath.includes(".")) return nodes.camelCase(fullPath); const [programName, typeName] = fullPath.split("."); return `${nodes.camelCase(programName)}.${nodes.camelCase(typeName)}`; }); const shouldInline = (typeName, programName) => { if (typesToInline === "*") return true; const fullPath = `${programName}.${typeName}`; if (!!programName && typesToInlineCamelCased.includes(fullPath)) return true; return typesToInlineCamelCased.includes(typeName); }; return visitorsCore.pipe( visitorsCore.nonNullableIdentityVisitor(), (v) => visitorsCore.extendVisitor(v, { visitDefinedTypeLink(linkType, { self }) { const programName = linkType.program?.name ?? visitorsCore.findProgramNodeFromPath(stack.getPath())?.name; if (!shouldInline(linkType.name, programName)) { return linkType; } const definedTypePath = linkables.getPathOrThrow(stack.getPath("definedTypeLinkNode")); const definedType = visitorsCore.getLastNodeFromPath(definedTypePath); stack.pushPath(definedTypePath); const result = visitorsCore.visit(definedType.type, self); stack.popPath(); return result; }, visitProgram(program, { self }) { return nodes.programNode({ ...program, accounts: (program.accounts ?? []).map((account) => visitorsCore.visit(account, self)).filter(nodes.assertIsNodeFilter("accountNode")), definedTypes: (program.definedTypes ?? []).filter((definedType) => !shouldInline(definedType.name, program.name)).map((type) => visitorsCore.visit(type, self)).filter(nodes.assertIsNodeFilter("definedTypeNode")), instructions: (program.instructions ?? []).map((instruction) => visitorsCore.visit(instruction, self)).filter(nodes.assertIsNodeFilter("instructionNode")) }); } }), (v) => visitorsCore.recordNodeStackVisitor(v, stack), (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables) ); } function unwrapInstructionArgsDefinedTypesVisitor() { return visitorsCore.rootNodeVisitor((root) => { const histogram = visitorsCore.visit(root, getDefinedTypeHistogramVisitor()); const linkables = new visitorsCore.LinkableDictionary(); visitorsCore.visit(root, visitorsCore.getRecordLinkablesVisitor(linkables)); const definedTypesToInline = Object.keys(histogram).filter((key) => (histogram[key].total ?? 0) === 1 && (histogram[key].directlyAsInstructionArgs ?? 0) === 1).filter((key) => { const names = key.split("."); const link = names.length == 2 ? nodes.definedTypeLinkNode(names[1], names[0]) : nodes.definedTypeLinkNode(key); const found = linkables.get([link]); return found && !nodes.isNode(found.type, "enumTypeNode"); }); if (definedTypesToInline.length > 0) { const inlineVisitor = unwrapDefinedTypesVisitor(definedTypesToInline); const newRoot = visitorsCore.visit(root, inlineVisitor); nodes.assertIsNode(newRoot, "rootNode"); return newRoot; } return root; }); } function unwrapTupleEnumWithSingleStructVisitor(enumsOrVariantsToUnwrap = "*") { const selectorFunctions = enumsOrVariantsToUnwrap === "*" ? [() => true] : enumsOrVariantsToUnwrap.map((selector) => visitorsCore.getNodeSelectorFunction(selector)); const shouldUnwrap = (stack) => selectorFunctions.some((selector) => selector(stack.getPath(nodes.REGISTERED_NODE_KINDS))); return visitorsCore.rootNodeVisitor((root) => { const typesToPotentiallyUnwrap = []; const definedTypes = new Map( nodes.getAllDefinedTypes(root).map((definedType) => [definedType.name, definedType]) ); let newRoot = visitorsCore.visit( root, visitorsCore.bottomUpTransformerVisitor([ { select: "[enumTupleVariantTypeNode]", transform: (node, stack) => { nodes.assertIsNode(node, "enumTupleVariantTypeNode"); if (!shouldUnwrap(stack)) return node; const tupleNode = nodes.resolveNestedTypeNode(node.tuple); const tupleItems = tupleNode.items ?? []; if (tupleItems.length !== 1) return node; let item = tupleItems[0]; if (nodes.isNode(item, "definedTypeLinkNode")) { const definedType = definedTypes.get(item.name); if (!definedType) return node; if (!nodes.isNode(definedType.type, "structTypeNode")) return node; typesToPotentiallyUnwrap.push(item.name); item = definedType.type; } if (!nodes.isNode(item, "structTypeNode")) return node; const nestedStruct = nodes.transformNestedTypeNode(node.tuple, () => item); return nodes.enumStructVariantTypeNode(node.name, nestedStruct); } } ]) ); nodes.assertIsNode(newRoot, "rootNode"); const histogram = visitorsCore.visit(newRoot, getDefinedTypeHistogramVisitor()); const typesToUnwrap = typesToPotentiallyUnwrap.filter( (type) => !histogram[type] || histogram[type].total === 0 ); newRoot = visitorsCore.visit(newRoot, unwrapDefinedTypesVisitor(typesToUnwrap)); nodes.assertIsNode(newRoot, "rootNode"); return newRoot; }); } function unwrapTypeDefinedLinksVisitor(definedLinksType) { const linkables = new visitorsCore.LinkableDictionary(); const transformers = definedLinksType.map((selector) => ({ select: ["[definedTypeLinkNode]", selector], transform: (_, stack) => { const definedType = linkables.getOrThrow(stack.getPath("definedTypeLinkNode")); return definedType.type; } })); return visitorsCore.pipe(visitorsCore.bottomUpTransformerVisitor(transformers), (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables)); } function renameStructNode(node, map) { return nodes.structTypeNode( (node.fields ?? []).map( (field) => map[field.name] ? nodes.structFieldTypeNode({ ...field, name: map[field.name] }) : field ) ); } function renameEnumNode(node, map) { return nodes.enumTypeNode( (node.variants ?? []).map( (variant) => map[variant.name] ? renameEnumVariant(variant, map[variant.name]) : variant ), { ...node } ); } function renameEnumVariant(variant, newName) { if (nodes.isNode(variant, "enumStructVariantTypeNode")) { return nodes.enumStructVariantTypeNode(newName, variant.struct); } if (nodes.isNode(variant, "enumTupleVariantTypeNode")) { return nodes.enumTupleVariantTypeNode(newName, variant.tuple); } return nodes.enumEmptyVariantTypeNode(newName); } // src/updateAccountsVisitor.ts function updateAccountsVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).flatMap(([selector, updates]) => { const newName = typeof updates === "object" && "name" in updates && updates.name ? nodes.camelCase(updates.name) : void 0; const pdasToUpsert = []; const transformers = [ { select: ["[accountNode]", selector], transform: (node, stack) => { nodes.assertIsNode(node, "accountNode"); if ("delete" in updates) return null; const programNode6 = visitorsCore.findProgramNodeFromPath(stack.getPath()); const { seeds, pda, ...assignableUpdates } = updates; let newPda = node.pda; if (pda && seeds !== void 0) { newPda = pda; pdasToUpsert.push({ pda: nodes.pdaNode({ name: pda.name, seeds }), program: programNode6.name }); } else if (pda) { newPda = pda; } else if (seeds !== void 0 && node.pda) { pdasToUpsert.push({ pda: nodes.pdaNode({ name: node.pda.name, seeds }), program: programNode6.name }); } else if (seeds !== void 0) { newPda = nodes.pdaLinkNode(newName ?? node.name); pdasToUpsert.push({ pda: nodes.pdaNode({ name: newName ?? node.name, seeds }), program: programNode6.name }); } return nodes.accountNode({ ...node, ...assignableUpdates, data: nodes.transformNestedTypeNode( node.data, (struct) => renameStructNode(struct, updates.data ?? {}) ), pda: newPda }); } }, { select: `[programNode]`, transform: (node) => { nodes.assertIsNode(node, "programNode"); const pdasToUpsertForProgram = pdasToUpsert.filter((p) => p.program === node.name).map((p) => p.pda); if (pdasToUpsertForProgram.length === 0) return node; const existingPdaNames = new Set((node.pdas ?? []).map((pda) => pda.name)); const pdasToCreate = pdasToUpsertForProgram.filter((p) => !existingPdaNames.has(p.name)); const pdasToUpdate = new Map( pdasToUpsertForProgram.filter((p) => existingPdaNames.has(p.name)).map((p) => [p.name, p]) ); const newPdas = [...(node.pdas ?? []).map((p) => pdasToUpdate.get(p.name) ?? p), ...pdasToCreate]; return nodes.programNode({ ...node, pdas: newPdas }); } } ]; if (newName) { transformers.push( { select: ["[accountLinkNode]", selector], transform: (node) => { nodes.assertIsNode(node, "accountLinkNode"); return nodes.accountLinkNode(newName); } }, { select: ["[pdaNode]", selector], transform: (node) => { nodes.assertIsNode(node, "pdaNode"); return nodes.pdaNode({ name: newName, seeds: node.seeds }); } }, { select: ["[pdaLinkNode]", selector], transform: (node) => { nodes.assertIsNode(node, "pdaLinkNode"); return nodes.pdaLinkNode(newName); } } ); } return transformers; }) ); } function updateDefinedTypesVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).flatMap(([selector, updates]) => { const newName = typeof updates === "object" && "name" in updates && updates.name ? nodes.camelCase(updates.name) : void 0; const transformers = [ { select: ["[definedTypeNode]", selector], transform: (node) => { nodes.assertIsNode(node, "definedTypeNode"); if ("delete" in updates) { return null; } const { data: dataUpdates, ...otherUpdates } = updates; let newType = node.type; if (nodes.isNode(node.type, "structTypeNode")) { newType = renameStructNode(node.type, dataUpdates ?? {}); } else if (nodes.isNode(node.type, "enumTypeNode")) { newType = renameEnumNode(node.type, dataUpdates ?? {}); } return nodes.definedTypeNode({ ...node, ...otherUpdates, name: newName ?? node.name, type: newType }); } } ]; if (newName) { transformers.push({ select: ["[definedTypeLinkNode]", selector], transform: (node) => { nodes.assertIsNode(node, "definedTypeLinkNode"); return nodes.definedTypeLinkNode(newName); } }); } return transformers; }) ); } function updateErrorsVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).map(([name, updates]) => ({ select: `[errorNode]${name}`, transform: (node) => { nodes.assertIsNode(node, "errorNode"); if ("delete" in updates) return null; return nodes.errorNode({ ...node, ...updates }); } })) ); } function updateInstructionsVisitor(map) { const linkables = new visitorsCore.LinkableDictionary(); const stack = new visitorsCore.NodeStack(); const transformers = Object.entries(map).map(([selector, updates]) => ({ select: ["[instructionNode]", selector], transform: (node) => { nodes.assertIsNode(node, "instructionNode"); if ("delete" in updates) { return null; } const instructionPath = stack.getPath("instructionNode"); const { accounts: accountUpdates, arguments: argumentUpdates, ...metadataUpdates } = updates; const { newArguments, newExtraArguments } = handleInstructionArguments(node, argumentUpdates ?? {}); const newAccounts = (node.accounts ?? []).map( (account) => handleInstructionAccount(instructionPath, account, accountUpdates ?? {}, linkables) ); return nodes.instructionNode({ ...node, ...metadataUpdates, accounts: newAccounts, arguments: newArguments, extraArguments: newExtraArguments.length > 0 ? newExtraArguments : void 0 }); } })); return visitorsCore.pipe( visitorsCore.bottomUpTransformerVisitor(transformers), (v) => visitorsCore.recordNodeStackVisitor(v, stack), (v) => visitorsCore.recordLinkablesOnFirstVisitVisitor(v, linkables) ); } function handleInstructionAccount(instructionPath, account, accountUpdates, linkables) { const accountUpdate = accountUpdates?.[account.name]; if (!accountUpdate) return account; const { defaultValue, ...acountWithoutDefault } = { ...account, ...accountUpdate }; if (!defaultValue) { return nodes.instructionAccountNode(acountWithoutDefault); } return nodes.instructionAccountNode({ ...acountWithoutDefault, defaultValue: visitorsCore.visit(defaultValue, fillDefaultPdaSeedValuesVisitor(instructionPath, linkables)) }); } function handleInstructionArguments(instruction, argUpdates) { const usedArguments = /* @__PURE__ */ new Set(); const newArguments = (instruction.arguments ?? []).map((node) => { const argUpdate = argUpdates[node.name]; if (!argUpdate) return node; usedArguments.add(node.name); return nodes.instructionArgumentNode({ ...node, defaultValue: argUpdate.defaultValue ?? node.defaultValue, defaultValueStrategy: argUpdate.defaultValueStrategy ?? node.defaultValueStrategy, docs: argUpdate.docs ?? node.docs, name: argUpdate.name ?? node.name, type: argUpdate.type ?? node.type }); }); const updatedExtraArguments = (instruction.extraArguments ?? []).map((node) => { if (usedArguments.has(node.name)) return node; const argUpdate = argUpdates[node.name]; if (!argUpdate) return node; usedArguments.add(node.name); return nodes.instructionArgumentNode({ ...node, defaultValue: argUpdate.defaultValue ?? node.defaultValue, defaultValueStrategy: argUpdate.defaultValueStrategy ?? node.defaultValueStrategy, docs: argUpdate.docs ?? node.docs, name: argUpdate.name ?? node.name, type: argUpdate.type ?? node.type }); }); const newExtraArguments = [ ...updatedExtraArguments, ...Object.entries(argUpdates).filter(([argName]) => !usedArguments.has(argName)).map(([argName, argUpdate]) => { const { type } = argUpdate; nodes.assertIsNode(type, nodes.TYPE_NODES); return nodes.instructionArgumentNode({ defaultValue: argUpdate.defaultValue ?? void 0, defaultValueStrategy: argUpdate.defaultValueStrategy ?? void 0, docs: argUpdate.docs ?? [], name: argUpdate.name ?? argName, type }); }) ]; return { newArguments, newExtraArguments }; } function updateProgramsVisitor(map) { return visitorsCore.bottomUpTransformerVisitor( Object.entries(map).flatMap(([name, updates]) => { const newName = typeof updates === "object" && "name" in updates && updates.name ? nodes.camelCase(updates.name) : void 0; const transformers = [ { select: `[programNode]${name}`, transform: (node) => { nodes.assertIsNode(node, "programNode"); if ("delete" in updates) return null; return nodes.programNode({ ...node, ...updates }); } } ]; if (newName) { transformers.push({ select: `[programLinkNode]${name}`, transform: (node) => { nodes.assertIsNode(node, "programLinkNode"); return nodes.programLinkNode(newName); } }); } return transformers; }) ); } exports.addPdasVisitor = addPdasVisitor; exports.createSubInstructionsFromEnumArgsVisitor = createSubInstructionsFromEnumArgsVisitor; exports.deduplicateIdenticalDefinedTypesVisitor = deduplicateIdenticalDefinedTypesVisitor; exports.fillDefaultPdaSeedValuesVisitor = fillDefaultPdaSeedValuesVisitor; exports.flattenInstructionArguments = flattenInstructionArguments; exports.flattenInstructionDataArgumentsVisitor = flattenInstructionDataArgumentsVisitor; exports.flattenStruct = flattenStruct; exports.flattenStructVisitor = flattenStructVisitor; exports.getCommonInstructionAccountDefaultRules = getCommonInstructionAccountDefaultRules; exports.getDefinedTypeHistogramVisitor = getDefinedTypeHistogramVisitor; exports.setAccountDiscriminatorFromFieldVisitor = setAccountDiscriminatorFromFieldVisitor; exports.setFixedAccountSizesVisitor = setFixedAccountSizesVisitor; exports.setInstructionAccountDefaultValuesVisitor = setInstructionAccountDefaultValuesVisitor; exports.setInstructionDiscriminatorsVisitor = setInstructionDiscriminatorsVisitor; exports.setNumberWrappersVisitor = setNumberWrappersVisitor; exports.setStructDefaultValuesVisitor = setStructDefaultValuesVisitor; exports.transformDefinedTypesIntoAccountsVisitor = transformDefinedTypesIntoAccountsVisitor; exports.transformU8ArraysToBytesVisitor = transformU8ArraysToBytesVisitor; exports.unwrapDefinedTypesVisitor = unwrapDefinedTypesVisitor; exports.unwrapInstructionArgsDefinedTypesVisitor = unwrapInstructionArgsDefinedTypesVisitor; exports.unwrapTupleEnumWithSingleStructVisitor = unwrapTupleEnumWithSingleStructVisitor; exports.unwrapTypeDefinedLinksVisitor = unwrapTypeDefinedLinksVisitor; exports.updateAccountsVisitor = updateAccountsVisitor; exports.updateDefinedTypesVisitor = updateDefinedTypesVisitor; exports.updateErrorsVisitor = updateErrorsVisitor; exports.updateInstructionsVisitor = updateInstructionsVisitor; exports.updateProgramsVisitor = updateProgramsVisitor; Object.keys(visitorsCore).forEach(function (k) { if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return visitorsCore[k]; } }); }); //# sourceMappingURL=index.browser.cjs.map //# sourceMappingURL=index.browser.cjs.map