diff --git a/.changeset/late-games-grab.md b/.changeset/late-games-grab.md new file mode 100644 index 000000000..40d3936ae --- /dev/null +++ b/.changeset/late-games-grab.md @@ -0,0 +1,5 @@ +--- +'@metaplex-foundation/kinobi': minor +--- + +Refactor nodes for consistency diff --git a/src/nodes/AccountDataNode.ts b/src/nodes/AccountDataNode.ts index 5275b6937..49d7f2373 100644 --- a/src/nodes/AccountDataNode.ts +++ b/src/nodes/AccountDataNode.ts @@ -4,9 +4,13 @@ import { StructTypeNode } from './typeNodes'; export type AccountDataNode = { readonly kind: 'accountDataNode'; - readonly name: MainCaseString; + + // Children. readonly struct: StructTypeNode; readonly link?: DefinedTypeLinkNode; + + // Data. + readonly name: MainCaseString; }; export type AccountDataNodeInput = { diff --git a/src/nodes/DefinedTypeNode.ts b/src/nodes/DefinedTypeNode.ts index 59f804dc6..070ccf8eb 100644 --- a/src/nodes/DefinedTypeNode.ts +++ b/src/nodes/DefinedTypeNode.ts @@ -6,7 +6,7 @@ export type DefinedTypeNode = { readonly kind: 'definedTypeNode'; // Children. - readonly data: TypeNode; + readonly type: TypeNode; // Data. readonly name: MainCaseString; @@ -17,7 +17,7 @@ export type DefinedTypeNode = { export type DefinedTypeNodeInput = { readonly name: string; - readonly data: TypeNode; + readonly type: TypeNode; readonly idlName?: string; readonly docs?: string[]; readonly internal?: boolean; @@ -30,7 +30,7 @@ export function definedTypeNode(input: DefinedTypeNodeInput): DefinedTypeNode { return { kind: 'definedTypeNode', name: mainCase(input.name), - data: input.data, + type: input.type, idlName: input.idlName ?? input.name, docs: input.docs ?? [], internal: input.internal ?? false, @@ -42,6 +42,6 @@ export function definedTypeNodeFromIdl( ): DefinedTypeNode { const name = idl.name ?? ''; const idlType = idl.type ?? { kind: 'struct', fields: [] }; - const data = createTypeNodeFromIdl(idlType); - return definedTypeNode({ name, data, idlName: name, docs: idl.docs }); + const type = createTypeNodeFromIdl(idlType); + return definedTypeNode({ name, type, idlName: name, docs: idl.docs }); } diff --git a/src/nodes/ErrorNode.ts b/src/nodes/ErrorNode.ts index 56da93480..b80e651d5 100644 --- a/src/nodes/ErrorNode.ts +++ b/src/nodes/ErrorNode.ts @@ -8,6 +8,8 @@ import { export type ErrorNode = { readonly kind: 'errorNode'; + + // Data. readonly name: MainCaseString; readonly idlName: string; readonly code: number; diff --git a/src/nodes/InstructionAccountNode.ts b/src/nodes/InstructionAccountNode.ts index 742dba398..5d3a3375c 100644 --- a/src/nodes/InstructionAccountNode.ts +++ b/src/nodes/InstructionAccountNode.ts @@ -6,7 +6,7 @@ export type InstructionAccountNode = { readonly kind: 'instructionAccountNode'; // Children. - readonly defaultsTo?: InstructionInputValueNode; + readonly defaultValue?: InstructionInputValueNode; // Data. readonly name: MainCaseString; @@ -33,7 +33,7 @@ export function instructionAccountNode( isSigner: input.isSigner, isOptional: input.isOptional ?? false, docs: input.docs ?? [], - defaultsTo: input.defaultsTo, + defaultValue: input.defaultValue, }; } diff --git a/src/nodes/InstructionDataArgsNode.ts b/src/nodes/InstructionDataArgsNode.ts index 165a642ac..b63561a40 100644 --- a/src/nodes/InstructionDataArgsNode.ts +++ b/src/nodes/InstructionDataArgsNode.ts @@ -4,9 +4,13 @@ import { StructTypeNode } from './typeNodes'; export type InstructionDataArgsNode = { readonly kind: 'instructionDataArgsNode'; - readonly name: MainCaseString; + + // Children. readonly struct: StructTypeNode; readonly link?: DefinedTypeLinkNode; + + // Data. + readonly name: MainCaseString; }; export type InstructionDataArgsNodeInput = Omit< diff --git a/src/nodes/InstructionExtraArgsNode.ts b/src/nodes/InstructionExtraArgsNode.ts index 5194236af..1b1a70555 100644 --- a/src/nodes/InstructionExtraArgsNode.ts +++ b/src/nodes/InstructionExtraArgsNode.ts @@ -4,9 +4,13 @@ import { StructTypeNode } from './typeNodes'; export type InstructionExtraArgsNode = { readonly kind: 'instructionExtraArgsNode'; - readonly name: MainCaseString; + + // Children. readonly struct: StructTypeNode; readonly link?: DefinedTypeLinkNode; + + // Data. + readonly name: MainCaseString; }; export type InstructionExtraArgsNodeInput = Omit< diff --git a/src/nodes/InstructionNode.ts b/src/nodes/InstructionNode.ts index 9a551b066..eb9e343c4 100644 --- a/src/nodes/InstructionNode.ts +++ b/src/nodes/InstructionNode.ts @@ -105,11 +105,9 @@ export function instructionNodeFromIdl( if (idl.discriminant) { const discriminatorField = structFieldTypeNode({ name: 'discriminator', - child: createTypeNodeFromIdl(idl.discriminant.type), - defaultsTo: { - strategy: 'omitted', - value: numberValueNode(idl.discriminant.value), - }, + type: createTypeNodeFromIdl(idl.discriminant.type), + defaultValue: numberValueNode(idl.discriminant.value), + defaultValueStrategy: 'omitted', }); dataArgs = structTypeNode([discriminatorField, ...dataArgs.fields]); } diff --git a/src/nodes/Node.ts b/src/nodes/Node.ts index a4b316924..bd4a6449c 100644 --- a/src/nodes/Node.ts +++ b/src/nodes/Node.ts @@ -1,3 +1,4 @@ +import { getNodeKinds } from '../shared/utils'; import type { AccountDataNode } from './AccountDataNode'; import type { AccountNode } from './AccountNode'; import type { DefinedTypeNode } from './DefinedTypeNode'; @@ -40,58 +41,53 @@ const REGISTERED_NODES = { ...REGISTERED_VALUE_NODES, }; -export const REGISTERED_NODES_KEYS = Object.keys( - REGISTERED_NODES -) as (keyof RegisteredNodes)[]; - -export type RegisteredNodes = typeof REGISTERED_NODES; +export const REGISTERED_NODE_KINDS = getNodeKinds(REGISTERED_NODES); +export type NodeDictionary = typeof REGISTERED_NODES; +export type NodeKind = keyof NodeDictionary; +export type Node = NodeDictionary[NodeKind]; // Node Helpers. -export type Node = RegisteredNodes[keyof RegisteredNodes]; - -export function isNode( +export function isNode( node: Node | null | undefined, - key: TKeys | TKeys[] -): node is RegisteredNodes[TKeys] { - const keys = Array.isArray(key) ? key : [key]; - return !!node && (keys as (keyof RegisteredNodes)[]).includes(node.kind); + kind: TKind | TKind[] +): node is NodeDictionary[TKind] { + const kinds = Array.isArray(kind) ? kind : [kind]; + return !!node && (kinds as NodeKind[]).includes(node.kind); } -export function assertIsNode( +export function assertIsNode( node: Node | null | undefined, - key: TKeys | TKeys[] -): asserts node is RegisteredNodes[TKeys] { - const keys = Array.isArray(key) ? key : [key]; - if (!isNode(node, keys)) { + kind: TKind | TKind[] +): asserts node is NodeDictionary[TKind] { + const kinds = Array.isArray(kind) ? kind : [kind]; + if (!isNode(node, kinds)) { throw new Error( - `Expected ${keys.join(' | ')}, got ${node?.kind ?? 'null'}.` + `Expected ${kinds.join(' | ')}, got ${node?.kind ?? 'null'}.` ); } } -export function isNodeFilter( - key: TKeys | TKeys[] -): (node: Node | null | undefined) => node is RegisteredNodes[TKeys] { - return (node): node is RegisteredNodes[TKeys] => isNode(node, key); +export function isNodeFilter( + kind: TKind | TKind[] +): (node: Node | null | undefined) => node is NodeDictionary[TKind] { + return (node): node is NodeDictionary[TKind] => isNode(node, kind); } -export function assertIsNodeFilter( - key: TKeys | TKeys[] -): (node: Node | null | undefined) => node is RegisteredNodes[TKeys] { - return (node): node is RegisteredNodes[TKeys] => { - assertIsNode(node, key); +export function assertIsNodeFilter( + kind: TKind | TKind[] +): (node: Node | null | undefined) => node is NodeDictionary[TKind] { + return (node): node is NodeDictionary[TKind] => { + assertIsNode(node, kind); return true; }; } -export function removeNullAndAssertIsNodeFilter< - TKeys extends keyof RegisteredNodes ->( - key: TKeys | TKeys[] -): (node: Node | null | undefined) => node is RegisteredNodes[TKeys] { - return (node): node is RegisteredNodes[TKeys] => { - if (node) assertIsNode(node, key); +export function removeNullAndAssertIsNodeFilter( + kind: TKind | TKind[] +): (node: Node | null | undefined) => node is NodeDictionary[TKind] { + return (node): node is NodeDictionary[TKind] => { + if (node) assertIsNode(node, kind); return node != null; }; } diff --git a/src/nodes/PdaNode.ts b/src/nodes/PdaNode.ts index 316c5804f..4be04f441 100644 --- a/src/nodes/PdaNode.ts +++ b/src/nodes/PdaNode.ts @@ -20,8 +20,12 @@ import { export type PdaNode = { readonly kind: 'pdaNode'; - readonly name: MainCaseString; + + // Children. readonly seeds: PdaSeedNode[]; + + // Data. + readonly name: MainCaseString; }; export function pdaNode(name: string, seeds: PdaSeedNode[]): PdaNode { diff --git a/src/nodes/RootNode.ts b/src/nodes/RootNode.ts index 4d76f71a6..808dcaf85 100644 --- a/src/nodes/RootNode.ts +++ b/src/nodes/RootNode.ts @@ -11,6 +11,8 @@ export type IdlInputs = string | Partial | (string | Partial)[]; export type RootNode = { readonly kind: 'rootNode'; + + // Children. readonly programs: ProgramNode[]; }; diff --git a/src/nodes/contextualValueNodes/AccountBumpValueNode.ts b/src/nodes/contextualValueNodes/AccountBumpValueNode.ts index 485526ca9..95e06cc4a 100644 --- a/src/nodes/contextualValueNodes/AccountBumpValueNode.ts +++ b/src/nodes/contextualValueNodes/AccountBumpValueNode.ts @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared'; export type AccountBumpValueNode = { readonly kind: 'accountBumpValueNode'; + + // Data. readonly name: MainCaseString; }; diff --git a/src/nodes/contextualValueNodes/AccountValueNode.ts b/src/nodes/contextualValueNodes/AccountValueNode.ts index 7518caaf5..9e687a1e6 100644 --- a/src/nodes/contextualValueNodes/AccountValueNode.ts +++ b/src/nodes/contextualValueNodes/AccountValueNode.ts @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared'; export type AccountValueNode = { readonly kind: 'accountValueNode'; + + // Data. readonly name: MainCaseString; }; diff --git a/src/nodes/contextualValueNodes/ArgumentValueNode.ts b/src/nodes/contextualValueNodes/ArgumentValueNode.ts index 913d97242..47ed83c38 100644 --- a/src/nodes/contextualValueNodes/ArgumentValueNode.ts +++ b/src/nodes/contextualValueNodes/ArgumentValueNode.ts @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared'; export type ArgumentValueNode = { readonly kind: 'argumentValueNode'; + + // Data. readonly name: MainCaseString; }; diff --git a/src/nodes/contextualValueNodes/ConditionalValueNode.ts b/src/nodes/contextualValueNodes/ConditionalValueNode.ts index d1a8308c2..24bf76eb0 100644 --- a/src/nodes/contextualValueNodes/ConditionalValueNode.ts +++ b/src/nodes/contextualValueNodes/ConditionalValueNode.ts @@ -13,6 +13,8 @@ export const CONDITIONAL_VALUE_BRANCH_NODES = INSTRUCTION_INPUT_VALUE_NODE; export type ConditionalValueNode = { readonly kind: 'conditionalValueNode'; + + // Children. readonly condition: ResolverValueNode | AccountValueNode | ArgumentValueNode; readonly value?: ValueNode; readonly ifTrue?: ConditionalValueBranch; diff --git a/src/nodes/contextualValueNodes/ContextualValueNode.ts b/src/nodes/contextualValueNodes/ContextualValueNode.ts index 8d748b48d..eafff5c2f 100644 --- a/src/nodes/contextualValueNodes/ContextualValueNode.ts +++ b/src/nodes/contextualValueNodes/ContextualValueNode.ts @@ -1,4 +1,4 @@ -import type { Mutable } from '../../shared'; +import { getNodeKinds } from '../../shared/utils'; import type { ProgramLinkNode } from '../linkNodes/ProgramLinkNode'; import { VALUE_NODES, ValueNode } from '../valueNodes/ValueNode'; import type { AccountBumpValueNode } from './AccountBumpValueNode'; @@ -7,13 +7,14 @@ import type { ArgumentValueNode } from './ArgumentValueNode'; import type { ConditionalValueNode } from './ConditionalValueNode'; import type { IdentityValueNode } from './IdentityValueNode'; import type { PayerValueNode } from './PayerValueNode'; +import type { PdaSeedValueNode } from './PdaSeedValueNode'; import type { PdaValueNode } from './PdaValueNode'; import type { ProgramIdValueNode } from './ProgramIdValueNode'; import type { ResolverValueNode } from './ResolverValueNode'; -// Node Group Registration. +// Standalone Contextual Value Node Registration. -export const REGISTERED_CONTEXTUAL_VALUE_NODES = { +export const STANDALONE_CONTEXTUAL_VALUE_NODES = { accountBumpValueNode: {} as AccountBumpValueNode, accountValueNode: {} as AccountValueNode, argumentValueNode: {} as ArgumentValueNode, @@ -25,32 +26,43 @@ export const REGISTERED_CONTEXTUAL_VALUE_NODES = { resolverValueNode: {} as ResolverValueNode, }; -export const REGISTERED_CONTEXTUAL_VALUE_NODE_KEYS = Object.keys( - REGISTERED_CONTEXTUAL_VALUE_NODES -) as (keyof typeof REGISTERED_CONTEXTUAL_VALUE_NODES)[]; +export const STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS = getNodeKinds( + STANDALONE_CONTEXTUAL_VALUE_NODES +); +export type StandaloneContextualValueNodeKind = + typeof STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS[number]; +export type StandaloneContextualValueNode = + typeof STANDALONE_CONTEXTUAL_VALUE_NODES[StandaloneContextualValueNodeKind]; + +// Contextual Value Node Registration. + +export const REGISTERED_CONTEXTUAL_VALUE_NODES = { + ...STANDALONE_CONTEXTUAL_VALUE_NODES, -export type RegisteredContextualValueNodes = - typeof REGISTERED_CONTEXTUAL_VALUE_NODES; + // The following are not valid standalone nodes. + pdaSeedValueNode: {} as PdaSeedValueNode, +}; -// Node Group Helpers. +export const REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS = getNodeKinds( + REGISTERED_CONTEXTUAL_VALUE_NODES +); +export type RegisteredContextualValueNodeKind = + typeof REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS[number]; +export type RegisteredContextualValueNode = + typeof REGISTERED_CONTEXTUAL_VALUE_NODES[RegisteredContextualValueNodeKind]; -export type ContextualValueNode = - RegisteredContextualValueNodes[keyof RegisteredContextualValueNodes]; +// Contextual Value Node Helpers. -export const CONTEXTUAL_VALUE_NODES = REGISTERED_CONTEXTUAL_VALUE_NODE_KEYS; +export type ContextualValueNode = StandaloneContextualValueNode; +export const CONTEXTUAL_VALUE_NODES = STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS; export type InstructionInputValueNode = | ValueNode | ContextualValueNode | ProgramLinkNode; -const INSTRUCTION_INPUT_VALUE_NODE_INTERNAL = [ +export const INSTRUCTION_INPUT_VALUE_NODE = [ ...VALUE_NODES, ...CONTEXTUAL_VALUE_NODES, - 'programLinkNode', -] as const; - -export const INSTRUCTION_INPUT_VALUE_NODE = - INSTRUCTION_INPUT_VALUE_NODE_INTERNAL as Mutable< - typeof INSTRUCTION_INPUT_VALUE_NODE_INTERNAL - >; + 'programLinkNode' as const, +]; diff --git a/src/nodes/contextualValueNodes/PdaSeedValueNode.ts b/src/nodes/contextualValueNodes/PdaSeedValueNode.ts new file mode 100644 index 000000000..5b918a7e4 --- /dev/null +++ b/src/nodes/contextualValueNodes/PdaSeedValueNode.ts @@ -0,0 +1,21 @@ +import { MainCaseString, mainCase } from '../../shared'; +import { ValueNode } from '../valueNodes'; +import { AccountValueNode } from './AccountValueNode'; +import { ArgumentValueNode } from './ArgumentValueNode'; + +export type PdaSeedValueNode = { + readonly kind: 'pdaSeedValueNode'; + + // Children. + readonly value: ValueNode | AccountValueNode | ArgumentValueNode; + + // Data. + readonly name: MainCaseString; +}; + +export function pdaSeedValueNode( + name: string, + value: PdaSeedValueNode['value'] +): PdaSeedValueNode { + return { kind: 'pdaSeedValueNode', name: mainCase(name), value }; +} diff --git a/src/nodes/contextualValueNodes/PdaValueNode.ts b/src/nodes/contextualValueNodes/PdaValueNode.ts index 01d78bb1e..35bedfe4e 100644 --- a/src/nodes/contextualValueNodes/PdaValueNode.ts +++ b/src/nodes/contextualValueNodes/PdaValueNode.ts @@ -1,44 +1,46 @@ -import { MainCaseString, mainCase } from '../../shared'; import { isNode } from '../Node'; import { PdaNode } from '../PdaNode'; import { PdaLinkNode, pdaLinkNode } from '../linkNodes'; -import { ValueNode } from '../valueNodes'; -import { AccountValueNode, accountValueNode } from './AccountValueNode'; -import { ArgumentValueNode, argumentValueNode } from './ArgumentValueNode'; +import { accountValueNode } from './AccountValueNode'; +import { argumentValueNode } from './ArgumentValueNode'; +import { PdaSeedValueNode, pdaSeedValueNode } from './PdaSeedValueNode'; export type PdaValueNode = { readonly kind: 'pdaValueNode'; + + // Children. readonly pda: PdaLinkNode; - readonly seeds: Record< - MainCaseString, - ValueNode | AccountValueNode | ArgumentValueNode - >; + readonly seeds: PdaSeedValueNode[]; }; export function pdaValueNode( pda: PdaLinkNode | string, - seeds: Record = {} + seeds: PdaSeedValueNode[] = [] ): PdaValueNode { return { kind: 'pdaValueNode', pda: typeof pda === 'string' ? pdaLinkNode(pda) : pda, - seeds: Object.entries(seeds).reduce((acc, [name, seedValue]) => { - acc[mainCase(name)] = seedValue; - return acc; - }, {} as PdaValueNode['seeds']), + seeds, }; } -export function getDefaultSeedValuesFromPda( - node: PdaNode -): PdaValueNode['seeds'] { - return node.seeds.reduce((acc, seed) => { - if (!isNode(seed, 'variablePdaSeedNode')) return acc; +export function addDefaultSeedValuesFromPdaWhenMissing( + node: PdaNode, + existingSeeds: PdaSeedValueNode[] +): PdaSeedValueNode[] { + const existingSeedNames = new Set(existingSeeds.map((seed) => seed.name)); + const defaultSeeds = getDefaultSeedValuesFromPda(node).filter( + (seed) => !existingSeedNames.has(seed.name) + ); + return [...defaultSeeds, ...existingSeeds]; +} + +export function getDefaultSeedValuesFromPda(node: PdaNode): PdaSeedValueNode[] { + return node.seeds.flatMap((seed): PdaSeedValueNode[] => { + if (!isNode(seed, 'variablePdaSeedNode')) return []; if (isNode(seed.type, 'publicKeyTypeNode')) { - acc[seed.name] = accountValueNode(seed.name); - } else { - acc[seed.name] = argumentValueNode(seed.name); + return [pdaSeedValueNode(seed.name, accountValueNode(seed.name))]; } - return acc; - }, {} as PdaValueNode['seeds']); + return [pdaSeedValueNode(seed.name, argumentValueNode(seed.name))]; + }); } diff --git a/src/nodes/contextualValueNodes/ResolverValueNode.ts b/src/nodes/contextualValueNodes/ResolverValueNode.ts index abed2418f..374696f33 100644 --- a/src/nodes/contextualValueNodes/ResolverValueNode.ts +++ b/src/nodes/contextualValueNodes/ResolverValueNode.ts @@ -4,9 +4,13 @@ import { ArgumentValueNode } from './ArgumentValueNode'; export type ResolverValueNode = { readonly kind: 'resolverValueNode'; + + // Children. + readonly dependsOn?: (AccountValueNode | ArgumentValueNode)[]; + + // Data. readonly name: MainCaseString; readonly importFrom?: ImportFrom; - readonly dependsOn?: (AccountValueNode | ArgumentValueNode)[]; }; export function resolverValueNode( diff --git a/src/nodes/contextualValueNodes/index.ts b/src/nodes/contextualValueNodes/index.ts index a96082467..c26843d90 100644 --- a/src/nodes/contextualValueNodes/index.ts +++ b/src/nodes/contextualValueNodes/index.ts @@ -5,6 +5,7 @@ export * from './ConditionalValueNode'; export * from './ContextualValueNode'; export * from './IdentityValueNode'; export * from './PayerValueNode'; +export * from './PdaSeedValueNode'; export * from './PdaValueNode'; export * from './ProgramIdValueNode'; export * from './ResolverValueNode'; diff --git a/src/nodes/linkNodes/AccountLinkNode.ts b/src/nodes/linkNodes/AccountLinkNode.ts index eab0f5e4a..41c3e845c 100644 --- a/src/nodes/linkNodes/AccountLinkNode.ts +++ b/src/nodes/linkNodes/AccountLinkNode.ts @@ -2,6 +2,8 @@ import { ImportFrom, MainCaseString, mainCase } from '../../shared'; export type AccountLinkNode = { readonly kind: 'accountLinkNode'; + + // Data. readonly name: MainCaseString; readonly importFrom?: ImportFrom; }; diff --git a/src/nodes/linkNodes/DefinedTypeLinkNode.ts b/src/nodes/linkNodes/DefinedTypeLinkNode.ts index 26852401a..6eab60d6b 100644 --- a/src/nodes/linkNodes/DefinedTypeLinkNode.ts +++ b/src/nodes/linkNodes/DefinedTypeLinkNode.ts @@ -2,6 +2,8 @@ import { ImportFrom, MainCaseString, mainCase } from '../../shared'; export type DefinedTypeLinkNode = { readonly kind: 'definedTypeLinkNode'; + + // Data. readonly name: MainCaseString; readonly importFrom?: ImportFrom; }; diff --git a/src/nodes/linkNodes/LinkNode.ts b/src/nodes/linkNodes/LinkNode.ts index 197728e28..9ff646666 100644 --- a/src/nodes/linkNodes/LinkNode.ts +++ b/src/nodes/linkNodes/LinkNode.ts @@ -1,9 +1,10 @@ -import type { ProgramLinkNode } from './ProgramLinkNode'; -import type { PdaLinkNode } from './PdaLinkNode'; +import { getNodeKinds } from '../../shared/utils'; import type { AccountLinkNode } from './AccountLinkNode'; import type { DefinedTypeLinkNode } from './DefinedTypeLinkNode'; +import type { PdaLinkNode } from './PdaLinkNode'; +import type { ProgramLinkNode } from './ProgramLinkNode'; -// Node Group Registration. +// Link Node Registration. export const REGISTERED_LINK_NODES = { programLinkNode: {} as ProgramLinkNode, @@ -12,14 +13,12 @@ export const REGISTERED_LINK_NODES = { definedTypeLinkNode: {} as DefinedTypeLinkNode, }; -export const REGISTERED_LINK_NODE_KEYS = Object.keys( - REGISTERED_LINK_NODES -) as (keyof typeof REGISTERED_LINK_NODES)[]; - -export type RegisteredLinkNodes = typeof REGISTERED_LINK_NODES; - -// Node Group Helpers. +export const REGISTERED_LINK_NODE_KINDS = getNodeKinds(REGISTERED_LINK_NODES); +export type RegisteredLinkNodeKind = typeof REGISTERED_LINK_NODE_KINDS[number]; +export type RegisteredLinkNode = + typeof REGISTERED_LINK_NODES[RegisteredLinkNodeKind]; -export type LinkNode = RegisteredLinkNodes[keyof RegisteredLinkNodes]; +// Link Node Helpers. -export const LINK_NODES = REGISTERED_LINK_NODE_KEYS; +export type LinkNode = RegisteredLinkNode; +export const LINK_NODES = REGISTERED_LINK_NODE_KINDS; diff --git a/src/nodes/linkNodes/PdaLinkNode.ts b/src/nodes/linkNodes/PdaLinkNode.ts index b36c25435..5673ac77f 100644 --- a/src/nodes/linkNodes/PdaLinkNode.ts +++ b/src/nodes/linkNodes/PdaLinkNode.ts @@ -2,6 +2,8 @@ import { ImportFrom, MainCaseString, mainCase } from '../../shared'; export type PdaLinkNode = { readonly kind: 'pdaLinkNode'; + + // Data. readonly name: MainCaseString; readonly importFrom?: ImportFrom; }; diff --git a/src/nodes/linkNodes/ProgramLinkNode.ts b/src/nodes/linkNodes/ProgramLinkNode.ts index 058dc7737..1a2fe7f04 100644 --- a/src/nodes/linkNodes/ProgramLinkNode.ts +++ b/src/nodes/linkNodes/ProgramLinkNode.ts @@ -2,6 +2,8 @@ import { ImportFrom, MainCaseString, mainCase } from '../../shared'; export type ProgramLinkNode = { readonly kind: 'programLinkNode'; + + // Data. readonly name: MainCaseString; readonly importFrom?: ImportFrom; }; diff --git a/src/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts b/src/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts index 8f537b6d9..13f99681d 100644 --- a/src/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts +++ b/src/nodes/pdaSeedNodes/ConstantPdaSeedNode.ts @@ -4,6 +4,8 @@ import { ValueNode, stringValueNode } from '../valueNodes'; export type ConstantPdaSeedNode = { readonly kind: 'constantPdaSeedNode'; + + // Children. readonly type: TypeNode; readonly value: ValueNode; }; diff --git a/src/nodes/pdaSeedNodes/PdaSeedNode.ts b/src/nodes/pdaSeedNodes/PdaSeedNode.ts index ac12ce4bf..60edb564a 100644 --- a/src/nodes/pdaSeedNodes/PdaSeedNode.ts +++ b/src/nodes/pdaSeedNodes/PdaSeedNode.ts @@ -1,8 +1,9 @@ +import { getNodeKinds } from '../../shared/utils'; import type { ConstantPdaSeedNode } from './ConstantPdaSeedNode'; import type { ProgramIdPdaSeedNode } from './ProgramIdPdaSeedNode'; import type { VariablePdaSeedNode } from './VariablePdaSeedNode'; -// Node Group Registration. +// Pda Seed Node Registration. export const REGISTERED_PDA_SEED_NODES = { constantPdaSeedNode: {} as ConstantPdaSeedNode, @@ -10,14 +11,15 @@ export const REGISTERED_PDA_SEED_NODES = { variablePdaSeedNode: {} as VariablePdaSeedNode, }; -export const REGISTERED_PDA_SEED_NODE_KEYS = Object.keys( +export const REGISTERED_PDA_SEED_NODE_KINDS = getNodeKinds( REGISTERED_PDA_SEED_NODES -) as (keyof typeof REGISTERED_PDA_SEED_NODES)[]; +); +export type RegisteredPdaSeedNodeKind = + typeof REGISTERED_PDA_SEED_NODE_KINDS[number]; +export type RegisteredPdaSeedNode = + typeof REGISTERED_PDA_SEED_NODES[RegisteredPdaSeedNodeKind]; -export type RegisteredPdaSeedNodes = typeof REGISTERED_PDA_SEED_NODES; +// Pda Seed Node Helpers. -// Node Group Helpers. - -export type PdaSeedNode = RegisteredPdaSeedNodes[keyof RegisteredPdaSeedNodes]; - -export const PDA_SEED_NODES = REGISTERED_PDA_SEED_NODE_KEYS; +export type PdaSeedNode = RegisteredPdaSeedNode; +export const PDA_SEED_NODES = REGISTERED_PDA_SEED_NODE_KINDS; diff --git a/src/nodes/pdaSeedNodes/VariablePdaSeedNode.ts b/src/nodes/pdaSeedNodes/VariablePdaSeedNode.ts index a47003a81..167c550b6 100644 --- a/src/nodes/pdaSeedNodes/VariablePdaSeedNode.ts +++ b/src/nodes/pdaSeedNodes/VariablePdaSeedNode.ts @@ -3,8 +3,12 @@ import { TypeNode } from '../typeNodes'; export type VariablePdaSeedNode = { readonly kind: 'variablePdaSeedNode'; - readonly name: MainCaseString; + + // Children. readonly type: TypeNode; + + // Data. + readonly name: MainCaseString; readonly docs: string[]; }; diff --git a/src/nodes/sizeNodes/FixedSizeNode.ts b/src/nodes/sizeNodes/FixedSizeNode.ts index 7e8ac5be4..e70eeef47 100644 --- a/src/nodes/sizeNodes/FixedSizeNode.ts +++ b/src/nodes/sizeNodes/FixedSizeNode.ts @@ -1,5 +1,7 @@ export type FixedSizeNode = { readonly kind: 'fixedSizeNode'; + + // Data. readonly size: number; }; diff --git a/src/nodes/sizeNodes/PrefixedSizeNode.ts b/src/nodes/sizeNodes/PrefixedSizeNode.ts index 0f6463fe8..bc8b7cbf7 100644 --- a/src/nodes/sizeNodes/PrefixedSizeNode.ts +++ b/src/nodes/sizeNodes/PrefixedSizeNode.ts @@ -2,6 +2,8 @@ import { NumberTypeNode } from '../typeNodes'; export type PrefixedSizeNode = { readonly kind: 'prefixedSizeNode'; + + // Children. readonly prefix: NumberTypeNode; }; diff --git a/src/nodes/sizeNodes/SizeNode.ts b/src/nodes/sizeNodes/SizeNode.ts index d5fb34046..2cc42cd72 100644 --- a/src/nodes/sizeNodes/SizeNode.ts +++ b/src/nodes/sizeNodes/SizeNode.ts @@ -1,8 +1,9 @@ +import { getNodeKinds } from '../../shared/utils'; import type { FixedSizeNode } from './FixedSizeNode'; import type { PrefixedSizeNode } from './PrefixedSizeNode'; import type { RemainderSizeNode } from './RemainderSizeNode'; -// Node Group Registration. +// Size Node Registration. export const REGISTERED_SIZE_NODES = { fixedSizeNode: {} as FixedSizeNode, @@ -10,14 +11,12 @@ export const REGISTERED_SIZE_NODES = { prefixedSizeNode: {} as PrefixedSizeNode, }; -export const REGISTERED_SIZE_NODE_KEYS = Object.keys( - REGISTERED_SIZE_NODES -) as (keyof typeof REGISTERED_SIZE_NODES)[]; +export const REGISTERED_SIZE_NODE_KINDS = getNodeKinds(REGISTERED_SIZE_NODES); +export type RegisteredSizeNodeKind = typeof REGISTERED_SIZE_NODE_KINDS[number]; +export type RegisteredSizeNode = + typeof REGISTERED_SIZE_NODES[RegisteredSizeNodeKind]; -export type RegisteredSizeNodes = typeof REGISTERED_SIZE_NODES; +// Size Node Helpers. -// Node Group Helpers. - -export type SizeNode = RegisteredSizeNodes[keyof RegisteredSizeNodes]; - -export const SIZE_NODES = REGISTERED_SIZE_NODE_KEYS; +export type SizeNode = RegisteredSizeNode; +export const SIZE_NODES = REGISTERED_SIZE_NODE_KINDS; diff --git a/src/nodes/typeNodes/AmountTypeNode.ts b/src/nodes/typeNodes/AmountTypeNode.ts index c9de2c068..199d4c948 100644 --- a/src/nodes/typeNodes/AmountTypeNode.ts +++ b/src/nodes/typeNodes/AmountTypeNode.ts @@ -2,15 +2,19 @@ import { NumberTypeNode } from './NumberTypeNode'; export type AmountTypeNode = { readonly kind: 'amountTypeNode'; + + // Children. readonly number: NumberTypeNode; - readonly identifier: string; + + // Data. readonly decimals: number; + readonly unit?: string; }; export function amountTypeNode( number: NumberTypeNode, - identifier: string, - decimals: number + decimals: number, + unit?: string ): AmountTypeNode { - return { kind: 'amountTypeNode', number, identifier, decimals }; + return { kind: 'amountTypeNode', number, decimals, unit }; } diff --git a/src/nodes/typeNodes/ArrayTypeNode.ts b/src/nodes/typeNodes/ArrayTypeNode.ts index 37d9dbb18..6e2f10f81 100644 --- a/src/nodes/typeNodes/ArrayTypeNode.ts +++ b/src/nodes/typeNodes/ArrayTypeNode.ts @@ -10,20 +10,17 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type ArrayTypeNode = { readonly kind: 'arrayTypeNode'; - readonly child: TypeNode; + + // Children. + readonly item: TypeNode; readonly size: SizeNode; }; -export function arrayTypeNode( - child: TypeNode, - options: { - readonly size?: ArrayTypeNode['size']; - } = {} -): ArrayTypeNode { +export function arrayTypeNode(item: TypeNode, size?: SizeNode): ArrayTypeNode { return { kind: 'arrayTypeNode', - child, - size: options.size ?? prefixedSizeNode(numberTypeNode('u32')), + item, + size: size ?? prefixedSizeNode(numberTypeNode('u32')), }; } @@ -31,16 +28,11 @@ export function arrayTypeNodeFromIdl( idl: IdlTypeArray | IdlTypeVec ): ArrayTypeNode { if ('array' in idl) { - const child = createTypeNodeFromIdl(idl.array[0]); - return arrayTypeNode(child, { size: fixedSizeNode(idl.array[1]) }); - } - - const child = createTypeNodeFromIdl(idl.vec); - if (!idl.size) return arrayTypeNode(child); - if (idl.size === 'remainder') { - return arrayTypeNode(child, { size: remainderSizeNode() }); + const item = createTypeNodeFromIdl(idl.array[0]); + return arrayTypeNode(item, fixedSizeNode(idl.array[1])); } - return arrayTypeNode(child, { - size: prefixedSizeNode(numberTypeNode(idl.size)), - }); + const item = createTypeNodeFromIdl(idl.vec); + if (!idl.size) return arrayTypeNode(item); + if (idl.size === 'remainder') return arrayTypeNode(item, remainderSizeNode()); + return arrayTypeNode(item, prefixedSizeNode(numberTypeNode(idl.size))); } diff --git a/src/nodes/typeNodes/BooleanTypeNode.ts b/src/nodes/typeNodes/BooleanTypeNode.ts index 6b0a1e979..e6dc9f181 100644 --- a/src/nodes/typeNodes/BooleanTypeNode.ts +++ b/src/nodes/typeNodes/BooleanTypeNode.ts @@ -2,6 +2,8 @@ import { NumberTypeNode, numberTypeNode } from './NumberTypeNode'; export type BooleanTypeNode = { readonly kind: 'booleanTypeNode'; + + // Children. readonly size: NumberTypeNode; }; diff --git a/src/nodes/typeNodes/BytesTypeNode.ts b/src/nodes/typeNodes/BytesTypeNode.ts index 4368d5147..359c9d3b1 100644 --- a/src/nodes/typeNodes/BytesTypeNode.ts +++ b/src/nodes/typeNodes/BytesTypeNode.ts @@ -2,6 +2,8 @@ import { SizeNode, remainderSizeNode } from '../sizeNodes'; export type BytesTypeNode = { readonly kind: 'bytesTypeNode'; + + // Children. readonly size: SizeNode; }; diff --git a/src/nodes/typeNodes/DateTimeTypeNode.ts b/src/nodes/typeNodes/DateTimeTypeNode.ts index 004ed2848..39412249f 100644 --- a/src/nodes/typeNodes/DateTimeTypeNode.ts +++ b/src/nodes/typeNodes/DateTimeTypeNode.ts @@ -2,6 +2,8 @@ import { NumberTypeNode } from './NumberTypeNode'; export type DateTimeTypeNode = { readonly kind: 'dateTimeTypeNode'; + + // Children. readonly number: NumberTypeNode; }; diff --git a/src/nodes/typeNodes/EnumEmptyVariantTypeNode.ts b/src/nodes/typeNodes/EnumEmptyVariantTypeNode.ts index 697971f81..c51deffa4 100644 --- a/src/nodes/typeNodes/EnumEmptyVariantTypeNode.ts +++ b/src/nodes/typeNodes/EnumEmptyVariantTypeNode.ts @@ -3,6 +3,8 @@ import { InvalidKinobiTreeError, MainCaseString, mainCase } from '../../shared'; export type EnumEmptyVariantTypeNode = { readonly kind: 'enumEmptyVariantTypeNode'; + + // Data. readonly name: MainCaseString; }; diff --git a/src/nodes/typeNodes/EnumStructVariantTypeNode.ts b/src/nodes/typeNodes/EnumStructVariantTypeNode.ts index 99ccc3c02..720b2e46a 100644 --- a/src/nodes/typeNodes/EnumStructVariantTypeNode.ts +++ b/src/nodes/typeNodes/EnumStructVariantTypeNode.ts @@ -4,8 +4,12 @@ import { StructTypeNode, structTypeNodeFromIdl } from './StructTypeNode'; export type EnumStructVariantTypeNode = { readonly kind: 'enumStructVariantTypeNode'; - readonly name: MainCaseString; + + // Children. readonly struct: StructTypeNode; + + // Data. + readonly name: MainCaseString; }; export function enumStructVariantTypeNode( diff --git a/src/nodes/typeNodes/EnumTupleVariantTypeNode.ts b/src/nodes/typeNodes/EnumTupleVariantTypeNode.ts index 9816076ba..a462143e6 100644 --- a/src/nodes/typeNodes/EnumTupleVariantTypeNode.ts +++ b/src/nodes/typeNodes/EnumTupleVariantTypeNode.ts @@ -4,8 +4,12 @@ import { TupleTypeNode, tupleTypeNodeFromIdl } from './TupleTypeNode'; export type EnumTupleVariantTypeNode = { readonly kind: 'enumTupleVariantTypeNode'; - readonly name: MainCaseString; + + // Children. readonly tuple: TupleTypeNode; + + // Data. + readonly name: MainCaseString; }; export function enumTupleVariantTypeNode( diff --git a/src/nodes/typeNodes/EnumTypeNode.ts b/src/nodes/typeNodes/EnumTypeNode.ts index 9fba098da..1bdc87f35 100644 --- a/src/nodes/typeNodes/EnumTypeNode.ts +++ b/src/nodes/typeNodes/EnumTypeNode.ts @@ -7,6 +7,8 @@ import { NumberTypeNode, numberTypeNode } from './NumberTypeNode'; export type EnumTypeNode = { readonly kind: 'enumTypeNode'; + + // Children. readonly variants: EnumVariantTypeNode[]; readonly size: NumberTypeNode; }; diff --git a/src/nodes/typeNodes/MapTypeNode.ts b/src/nodes/typeNodes/MapTypeNode.ts index c50d4101d..7ad011b49 100644 --- a/src/nodes/typeNodes/MapTypeNode.ts +++ b/src/nodes/typeNodes/MapTypeNode.ts @@ -10,26 +10,28 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type MapTypeNode = { readonly kind: 'mapTypeNode'; + + // Children. readonly key: TypeNode; readonly value: TypeNode; readonly size: SizeNode; + + // Data. readonly idlMap: 'hashMap' | 'bTreeMap'; }; export function mapTypeNode( key: TypeNode, value: TypeNode, - options: { - readonly size?: MapTypeNode['size']; - readonly idlMap?: MapTypeNode['idlMap']; - } = {} + size?: SizeNode, + idlMap?: MapTypeNode['idlMap'] ): MapTypeNode { return { kind: 'mapTypeNode', key, value, - size: options.size ?? prefixedSizeNode(numberTypeNode('u32')), - idlMap: options.idlMap ?? 'hashMap', + size: size ?? prefixedSizeNode(numberTypeNode('u32')), + idlMap: idlMap ?? 'hashMap', }; } @@ -43,8 +45,10 @@ export function mapTypeNodeFromIdl(idl: IdlTypeMap): MapTypeNode { } else if (idl.size) { size = prefixedSizeNode(numberTypeNode(idl.size)); } - return mapTypeNode(createTypeNodeFromIdl(key), createTypeNodeFromIdl(value), { + return mapTypeNode( + createTypeNodeFromIdl(key), + createTypeNodeFromIdl(value), size, - idlMap: 'hashMap' in idl ? 'hashMap' : 'bTreeMap', - }); + 'hashMap' in idl ? 'hashMap' : 'bTreeMap' + ); } diff --git a/src/nodes/typeNodes/NumberTypeNode.ts b/src/nodes/typeNodes/NumberTypeNode.ts index 361b8740e..e61518987 100644 --- a/src/nodes/typeNodes/NumberTypeNode.ts +++ b/src/nodes/typeNodes/NumberTypeNode.ts @@ -14,6 +14,8 @@ export type NumberFormat = export type NumberTypeNode = { readonly kind: 'numberTypeNode'; + + // Data. readonly format: NumberFormat; readonly endian: 'le' | 'be'; }; diff --git a/src/nodes/typeNodes/OptionTypeNode.ts b/src/nodes/typeNodes/OptionTypeNode.ts index 9b48d4078..789b889b7 100644 --- a/src/nodes/typeNodes/OptionTypeNode.ts +++ b/src/nodes/typeNodes/OptionTypeNode.ts @@ -4,14 +4,18 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type OptionTypeNode = { readonly kind: 'optionTypeNode'; - readonly child: TypeNode; + + // Children. + readonly item: TypeNode; readonly prefix: NumberTypeNode; + + // Data. readonly fixed: boolean; readonly idlOption: 'option' | 'coption'; }; export function optionTypeNode( - child: TypeNode, + item: TypeNode, options: { readonly prefix?: NumberTypeNode; readonly fixed?: boolean; @@ -20,7 +24,7 @@ export function optionTypeNode( ): OptionTypeNode { return { kind: 'optionTypeNode', - child, + item, prefix: options.prefix ?? numberTypeNode('u8'), fixed: options.fixed ?? false, idlOption: options.idlOption ?? 'option', @@ -28,10 +32,10 @@ export function optionTypeNode( } export function optionTypeNodeFromIdl(idl: IdlTypeOption): OptionTypeNode { - const child = 'option' in idl ? idl.option : idl.coption; + const item = 'option' in idl ? idl.option : idl.coption; const defaultPrefix = numberTypeNode('option' in idl ? 'u8' : 'u32'); const defaultFixed = !('option' in idl); - return optionTypeNode(createTypeNodeFromIdl(child), { + return optionTypeNode(createTypeNodeFromIdl(item), { prefix: idl.prefix ? numberTypeNode(idl.prefix) : defaultPrefix, fixed: idl.fixed !== undefined ? idl.fixed : defaultFixed, idlOption: 'option' in idl ? 'option' : 'coption', diff --git a/src/nodes/typeNodes/SetTypeNode.ts b/src/nodes/typeNodes/SetTypeNode.ts index 0ee0e8b0e..47b48e92a 100644 --- a/src/nodes/typeNodes/SetTypeNode.ts +++ b/src/nodes/typeNodes/SetTypeNode.ts @@ -10,23 +10,25 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type SetTypeNode = { readonly kind: 'setTypeNode'; - readonly child: TypeNode; + + // Children. + readonly item: TypeNode; readonly size: SizeNode; + + // Data. readonly idlSet: 'hashSet' | 'bTreeSet'; }; export function setTypeNode( - child: TypeNode, - options: { - readonly size?: SetTypeNode['size']; - readonly idlSet?: SetTypeNode['idlSet']; - } = {} + item: TypeNode, + size?: SizeNode, + idlSet?: SetTypeNode['idlSet'] ): SetTypeNode { return { kind: 'setTypeNode', - child, - size: options.size ?? prefixedSizeNode(numberTypeNode('u32')), - idlSet: options.idlSet ?? 'hashSet', + item, + size: size ?? prefixedSizeNode(numberTypeNode('u32')), + idlSet: idlSet ?? 'hashSet', }; } @@ -40,8 +42,9 @@ export function setTypeNodeFromIdl(idl: IdlTypeSet): SetTypeNode { } else if (idl.size) { size = prefixedSizeNode(numberTypeNode(idl.size)); } - return setTypeNode(createTypeNodeFromIdl(child), { + return setTypeNode( + createTypeNodeFromIdl(child), size, - idlSet: 'hashSet' in idl ? 'hashSet' : 'bTreeSet', - }); + 'hashSet' in idl ? 'hashSet' : 'bTreeSet' + ); } diff --git a/src/nodes/typeNodes/SolAmountTypeNode.ts b/src/nodes/typeNodes/SolAmountTypeNode.ts index 14c0e2824..f06a02852 100644 --- a/src/nodes/typeNodes/SolAmountTypeNode.ts +++ b/src/nodes/typeNodes/SolAmountTypeNode.ts @@ -2,6 +2,8 @@ import { NumberTypeNode } from './NumberTypeNode'; export type SolAmountTypeNode = { readonly kind: 'solAmountTypeNode'; + + // Children. readonly number: NumberTypeNode; }; diff --git a/src/nodes/typeNodes/StringTypeNode.ts b/src/nodes/typeNodes/StringTypeNode.ts index 2b3619232..210758574 100644 --- a/src/nodes/typeNodes/StringTypeNode.ts +++ b/src/nodes/typeNodes/StringTypeNode.ts @@ -5,19 +5,23 @@ export type StringEncoding = 'utf8' | 'base16' | 'base58' | 'base64'; export type StringTypeNode = { readonly kind: 'stringTypeNode'; - readonly encoding: StringEncoding; + + // Children. readonly size: SizeNode; + + // Data. + readonly encoding: StringEncoding; }; export function stringTypeNode( - options: { + input: { readonly encoding?: StringEncoding; readonly size?: SizeNode; } = {} ): StringTypeNode { return { kind: 'stringTypeNode', - encoding: options.encoding ?? 'utf8', - size: options.size ?? prefixedSizeNode(numberTypeNode('u32')), + encoding: input.encoding ?? 'utf8', + size: input.size ?? prefixedSizeNode(numberTypeNode('u32')), }; } diff --git a/src/nodes/typeNodes/StructFieldTypeNode.ts b/src/nodes/typeNodes/StructFieldTypeNode.ts index da9e83f97..81cc4127d 100644 --- a/src/nodes/typeNodes/StructFieldTypeNode.ts +++ b/src/nodes/typeNodes/StructFieldTypeNode.ts @@ -5,20 +5,23 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type StructFieldTypeNode = { readonly kind: 'structFieldTypeNode'; + + // Children. + readonly type: TypeNode; + readonly defaultValue?: ValueNode; + + // Data. readonly name: MainCaseString; - readonly child: TypeNode; readonly docs: string[]; - readonly defaultsTo: { - strategy: 'optional' | 'omitted'; - value: ValueNode; - } | null; + readonly defaultValueStrategy?: 'optional' | 'omitted'; }; export type StructFieldTypeNodeInput = { readonly name: string; - readonly child: TypeNode; + readonly type: TypeNode; readonly docs?: string[]; - readonly defaultsTo?: StructFieldTypeNode['defaultsTo']; + readonly defaultValue?: ValueNode; + readonly defaultValueStrategy?: 'optional' | 'omitted'; }; export function structFieldTypeNode( @@ -30,9 +33,10 @@ export function structFieldTypeNode( return { kind: 'structFieldTypeNode', name: mainCase(input.name), - child: input.child, + type: input.type, docs: input.docs ?? [], - defaultsTo: input.defaultsTo ?? null, + defaultValue: input.defaultValue, + defaultValueStrategy: input.defaultValueStrategy, }; } @@ -41,8 +45,7 @@ export function structFieldTypeNodeFromIdl( ): StructFieldTypeNode { return structFieldTypeNode({ name: idl.name ?? '', - child: createTypeNodeFromIdl(idl.type), + type: createTypeNodeFromIdl(idl.type), docs: idl.docs ?? [], - defaultsTo: null, }); } diff --git a/src/nodes/typeNodes/StructTypeNode.ts b/src/nodes/typeNodes/StructTypeNode.ts index 642cda035..76fe0627e 100644 --- a/src/nodes/typeNodes/StructTypeNode.ts +++ b/src/nodes/typeNodes/StructTypeNode.ts @@ -6,6 +6,8 @@ import { export type StructTypeNode = { readonly kind: 'structTypeNode'; + + // Children. readonly fields: StructFieldTypeNode[]; }; diff --git a/src/nodes/typeNodes/TupleTypeNode.ts b/src/nodes/typeNodes/TupleTypeNode.ts index a2cb555a4..0994f28d1 100644 --- a/src/nodes/typeNodes/TupleTypeNode.ts +++ b/src/nodes/typeNodes/TupleTypeNode.ts @@ -3,13 +3,15 @@ import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; export type TupleTypeNode = { readonly kind: 'tupleTypeNode'; - readonly children: TypeNode[]; + + // Children. + readonly items: TypeNode[]; }; export function tupleTypeNode( - children: [...TItems] -): TupleTypeNode & { readonly children: [...TItems] } { - return { kind: 'tupleTypeNode', children }; + items: [...TItems] +): TupleTypeNode & { readonly items: [...TItems] } { + return { kind: 'tupleTypeNode', items }; } export function tupleTypeNodeFromIdl(idl: IdlTypeTuple): TupleTypeNode { diff --git a/src/nodes/typeNodes/TypeNode.ts b/src/nodes/typeNodes/TypeNode.ts index 9eed8274f..64c77d037 100644 --- a/src/nodes/typeNodes/TypeNode.ts +++ b/src/nodes/typeNodes/TypeNode.ts @@ -1,7 +1,9 @@ -import type { Mutable } from '../../shared'; import { IDL_TYPE_LEAVES, IdlType } from '../../idl'; -import type { RegisteredNodes } from '../Node'; -import { definedTypeLinkNode } from '../linkNodes/DefinedTypeLinkNode'; +import { getNodeKinds } from '../../shared/utils'; +import { + DefinedTypeLinkNode, + definedTypeLinkNode, +} from '../linkNodes/DefinedTypeLinkNode'; import { prefixedSizeNode } from '../sizeNodes/PrefixedSizeNode'; import { AmountTypeNode } from './AmountTypeNode'; import { ArrayTypeNode, arrayTypeNodeFromIdl } from './ArrayTypeNode'; @@ -23,9 +25,9 @@ import { StructFieldTypeNode } from './StructFieldTypeNode'; import { StructTypeNode, structTypeNodeFromIdl } from './StructTypeNode'; import { TupleTypeNode, tupleTypeNodeFromIdl } from './TupleTypeNode'; -// Node Group Registration. +// Standalone Type Node Registration. -export const REGISTERED_TYPE_NODES = { +export const STANDALONE_TYPE_NODES = { amountTypeNode: {} as AmountTypeNode, arrayTypeNode: {} as ArrayTypeNode, booleanTypeNode: {} as BooleanTypeNode, @@ -41,54 +43,41 @@ export const REGISTERED_TYPE_NODES = { stringTypeNode: {} as StringTypeNode, structTypeNode: {} as StructTypeNode, tupleTypeNode: {} as TupleTypeNode, +}; + +export const STANDALONE_TYPE_NODE_KINDS = getNodeKinds(STANDALONE_TYPE_NODES); +export type StandaloneTypeNodeKind = typeof STANDALONE_TYPE_NODE_KINDS[number]; +export type StandaloneTypeNode = + typeof STANDALONE_TYPE_NODES[StandaloneTypeNodeKind]; + +// Type Node Registration. - // The following are not valid standalone types. +export const REGISTERED_TYPE_NODES = { + ...STANDALONE_TYPE_NODES, + + // The following are not valid standalone nodes. structFieldTypeNode: {} as StructFieldTypeNode, enumEmptyVariantTypeNode: {} as EnumEmptyVariantTypeNode, enumStructVariantTypeNode: {} as EnumStructVariantTypeNode, enumTupleVariantTypeNode: {} as EnumTupleVariantTypeNode, }; -export const REGISTERED_TYPE_NODE_KEYS = Object.keys( - REGISTERED_TYPE_NODES -) as (keyof typeof REGISTERED_TYPE_NODES)[]; - -export type RegisteredTypeNodes = typeof REGISTERED_TYPE_NODES; +export const REGISTERED_TYPE_NODE_KINDS = getNodeKinds(REGISTERED_TYPE_NODES); +export type RegisteredTypeNodeKind = typeof REGISTERED_TYPE_NODE_KINDS[number]; +export type RegisteredTypeNode = + typeof REGISTERED_TYPE_NODES[RegisteredTypeNodeKind]; // Type Node Helpers. // This only includes type nodes that can be used as standalone types. // E.g. this excludes structFieldTypeNode, enumEmptyVariantTypeNode, etc. // It also includes the definedTypeLinkNode to compose types. -const TYPE_NODES_INTERNAL = [ - // Standalone types. - 'amountTypeNode', - 'arrayTypeNode', - 'booleanTypeNode', - 'bytesTypeNode', - 'dateTimeTypeNode', - 'enumTypeNode', - 'mapTypeNode', - 'numberTypeNode', - 'optionTypeNode', - 'publicKeyTypeNode', - 'setTypeNode', - 'solAmountTypeNode', - 'stringTypeNode', - 'structTypeNode', - 'tupleTypeNode', - - // Link types. - 'definedTypeLinkNode', -] as const; - -export const TYPE_NODES = TYPE_NODES_INTERNAL as Mutable< - typeof TYPE_NODES_INTERNAL ->; - -export type TypeNode = RegisteredNodes[typeof TYPE_NODES[number]]; - -// Node Group Helpers. +export const TYPE_NODES = [ + ...STANDALONE_TYPE_NODE_KINDS, + 'definedTypeLinkNode' as const, +]; +export type TypeNodeKind = typeof TYPE_NODES[number]; +export type TypeNode = StandaloneTypeNode | DefinedTypeLinkNode; function isArrayOfSize(array: any, size: number): boolean { return Array.isArray(array) && array.length === size; diff --git a/src/nodes/valueNodes/ArrayValueNode.ts b/src/nodes/valueNodes/ArrayValueNode.ts index 7b3db7f6c..31a04c6cb 100644 --- a/src/nodes/valueNodes/ArrayValueNode.ts +++ b/src/nodes/valueNodes/ArrayValueNode.ts @@ -2,6 +2,8 @@ import { ValueNode } from './ValueNode'; export type ArrayValueNode = { readonly kind: 'arrayValueNode'; + + // Children. readonly items: ValueNode[]; }; diff --git a/src/nodes/valueNodes/BooleanValueNode.ts b/src/nodes/valueNodes/BooleanValueNode.ts index 97a29890f..d460245ed 100644 --- a/src/nodes/valueNodes/BooleanValueNode.ts +++ b/src/nodes/valueNodes/BooleanValueNode.ts @@ -1,5 +1,7 @@ export type BooleanValueNode = { readonly kind: 'booleanValueNode'; + + // Data. readonly boolean: boolean; }; diff --git a/src/nodes/valueNodes/EnumValueNode.ts b/src/nodes/valueNodes/EnumValueNode.ts index ba002b8eb..3d8a1d96a 100644 --- a/src/nodes/valueNodes/EnumValueNode.ts +++ b/src/nodes/valueNodes/EnumValueNode.ts @@ -1,26 +1,29 @@ -import { ImportFrom, MainCaseString, mainCase } from '../../shared'; +import { MainCaseString, mainCase } from '../../shared'; +import { DefinedTypeLinkNode, definedTypeLinkNode } from '../linkNodes'; import { StructValueNode } from './StructValueNode'; import { TupleValueNode } from './TupleValueNode'; export type EnumValueNode = { readonly kind: 'enumValueNode'; - readonly enumType: MainCaseString; + + // Children. + readonly enum: DefinedTypeLinkNode; + readonly value?: StructValueNode | TupleValueNode; + + // Data. readonly variant: MainCaseString; - readonly value: StructValueNode | TupleValueNode | 'empty' | 'scalar'; - readonly importFrom: ImportFrom | null; }; export function enumValueNode( - enumType: string, + enumLink: DefinedTypeLinkNode | string, variant: string, - value?: StructValueNode | TupleValueNode | 'empty' | 'scalar', - importFrom?: ImportFrom | null + value?: StructValueNode | TupleValueNode ): EnumValueNode { return { kind: 'enumValueNode', - enumType: mainCase(enumType), + enum: + typeof enumLink === 'string' ? definedTypeLinkNode(enumLink) : enumLink, variant: mainCase(variant), - value: value ?? 'scalar', - importFrom: importFrom ?? null, + value, }; } diff --git a/src/nodes/valueNodes/MapEntryValueNode.ts b/src/nodes/valueNodes/MapEntryValueNode.ts new file mode 100644 index 000000000..4e6c37275 --- /dev/null +++ b/src/nodes/valueNodes/MapEntryValueNode.ts @@ -0,0 +1,16 @@ +import { ValueNode } from './ValueNode'; + +export type MapEntryValueNode = { + readonly kind: 'mapEntryValueNode'; + + // Children. + readonly key: ValueNode; + readonly value: ValueNode; +}; + +export function mapEntryValueNode( + key: ValueNode, + value: ValueNode +): MapEntryValueNode { + return { kind: 'mapEntryValueNode', key, value }; +} diff --git a/src/nodes/valueNodes/MapValueNode.ts b/src/nodes/valueNodes/MapValueNode.ts index 3fba0449c..1f7d7b18c 100644 --- a/src/nodes/valueNodes/MapValueNode.ts +++ b/src/nodes/valueNodes/MapValueNode.ts @@ -1,10 +1,12 @@ -import { ValueNode } from './ValueNode'; +import { MapEntryValueNode } from './MapEntryValueNode'; export type MapValueNode = { readonly kind: 'mapValueNode'; - readonly entries: [ValueNode, ValueNode][]; + + // Children. + readonly entries: MapEntryValueNode[]; }; -export function mapValueNode(entries: [ValueNode, ValueNode][]): MapValueNode { +export function mapValueNode(entries: MapEntryValueNode[]): MapValueNode { return { kind: 'mapValueNode', entries }; } diff --git a/src/nodes/valueNodes/NumberValueNode.ts b/src/nodes/valueNodes/NumberValueNode.ts index 37c471e99..7661f95e8 100644 --- a/src/nodes/valueNodes/NumberValueNode.ts +++ b/src/nodes/valueNodes/NumberValueNode.ts @@ -1,5 +1,7 @@ export type NumberValueNode = { readonly kind: 'numberValueNode'; + + // Data. readonly number: number; }; diff --git a/src/nodes/valueNodes/PublicKeyValueNode.ts b/src/nodes/valueNodes/PublicKeyValueNode.ts index 31fdf6808..fa57e4e0e 100644 --- a/src/nodes/valueNodes/PublicKeyValueNode.ts +++ b/src/nodes/valueNodes/PublicKeyValueNode.ts @@ -1,5 +1,7 @@ export type PublicKeyValueNode = { readonly kind: 'publicKeyValueNode'; + + // Data. readonly publicKey: string; }; diff --git a/src/nodes/valueNodes/SetValueNode.ts b/src/nodes/valueNodes/SetValueNode.ts index 8474443df..aaf4abed0 100644 --- a/src/nodes/valueNodes/SetValueNode.ts +++ b/src/nodes/valueNodes/SetValueNode.ts @@ -2,6 +2,8 @@ import { ValueNode } from './ValueNode'; export type SetValueNode = { readonly kind: 'setValueNode'; + + // Children. readonly items: ValueNode[]; }; diff --git a/src/nodes/valueNodes/SomeValueNode.ts b/src/nodes/valueNodes/SomeValueNode.ts index 891ef9c00..b16e68284 100644 --- a/src/nodes/valueNodes/SomeValueNode.ts +++ b/src/nodes/valueNodes/SomeValueNode.ts @@ -2,6 +2,8 @@ import { ValueNode } from './ValueNode'; export type SomeValueNode = { readonly kind: 'someValueNode'; + + // Children. readonly value: ValueNode; }; diff --git a/src/nodes/valueNodes/StringValueNode.ts b/src/nodes/valueNodes/StringValueNode.ts index c291ac5f3..2abdea469 100644 --- a/src/nodes/valueNodes/StringValueNode.ts +++ b/src/nodes/valueNodes/StringValueNode.ts @@ -1,5 +1,7 @@ export type StringValueNode = { readonly kind: 'stringValueNode'; + + // Data. readonly string: string; }; diff --git a/src/nodes/valueNodes/StructFieldValueNode.ts b/src/nodes/valueNodes/StructFieldValueNode.ts new file mode 100644 index 000000000..6809508fd --- /dev/null +++ b/src/nodes/valueNodes/StructFieldValueNode.ts @@ -0,0 +1,19 @@ +import { MainCaseString, mainCase } from '../../shared'; +import { ValueNode } from './ValueNode'; + +export type StructFieldValueNode = { + readonly kind: 'structFieldValueNode'; + + // Children. + readonly value: ValueNode; + + // Data. + readonly name: MainCaseString; +}; + +export function structFieldValueNode( + name: string, + value: ValueNode +): StructFieldValueNode { + return { kind: 'structFieldValueNode', name: mainCase(name), value }; +} diff --git a/src/nodes/valueNodes/StructValueNode.ts b/src/nodes/valueNodes/StructValueNode.ts index 5f998f077..597b28f85 100644 --- a/src/nodes/valueNodes/StructValueNode.ts +++ b/src/nodes/valueNodes/StructValueNode.ts @@ -1,18 +1,14 @@ -import { MainCaseString, mainCase } from '../../shared'; -import { ValueNode } from './ValueNode'; +import { StructFieldValueNode } from './StructFieldValueNode'; export type StructValueNode = { readonly kind: 'structValueNode'; - readonly fields: Record; + + // Children. + readonly fields: StructFieldValueNode[]; }; export function structValueNode( - fields: Record + fields: StructFieldValueNode[] ): StructValueNode { - return { - kind: 'structValueNode', - fields: Object.fromEntries( - Object.entries(fields).map(([key, value]) => [mainCase(key), value]) - ), - }; + return { kind: 'structValueNode', fields }; } diff --git a/src/nodes/valueNodes/TupleValueNode.ts b/src/nodes/valueNodes/TupleValueNode.ts index 2ae39e259..3fef80473 100644 --- a/src/nodes/valueNodes/TupleValueNode.ts +++ b/src/nodes/valueNodes/TupleValueNode.ts @@ -2,6 +2,8 @@ import { ValueNode } from './ValueNode'; export type TupleValueNode = { readonly kind: 'tupleValueNode'; + + // Children. readonly items: ValueNode[]; }; diff --git a/src/nodes/valueNodes/ValueNode.ts b/src/nodes/valueNodes/ValueNode.ts index 760f75e79..1f348abf3 100644 --- a/src/nodes/valueNodes/ValueNode.ts +++ b/src/nodes/valueNodes/ValueNode.ts @@ -1,6 +1,8 @@ +import { getNodeKinds } from '../../shared/utils'; import type { ArrayValueNode } from './ArrayValueNode'; import type { BooleanValueNode } from './BooleanValueNode'; import type { EnumValueNode } from './EnumValueNode'; +import type { MapEntryValueNode } from './MapEntryValueNode'; import type { MapValueNode } from './MapValueNode'; import type { NoneValueNode } from './NoneValueNode'; import type { NumberValueNode } from './NumberValueNode'; @@ -8,12 +10,13 @@ import type { PublicKeyValueNode } from './PublicKeyValueNode'; import type { SetValueNode } from './SetValueNode'; import type { SomeValueNode } from './SomeValueNode'; import type { StringValueNode } from './StringValueNode'; +import type { StructFieldValueNode } from './StructFieldValueNode'; import type { StructValueNode } from './StructValueNode'; import type { TupleValueNode } from './TupleValueNode'; -// Node Group Registration. +// Standalone Value Node Registration. -export const REGISTERED_VALUE_NODES = { +export const STANDALONE_VALUE_NODES = { arrayValueNode: {} as ArrayValueNode, booleanValueNode: {} as BooleanValueNode, enumValueNode: {} as EnumValueNode, @@ -28,14 +31,29 @@ export const REGISTERED_VALUE_NODES = { stringValueNode: {} as StringValueNode, }; -export const REGISTERED_VALUE_NODE_KEYS = Object.keys( - REGISTERED_VALUE_NODES -) as (keyof typeof REGISTERED_VALUE_NODES)[]; +export const STANDALONE_VALUE_NODE_KINDS = getNodeKinds(STANDALONE_VALUE_NODES); +export type StandaloneValueNodeKind = + typeof STANDALONE_VALUE_NODE_KINDS[number]; +export type StandaloneValueNode = + typeof STANDALONE_VALUE_NODES[StandaloneValueNodeKind]; + +// Value Node Registration. -export type RegisteredValueNodes = typeof REGISTERED_VALUE_NODES; +export const REGISTERED_VALUE_NODES = { + ...STANDALONE_VALUE_NODES, + + // The following are not valid standalone nodes. + mapEntryValueNode: {} as MapEntryValueNode, + structFieldValueNode: {} as StructFieldValueNode, +}; -// Node Group Helpers. +export const REGISTERED_VALUE_NODE_KINDS = getNodeKinds(REGISTERED_VALUE_NODES); +export type RegisteredValueNodeKind = + typeof REGISTERED_VALUE_NODE_KINDS[number]; +export type RegisteredValueNode = + typeof REGISTERED_VALUE_NODES[RegisteredValueNodeKind]; -export type ValueNode = RegisteredValueNodes[keyof RegisteredValueNodes]; +// Value Node Helpers. -export const VALUE_NODES = REGISTERED_VALUE_NODE_KEYS; +export type ValueNode = StandaloneValueNode; +export const VALUE_NODES = STANDALONE_VALUE_NODE_KINDS; diff --git a/src/nodes/valueNodes/index.ts b/src/nodes/valueNodes/index.ts index 201527561..40f3a71cf 100644 --- a/src/nodes/valueNodes/index.ts +++ b/src/nodes/valueNodes/index.ts @@ -1,12 +1,14 @@ export * from './ArrayValueNode'; export * from './BooleanValueNode'; export * from './EnumValueNode'; +export * from './MapEntryValueNode'; export * from './MapValueNode'; export * from './NumberValueNode'; export * from './PublicKeyValueNode'; export * from './SetValueNode'; export * from './SomeValueNode'; export * from './StringValueNode'; +export * from './StructFieldValueNode'; export * from './StructValueNode'; export * from './TupleValueNode'; export * from './ValueNode'; diff --git a/src/renderers/js-experimental/asyncHelpers.ts b/src/renderers/js-experimental/asyncHelpers.ts index 211fe9fe7..04f5f8a4a 100644 --- a/src/renderers/js-experimental/asyncHelpers.ts +++ b/src/renderers/js-experimental/asyncHelpers.ts @@ -26,29 +26,29 @@ export function hasAsyncDefaultValues( ): boolean { return resolvedInputs.some( (input) => - !!input.defaultsTo && - isAsyncDefaultValue(input.defaultsTo, asyncResolvers) + !!input.defaultValue && + isAsyncDefaultValue(input.defaultValue, asyncResolvers) ); } export function isAsyncDefaultValue( - defaultsTo: InstructionInputValueNode, + defaultValue: InstructionInputValueNode, asyncResolvers: string[] ): boolean { - switch (defaultsTo.kind) { + switch (defaultValue.kind) { case 'pdaValueNode': return true; case 'resolverValueNode': - return asyncResolvers.includes(defaultsTo.name); + return asyncResolvers.includes(defaultValue.name); case 'conditionalValueNode': return ( - isAsyncDefaultValue(defaultsTo.condition, asyncResolvers) || - (defaultsTo.ifFalse == null + isAsyncDefaultValue(defaultValue.condition, asyncResolvers) || + (defaultValue.ifFalse == null ? false - : isAsyncDefaultValue(defaultsTo.ifFalse, asyncResolvers)) || - (defaultsTo.ifTrue == null + : isAsyncDefaultValue(defaultValue.ifFalse, asyncResolvers)) || + (defaultValue.ifTrue == null ? false - : isAsyncDefaultValue(defaultsTo.ifTrue, asyncResolvers)) + : isAsyncDefaultValue(defaultValue.ifTrue, asyncResolvers)) ); default: return false; diff --git a/src/renderers/js-experimental/fragments/accountFetchHelpers.ts b/src/renderers/js-experimental/fragments/accountFetchHelpers.ts index 94a4043b8..2b17febb0 100644 --- a/src/renderers/js-experimental/fragments/accountFetchHelpers.ts +++ b/src/renderers/js-experimental/fragments/accountFetchHelpers.ts @@ -1,13 +1,14 @@ import { AccountNode } from '../../../nodes'; import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getAccountFetchHelpersFragment(scope: { - accountNode: AccountNode; - typeManifest: TypeManifest; - nameApi: NameApi; -}): Fragment { +export function getAccountFetchHelpersFragment( + scope: Pick & { + accountNode: AccountNode; + typeManifest: TypeManifest; + } +): Fragment { const { accountNode, typeManifest, nameApi } = scope; const decoderFunctionFragment = accountNode.data.link ? typeManifest.decoder.clone() diff --git a/src/renderers/js-experimental/fragments/accountPdaHelpers.ts b/src/renderers/js-experimental/fragments/accountPdaHelpers.ts index 46d30c8a4..1e1e17bb3 100644 --- a/src/renderers/js-experimental/fragments/accountPdaHelpers.ts +++ b/src/renderers/js-experimental/fragments/accountPdaHelpers.ts @@ -1,14 +1,13 @@ import { AccountNode, ProgramNode, isNodeFilter } from '../../../nodes'; -import { LinkableDictionary } from '../../../shared'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getAccountPdaHelpersFragment(scope: { - accountNode: AccountNode; - programNode: ProgramNode; - nameApi: NameApi; - linkables: LinkableDictionary; -}): Fragment { +export function getAccountPdaHelpersFragment( + scope: Pick & { + accountNode: AccountNode; + programNode: ProgramNode; + } +): Fragment { const { accountNode, programNode, nameApi, linkables } = scope; const pdaNode = accountNode.pda ? linkables.get(accountNode.pda) : undefined; if (!pdaNode) { diff --git a/src/renderers/js-experimental/fragments/accountSizeHelpers.ts b/src/renderers/js-experimental/fragments/accountSizeHelpers.ts index 874487120..50086ff70 100644 --- a/src/renderers/js-experimental/fragments/accountSizeHelpers.ts +++ b/src/renderers/js-experimental/fragments/accountSizeHelpers.ts @@ -1,11 +1,10 @@ import { AccountNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getAccountSizeHelpersFragment(scope: { - accountNode: AccountNode; - nameApi: NameApi; -}): Fragment { +export function getAccountSizeHelpersFragment( + scope: Pick & { accountNode: AccountNode } +): Fragment { const { accountNode, nameApi } = scope; if (accountNode.size == null) { return fragment(''); diff --git a/src/renderers/js-experimental/fragments/accountType.ts b/src/renderers/js-experimental/fragments/accountType.ts index 26864c571..1f71e04f0 100644 --- a/src/renderers/js-experimental/fragments/accountType.ts +++ b/src/renderers/js-experimental/fragments/accountType.ts @@ -1,14 +1,15 @@ import { AccountNode } from '../../../nodes'; import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; import { getTypeWithCodecFragment } from './typeWithCodec'; -export function getAccountTypeFragment(scope: { - accountNode: AccountNode; - typeManifest: TypeManifest; - nameApi: NameApi; -}): Fragment { +export function getAccountTypeFragment( + scope: Pick & { + accountNode: AccountNode; + typeManifest: TypeManifest; + } +): Fragment { const { accountNode, typeManifest, nameApi } = scope; const typeWithCodecFragment = accountNode.data.link ? fragment('') diff --git a/src/renderers/js-experimental/fragments/index.ts b/src/renderers/js-experimental/fragments/index.ts index 03ba78f92..8ded3a16c 100644 --- a/src/renderers/js-experimental/fragments/index.ts +++ b/src/renderers/js-experimental/fragments/index.ts @@ -25,4 +25,3 @@ export * from './typeDataEnumHelpers'; export * from './typeDecoder'; export * from './typeEncoder'; export * from './typeWithCodec'; -export * from './valueNode'; diff --git a/src/renderers/js-experimental/fragments/instructionAccountTypeParam.ts b/src/renderers/js-experimental/fragments/instructionAccountTypeParam.ts index 5e3e64404..807ae580c 100644 --- a/src/renderers/js-experimental/fragments/instructionAccountTypeParam.ts +++ b/src/renderers/js-experimental/fragments/instructionAccountTypeParam.ts @@ -6,15 +6,17 @@ import { } from '../../../nodes'; import { LinkableDictionary, pascalCase } from '../../../shared'; import { ImportMap } from '../ImportMap'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment } from './common'; -export function getInstructionAccountTypeParamFragment(scope: { - instructionNode: InstructionNode; - instructionAccountNode: InstructionAccountNode; - programNode: ProgramNode; - allowAccountMeta: boolean; - linkables: LinkableDictionary; -}): Fragment { +export function getInstructionAccountTypeParamFragment( + scope: Pick & { + instructionNode: InstructionNode; + instructionAccountNode: InstructionAccountNode; + programNode: ProgramNode; + allowAccountMeta: boolean; + } +): Fragment { const { instructionNode, instructionAccountNode, @@ -40,7 +42,7 @@ export function getInstructionAccountTypeParamFragment(scope: { } const defaultAddress = getDefaultAddress( - instructionAccountNode.defaultsTo, + instructionAccountNode.defaultValue, programNode.publicKey, linkables ); @@ -52,15 +54,15 @@ export function getInstructionAccountTypeParamFragment(scope: { } function getDefaultAddress( - defaultsTo: InstructionInputValueNode | undefined, + defaultValue: InstructionInputValueNode | undefined, programId: string, linkables: LinkableDictionary ): string { - switch (defaultsTo?.kind) { + switch (defaultValue?.kind) { case 'publicKeyValueNode': - return `"${defaultsTo.publicKey}"`; + return `"${defaultValue.publicKey}"`; case 'programLinkNode': - const programNode = linkables.get(defaultsTo); + const programNode = linkables.get(defaultValue); return programNode ? `"${programNode.publicKey}"` : 'string'; case 'programIdValueNode': return `"${programId}"`; diff --git a/src/renderers/js-experimental/fragments/instructionBytesCreatedOnChain.ts b/src/renderers/js-experimental/fragments/instructionBytesCreatedOnChain.ts index b3017e7f1..e57b57788 100644 --- a/src/renderers/js-experimental/fragments/instructionBytesCreatedOnChain.ts +++ b/src/renderers/js-experimental/fragments/instructionBytesCreatedOnChain.ts @@ -1,18 +1,20 @@ import { InstructionNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import { MainCaseString } from '../../../shared'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getInstructionBytesCreatedOnChainFragment(scope: { - instructionNode: InstructionNode; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { +export function getInstructionBytesCreatedOnChainFragment( + scope: Pick & { + instructionNode: InstructionNode; + useAsync: boolean; + } +): Fragment { const bytes = scope.instructionNode.bytesCreatedOnChain; if (!bytes) return fragment(''); const isAsync = - bytes?.kind === 'resolver' && scope.asyncResolvers.includes(bytes.name); + bytes?.kind === 'resolver' && + scope.asyncResolvers.includes(bytes.name as MainCaseString); if (!scope.useAsync && isAsync) return fragment(''); const awaitKeyword = scope.useAsync && isAsync ? 'await ' : ''; diff --git a/src/renderers/js-experimental/fragments/instructionData.ts b/src/renderers/js-experimental/fragments/instructionData.ts index 39dea9728..31815c1b4 100644 --- a/src/renderers/js-experimental/fragments/instructionData.ts +++ b/src/renderers/js-experimental/fragments/instructionData.ts @@ -1,14 +1,15 @@ import { InstructionNode } from '../../../nodes'; import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment } from './common'; import { getTypeWithCodecFragment } from './typeWithCodec'; -export function getInstructionDataFragment(scope: { - instructionNode: InstructionNode; - dataArgsManifest: TypeManifest; - nameApi: NameApi; -}): Fragment { +export function getInstructionDataFragment( + scope: Pick & { + instructionNode: InstructionNode; + dataArgsManifest: TypeManifest; + } +): Fragment { const { instructionNode, dataArgsManifest, nameApi } = scope; if ( instructionNode.dataArgs.struct.fields.length === 0 || diff --git a/src/renderers/js-experimental/fragments/instructionExtraArgs.ts b/src/renderers/js-experimental/fragments/instructionExtraArgs.ts index 0549d2e28..af639ed6f 100644 --- a/src/renderers/js-experimental/fragments/instructionExtraArgs.ts +++ b/src/renderers/js-experimental/fragments/instructionExtraArgs.ts @@ -1,13 +1,14 @@ import { InstructionNode } from '../../../nodes'; import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getInstructionExtraArgsFragment(scope: { - instructionNode: InstructionNode; - extraArgsManifest: TypeManifest; - nameApi: NameApi; -}): Fragment { +export function getInstructionExtraArgsFragment( + scope: Pick & { + instructionNode: InstructionNode; + extraArgsManifest: TypeManifest; + } +): Fragment { const { instructionNode, extraArgsManifest, nameApi } = scope; if ( instructionNode.extraArgs.struct.fields.length === 0 || diff --git a/src/renderers/js-experimental/fragments/instructionFunctionHighLevel.ts b/src/renderers/js-experimental/fragments/instructionFunctionHighLevel.ts index f9f0063b5..791fff298 100644 --- a/src/renderers/js-experimental/fragments/instructionFunctionHighLevel.ts +++ b/src/renderers/js-experimental/fragments/instructionFunctionHighLevel.ts @@ -3,6 +3,7 @@ import { camelCase, pascalCase } from '../../../shared'; import { ResolvedInstructionInput } from '../../../visitors'; import { TypeManifest } from '../TypeManifest'; import { hasAsyncFunction } from '../asyncHelpers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { NameApi } from '../nameTransformers'; import { Fragment, @@ -15,17 +16,20 @@ import { getInstructionInputResolvedFragment } from './instructionInputResolved' import { getInstructionInputTypeFragment } from './instructionInputType'; import { getInstructionRemainingAccountsFragment } from './instructionRemainingAccounts'; -export function getInstructionFunctionHighLevelFragment(scope: { - instructionNode: InstructionNode; - programNode: ProgramNode; - renamedArgs: Map; - dataArgsManifest: TypeManifest; - extraArgsManifest: TypeManifest; - resolvedInputs: ResolvedInstructionInput[]; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { +export function getInstructionFunctionHighLevelFragment( + scope: Pick< + GlobalFragmentScope, + 'nameApi' | 'asyncResolvers' | 'valueNodeVisitor' + > & { + instructionNode: InstructionNode; + programNode: ProgramNode; + renamedArgs: Map; + dataArgsManifest: TypeManifest; + extraArgsManifest: TypeManifest; + resolvedInputs: ResolvedInstructionInput[]; + useAsync: boolean; + } +): Fragment { const { useAsync, instructionNode, @@ -47,12 +51,12 @@ export function getInstructionFunctionHighLevelFragment(scope: { const hasDataArgs = !!instructionNode.dataArgs.link || instructionNode.dataArgs.struct.fields.filter( - (field) => field.defaultsTo?.strategy !== 'omitted' + (field) => !field.defaultValue || field.defaultValueStrategy !== 'omitted' ).length > 0; const hasExtraArgs = !!instructionNode.extraArgs.link || instructionNode.extraArgs.struct.fields.filter( - (field) => field.defaultsTo?.strategy !== 'omitted' + (field) => !field.defaultValue || field.defaultValueStrategy !== 'omitted' ).length > 0; const hasAnyArgs = hasDataArgs || hasExtraArgs; const argsTypeFragment = fragment( diff --git a/src/renderers/js-experimental/fragments/instructionFunctionLowLevel.ts b/src/renderers/js-experimental/fragments/instructionFunctionLowLevel.ts index a36f3749f..3a721babc 100644 --- a/src/renderers/js-experimental/fragments/instructionFunctionLowLevel.ts +++ b/src/renderers/js-experimental/fragments/instructionFunctionLowLevel.ts @@ -4,9 +4,10 @@ import { ProgramNode, isNode, } from '../../../nodes'; -import { LinkableDictionary, pascalCase } from '../../../shared'; +import { pascalCase } from '../../../shared'; import { ImportMap } from '../ImportMap'; import { TypeManifest } from '../TypeManifest'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { NameApi } from '../nameTransformers'; import { Fragment, @@ -16,13 +17,13 @@ import { } from './common'; import { getInstructionAccountTypeParamFragment } from './instructionAccountTypeParam'; -export function getInstructionFunctionLowLevelFragment(scope: { - instructionNode: InstructionNode; - programNode: ProgramNode; - dataArgsManifest: TypeManifest; - nameApi: NameApi; - linkables: LinkableDictionary; -}): Fragment { +export function getInstructionFunctionLowLevelFragment( + scope: Pick & { + instructionNode: InstructionNode; + programNode: ProgramNode; + dataArgsManifest: TypeManifest; + } +): Fragment { const { instructionNode, programNode, dataArgsManifest, nameApi } = scope; const imports = new ImportMap(); const hasAccounts = instructionNode.accounts.length > 0; @@ -35,7 +36,7 @@ export function getInstructionFunctionLowLevelFragment(scope: { const hasArgs = !!instructionNode.dataArgs.link || instructionNode.dataArgs.struct.fields.filter( - (field) => field.defaultsTo?.strategy !== 'omitted' + (field) => !field.defaultValue || field.defaultValueStrategy !== 'omitted' ).length > 0; const argsType = instructionNode.dataArgs.link ? dataArgsManifest.looseType.render @@ -123,20 +124,20 @@ function getDefaultValue( if (account.isOptional && usesLegacyOptionalAccounts) { return fragment(''); } - const defaultsTo = account.defaultsTo ?? null; - if (account.isOptional || isNode(defaultsTo, 'programIdValueNode')) { + const defaultValue = account.defaultValue ?? null; + if (account.isOptional || isNode(defaultValue, 'programIdValueNode')) { return fragment( `{ address: "${program.publicKey}" as Address<"${program.publicKey}">, role: AccountRole.READONLY }` ); } - if (isNode(defaultsTo, 'publicKeyValueNode')) { + if (isNode(defaultValue, 'publicKeyValueNode')) { return fragment( - `"${defaultsTo.publicKey}" as Address<"${defaultsTo.publicKey}">` + `"${defaultValue.publicKey}" as Address<"${defaultValue.publicKey}">` ); } - if (isNode(defaultsTo, 'programLinkNode')) { - const programAddress = nameApi.programAddressConstant(defaultsTo.name); - const importFrom = defaultsTo.importFrom ?? 'generatedPrograms'; + if (isNode(defaultValue, 'programLinkNode')) { + const programAddress = nameApi.programAddressConstant(defaultValue.name); + const importFrom = defaultValue.importFrom ?? 'generatedPrograms'; return fragment( `{ address: ${programAddress}, role: AccountRole.READONLY }` ).addImports(importFrom, programAddress); diff --git a/src/renderers/js-experimental/fragments/instructionInputDefault.ts b/src/renderers/js-experimental/fragments/instructionInputDefault.ts index c9fa18ee8..fd4796e3e 100644 --- a/src/renderers/js-experimental/fragments/instructionInputDefault.ts +++ b/src/renderers/js-experimental/fragments/instructionInputDefault.ts @@ -1,57 +1,65 @@ import { InstructionInputValueNode, isNode } from '../../../nodes'; -import { MainCaseString, camelCase } from '../../../shared'; -import { ResolvedInstructionInput } from '../../../visitors'; +import { camelCase } from '../../../shared'; +import { ResolvedInstructionInput, visit } from '../../../visitors'; import { isAsyncDefaultValue } from '../asyncHelpers'; -import { NameApi } from '../nameTransformers'; +import { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, mergeFragments } from './common'; -import { getValueNodeFragment } from './valueNode'; - -export function getInstructionInputDefaultFragment(scope: { - input: ResolvedInstructionInput; - optionalAccountStrategy: 'programId' | 'omitted'; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { - const { input, optionalAccountStrategy, asyncResolvers, useAsync, nameApi } = - scope; - if (!input.defaultsTo) { + +export function getInstructionInputDefaultFragment( + scope: Pick< + GlobalFragmentScope, + 'nameApi' | 'asyncResolvers' | 'valueNodeVisitor' + > & { + input: ResolvedInstructionInput; + optionalAccountStrategy: 'programId' | 'omitted'; + useAsync: boolean; + } +): Fragment { + const { + input, + optionalAccountStrategy, + asyncResolvers, + useAsync, + nameApi, + valueNodeVisitor, + } = scope; + if (!input.defaultValue) { return fragment(''); } - if (!useAsync && isAsyncDefaultValue(input.defaultsTo, asyncResolvers)) { + if (!useAsync && isAsyncDefaultValue(input.defaultValue, asyncResolvers)) { return fragment(''); } - const { defaultsTo } = input; + const { defaultValue } = input; const defaultFragment = ( - defaultValue: string, + renderedValue: string, isWritable?: boolean ): Fragment => { const inputName = camelCase(input.name); if ( input.kind === 'instructionAccountNode' && - isNode(defaultsTo, 'resolverValueNode') + isNode(defaultValue, 'resolverValueNode') ) { return fragment( - `accounts.${inputName} = { ...accounts.${inputName}, ...${defaultValue} };` + `accounts.${inputName} = { ...accounts.${inputName}, ...${renderedValue} };` ); } if (input.kind === 'instructionAccountNode' && isWritable === undefined) { - return fragment(`accounts.${inputName}.value = ${defaultValue};`); + return fragment(`accounts.${inputName}.value = ${renderedValue};`); } if (input.kind === 'instructionAccountNode') { return fragment( - `accounts.${inputName}.value = ${defaultValue};\n` + + `accounts.${inputName}.value = ${renderedValue};\n` + `accounts.${inputName}.isWritable = ${isWritable ? 'true' : 'false'}` ); } - return fragment(`args.${inputName} = ${defaultValue};`); + return fragment(`args.${inputName} = ${renderedValue};`); }; - switch (defaultsTo.kind) { + switch (defaultValue.kind) { case 'accountValueNode': - const name = camelCase(defaultsTo.name); + const name = camelCase(defaultValue.name); if ( input.kind === 'instructionAccountNode' && input.resolvedIsSigner && @@ -72,29 +80,26 @@ export function getInstructionInputDefaultFragment(scope: { ).addImports('shared', 'expectAddress'); case 'pdaValueNode': - const pdaFunction = nameApi.pdaFindFunction(defaultsTo.pda.name); - const pdaImportFrom = defaultsTo.pda.importFrom ?? 'generatedPdas'; + const pdaFunction = nameApi.pdaFindFunction(defaultValue.pda.name); + const pdaImportFrom = defaultValue.pda.importFrom ?? 'generatedPdas'; const pdaArgs = []; - const pdaSeeds = Object.keys(defaultsTo.seeds).map( - (seed: string): Fragment => { - const seedValue = defaultsTo.seeds[seed as MainCaseString]; - if (isNode(seedValue, 'accountValueNode')) { - return fragment( - `${seed}: expectAddress(accounts.${camelCase( - seedValue.name - )}.value)` - ).addImports('shared', 'expectAddress'); - } - if (isNode(seedValue, 'argumentValueNode')) { - return fragment( - `${seed}: expectSome(args.${camelCase(seedValue.name)})` - ).addImports('shared', 'expectSome'); - } - return getValueNodeFragment(seedValue, nameApi).mapRender( - (r) => `${seed}: ${r}` - ); + const pdaSeeds = defaultValue.seeds.map((seed): Fragment => { + if (isNode(seed.value, 'accountValueNode')) { + return fragment( + `${seed.name}: expectAddress(accounts.${camelCase( + seed.value.name + )}.value)` + ).addImports('shared', 'expectAddress'); } - ); + if (isNode(seed.value, 'argumentValueNode')) { + return fragment( + `${seed.name}: expectSome(args.${camelCase(seed.value.name)})` + ).addImports('shared', 'expectSome'); + } + return visit(seed.value, valueNodeVisitor).mapRender( + (r) => `${seed.name}: ${r}` + ); + }); const pdaSeedsFragment = mergeFragments(pdaSeeds, (renders) => renders.join(', ') ).mapRender((r) => `{ ${r} }`); @@ -107,12 +112,12 @@ export function getInstructionInputDefaultFragment(scope: { case 'publicKeyValueNode': return defaultFragment( - `'${defaultsTo.publicKey}' as Address<'${defaultsTo.publicKey}'>` + `'${defaultValue.publicKey}' as Address<'${defaultValue.publicKey}'>` ).addImports('solanaAddresses', 'Address'); case 'programLinkNode': - const programAddress = nameApi.programAddressConstant(defaultsTo.name); - const importFrom = defaultsTo.importFrom ?? 'generatedPrograms'; + const programAddress = nameApi.programAddressConstant(defaultValue.name); + const importFrom = defaultValue.importFrom ?? 'generatedPrograms'; return defaultFragment(programAddress, false).addImports( importFrom, programAddress @@ -135,33 +140,33 @@ export function getInstructionInputDefaultFragment(scope: { case 'accountBumpValueNode': return defaultFragment( `expectProgramDerivedAddress(accounts.${camelCase( - defaultsTo.name + defaultValue.name )}.value)[1]` ).addImports('shared', 'expectProgramDerivedAddress'); case 'argumentValueNode': return defaultFragment( - `expectSome(args.${camelCase(defaultsTo.name)})` + `expectSome(args.${camelCase(defaultValue.name)})` ).addImports('shared', 'expectSome'); case 'resolverValueNode': - const resolverFunction = nameApi.resolverFunction(defaultsTo.name); + const resolverFunction = nameApi.resolverFunction(defaultValue.name); const resolverAwait = - useAsync && asyncResolvers.includes(defaultsTo.name) ? 'await ' : ''; + useAsync && asyncResolvers.includes(defaultValue.name) ? 'await ' : ''; return defaultFragment( `${resolverAwait}${resolverFunction}(resolverScope)` ) - .addImports(defaultsTo.importFrom ?? 'hooked', resolverFunction) + .addImports(defaultValue.importFrom ?? 'hooked', resolverFunction) .addFeatures(['instruction:resolverScopeVariable']); case 'conditionalValueNode': const ifTrueRenderer = renderNestedInstructionDefault({ ...scope, - defaultsTo: defaultsTo.ifTrue, + defaultValue: defaultValue.ifTrue, }); const ifFalseRenderer = renderNestedInstructionDefault({ ...scope, - defaultsTo: defaultsTo.ifFalse, + defaultValue: defaultValue.ifFalse, }); if (!ifTrueRenderer && !ifFalseRenderer) { return fragment(''); @@ -180,31 +185,31 @@ export function getInstructionInputDefaultFragment(scope: { const negatedCondition = !ifTrueRenderer; let condition = 'true'; - if (isNode(defaultsTo.condition, 'resolverValueNode')) { + if (isNode(defaultValue.condition, 'resolverValueNode')) { const conditionalResolverFunction = nameApi.resolverFunction( - defaultsTo.condition.name + defaultValue.condition.name ); conditionalFragment .addImports( - defaultsTo.condition.importFrom ?? 'hooked', + defaultValue.condition.importFrom ?? 'hooked', conditionalResolverFunction ) .addFeatures(['instruction:resolverScopeVariable']); const conditionalResolverAwait = - useAsync && asyncResolvers.includes(defaultsTo.condition.name) + useAsync && asyncResolvers.includes(defaultValue.condition.name) ? 'await ' : ''; condition = `${conditionalResolverAwait}${conditionalResolverFunction}(resolverScope)`; condition = negatedCondition ? `!${condition}` : condition; } else { const comparedInputName = isNode( - defaultsTo.condition, + defaultValue.condition, 'accountValueNode' ) - ? `accounts.${camelCase(defaultsTo.condition.name)}.value` - : `args.${camelCase(defaultsTo.condition.name)}`; - if (defaultsTo.value) { - const comparedValue = getValueNodeFragment(defaultsTo.value, nameApi); + ? `accounts.${camelCase(defaultValue.condition.name)}.value` + : `args.${camelCase(defaultValue.condition.name)}`; + if (defaultValue.value) { + const comparedValue = visit(defaultValue.value, valueNodeVisitor); conditionalFragment .mergeImportsWith(comparedValue) .mergeFeaturesWith(comparedValue); @@ -230,7 +235,7 @@ export function getInstructionInputDefaultFragment(scope: { ); default: - const valueManifest = getValueNodeFragment(defaultsTo, nameApi); + const valueManifest = visit(defaultValue, valueNodeVisitor); return defaultFragment(valueManifest.render).mergeImportsWith( valueManifest ); @@ -239,13 +244,13 @@ export function getInstructionInputDefaultFragment(scope: { function renderNestedInstructionDefault( scope: Parameters[0] & { - defaultsTo: InstructionInputValueNode | undefined; + defaultValue: InstructionInputValueNode | undefined; } ): Fragment | undefined { - const { input, defaultsTo } = scope; - if (!defaultsTo) return undefined; + const { input, defaultValue } = scope; + if (!defaultValue) return undefined; return getInstructionInputDefaultFragment({ ...scope, - input: { ...input, defaultsTo }, + input: { ...input, defaultValue }, }); } diff --git a/src/renderers/js-experimental/fragments/instructionInputResolved.ts b/src/renderers/js-experimental/fragments/instructionInputResolved.ts index 8ed1359db..3d0256a2d 100644 --- a/src/renderers/js-experimental/fragments/instructionInputResolved.ts +++ b/src/renderers/js-experimental/fragments/instructionInputResolved.ts @@ -1,17 +1,20 @@ import { InstructionNode } from '../../../nodes'; import { camelCase } from '../../../shared'; import { ResolvedInstructionInput } from '../../../visitors'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, mergeFragments } from './common'; import { getInstructionInputDefaultFragment } from './instructionInputDefault'; -export function getInstructionInputResolvedFragment(scope: { - instructionNode: InstructionNode; - resolvedInputs: ResolvedInstructionInput[]; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { +export function getInstructionInputResolvedFragment( + scope: Pick< + GlobalFragmentScope, + 'nameApi' | 'asyncResolvers' | 'valueNodeVisitor' + > & { + instructionNode: InstructionNode; + resolvedInputs: ResolvedInstructionInput[]; + useAsync: boolean; + } +): Fragment { const resolvedInputFragments = scope.resolvedInputs.flatMap( (input: ResolvedInstructionInput): Fragment[] => { const inputFragment = getInstructionInputDefaultFragment({ diff --git a/src/renderers/js-experimental/fragments/instructionInputType.ts b/src/renderers/js-experimental/fragments/instructionInputType.ts index b013f4c84..fcc7c88fa 100644 --- a/src/renderers/js-experimental/fragments/instructionInputType.ts +++ b/src/renderers/js-experimental/fragments/instructionInputType.ts @@ -13,21 +13,21 @@ import { import { ImportMap } from '../ImportMap'; import { TypeManifest } from '../TypeManifest'; import { isAsyncDefaultValue } from '../asyncHelpers'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getInstructionInputTypeFragment(scope: { - instructionNode: InstructionNode; - resolvedInputs: ResolvedInstructionInput[]; - renamedArgs: Map; - dataArgsManifest: TypeManifest; - extraArgsManifest: TypeManifest; - programNode: ProgramNode; - withSigners: boolean; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { +export function getInstructionInputTypeFragment( + scope: Pick & { + instructionNode: InstructionNode; + resolvedInputs: ResolvedInstructionInput[]; + renamedArgs: Map; + dataArgsManifest: TypeManifest; + extraArgsManifest: TypeManifest; + programNode: ProgramNode; + withSigners: boolean; + useAsync: boolean; + } +): Fragment { const { instructionNode, resolvedInputs, @@ -50,13 +50,13 @@ export function getInstructionInputTypeFragment(scope: { input.kind === 'instructionAccountNode' && input.name === account.name ) as ResolvedInstructionAccount; const hasDefaultValue = - !!resolvedAccount.defaultsTo && - !isNode(resolvedAccount.defaultsTo, [ + !!resolvedAccount.defaultValue && + !isNode(resolvedAccount.defaultValue, [ 'identityValueNode', 'payerValueNode', ]) && (useAsync || - !isAsyncDefaultValue(resolvedAccount.defaultsTo, asyncResolvers)); + !isAsyncDefaultValue(resolvedAccount.defaultValue, asyncResolvers)); const type = getAccountType(resolvedAccount, withSigners); accountImports.mergeWith(type); return { @@ -81,9 +81,9 @@ export function getInstructionInputTypeFragment(scope: { const resolvedArg = resolvedInputs.find( (input) => input.kind === 'argument' && input.name === arg.name ) as ResolvedInstructionArgument | undefined; - if (arg.defaultsTo?.strategy === 'omitted') return []; + if (arg.defaultValue && arg.defaultValueStrategy === 'omitted') return []; const renamedName = renamedArgs.get(arg.name) ?? arg.name; - const optionalSign = arg.defaultsTo || resolvedArg ? '?' : ''; + const optionalSign = arg.defaultValue || resolvedArg ? '?' : ''; return [ { ...arg, diff --git a/src/renderers/js-experimental/fragments/instructionParseFunction.ts b/src/renderers/js-experimental/fragments/instructionParseFunction.ts index 80bb3b59e..192ea1fae 100644 --- a/src/renderers/js-experimental/fragments/instructionParseFunction.ts +++ b/src/renderers/js-experimental/fragments/instructionParseFunction.ts @@ -1,14 +1,15 @@ import { InstructionNode, ProgramNode } from '../../../nodes'; import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getInstructionParseFunctionFragment(scope: { - instructionNode: InstructionNode; - programNode: ProgramNode; - dataArgsManifest: TypeManifest; - nameApi: NameApi; -}): Fragment { +export function getInstructionParseFunctionFragment( + scope: Pick & { + instructionNode: InstructionNode; + programNode: ProgramNode; + dataArgsManifest: TypeManifest; + } +): Fragment { const { instructionNode, programNode, dataArgsManifest, nameApi } = scope; const hasAccounts = instructionNode.accounts.length > 0; const hasOptionalAccounts = instructionNode.accounts.some( diff --git a/src/renderers/js-experimental/fragments/instructionRemainingAccounts.ts b/src/renderers/js-experimental/fragments/instructionRemainingAccounts.ts index d25bec39d..141bfb203 100644 --- a/src/renderers/js-experimental/fragments/instructionRemainingAccounts.ts +++ b/src/renderers/js-experimental/fragments/instructionRemainingAccounts.ts @@ -1,13 +1,13 @@ import { InstructionNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getInstructionRemainingAccountsFragment(scope: { - instructionNode: InstructionNode; - asyncResolvers: string[]; - useAsync: boolean; - nameApi: NameApi; -}): Fragment { +export function getInstructionRemainingAccountsFragment( + scope: Pick & { + instructionNode: InstructionNode; + useAsync: boolean; + } +): Fragment { const { remainingAccounts } = scope.instructionNode; if (!remainingAccounts) return fragment(''); diff --git a/src/renderers/js-experimental/fragments/instructionType.ts b/src/renderers/js-experimental/fragments/instructionType.ts index eea1af796..d253b32b5 100644 --- a/src/renderers/js-experimental/fragments/instructionType.ts +++ b/src/renderers/js-experimental/fragments/instructionType.ts @@ -1,17 +1,17 @@ import { InstructionNode, ProgramNode } from '../../../nodes'; -import { LinkableDictionary, pascalCase } from '../../../shared'; -import { NameApi } from '../nameTransformers'; +import { pascalCase } from '../../../shared'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate, mergeFragments } from './common'; import { getInstructionAccountMetaFragment } from './instructionAccountMeta'; import { getInstructionAccountTypeParamFragment } from './instructionAccountTypeParam'; -export function getInstructionTypeFragment(scope: { - instructionNode: InstructionNode; - programNode: ProgramNode; - withSigners: boolean; - nameApi: NameApi; - linkables: LinkableDictionary; -}): Fragment { +export function getInstructionTypeFragment( + scope: Pick & { + instructionNode: InstructionNode; + programNode: ProgramNode; + withSigners: boolean; + } +): Fragment { const { instructionNode, programNode, withSigners, nameApi } = scope; const hasAccounts = instructionNode.accounts.length > 0; const hasData = diff --git a/src/renderers/js-experimental/fragments/pdaFunction.ts b/src/renderers/js-experimental/fragments/pdaFunction.ts index ae62409f6..6564421b1 100644 --- a/src/renderers/js-experimental/fragments/pdaFunction.ts +++ b/src/renderers/js-experimental/fragments/pdaFunction.ts @@ -1,27 +1,25 @@ -import { - PdaNode, - ProgramNode, - RegisteredTypeNodes, - isNode, - isNodeFilter, -} from '../../../nodes'; -import { Visitor, visit } from '../../../visitors'; +import { PdaNode, ProgramNode, isNode, isNodeFilter } from '../../../nodes'; +import { visit } from '../../../visitors'; import { ImportMap } from '../ImportMap'; -import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -import { getValueNodeFragment } from './valueNode'; -export function getPdaFunctionFragment(scope: { - pdaNode: PdaNode; - programNode: ProgramNode; - typeManifestVisitor: Visitor< - TypeManifest, - keyof RegisteredTypeNodes | 'definedTypeLinkNode' - >; - nameApi: NameApi; -}): Fragment { - const { pdaNode, programNode, typeManifestVisitor, nameApi } = scope; +export function getPdaFunctionFragment( + scope: Pick< + GlobalFragmentScope, + 'nameApi' | 'typeManifestVisitor' | 'valueNodeVisitor' + > & { + pdaNode: PdaNode; + programNode: ProgramNode; + } +): Fragment { + const { + pdaNode, + programNode, + typeManifestVisitor, + valueNodeVisitor, + nameApi, + } = scope; if (pdaNode.seeds.length === 0) { return fragment(''); } @@ -33,7 +31,7 @@ export function getPdaFunctionFragment(scope: { const seedManifest = visit(seed.type, typeManifestVisitor); imports.mergeWith(seedManifest.encoder); const seedValue = seed.value; - const valueManifest = getValueNodeFragment(seedValue, nameApi); + const valueManifest = visit(seedValue, valueNodeVisitor); (seedValue as any).render = valueManifest.render; imports.mergeWith(valueManifest.imports); return { ...seed, typeManifest: seedManifest }; diff --git a/src/renderers/js-experimental/fragments/program.ts b/src/renderers/js-experimental/fragments/program.ts index 2728643e4..9d8186904 100644 --- a/src/renderers/js-experimental/fragments/program.ts +++ b/src/renderers/js-experimental/fragments/program.ts @@ -1,11 +1,12 @@ import { ProgramNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate } from './common'; -export function getProgramFragment(scope: { - programNode: ProgramNode; - nameApi: NameApi; -}): Fragment { +export function getProgramFragment( + scope: Pick & { + programNode: ProgramNode; + } +): Fragment { const { programNode, nameApi } = scope; const programErrorClass = nameApi.programErrorClass(programNode.name); const programErrorCode = nameApi.programErrorCodeEnum(programNode.name); diff --git a/src/renderers/js-experimental/fragments/programErrors.ts b/src/renderers/js-experimental/fragments/programErrors.ts index 872360cf3..34a10fc30 100644 --- a/src/renderers/js-experimental/fragments/programErrors.ts +++ b/src/renderers/js-experimental/fragments/programErrors.ts @@ -1,11 +1,12 @@ import { ProgramNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate } from './common'; -export function getProgramErrorsFragment(scope: { - programNode: ProgramNode; - nameApi: NameApi; -}): Fragment { +export function getProgramErrorsFragment( + scope: Pick & { + programNode: ProgramNode; + } +): Fragment { const { programNode, nameApi } = scope; return fragmentFromTemplate('programErrors.njk', { errors: programNode.errors, diff --git a/src/renderers/js-experimental/fragments/type.ts b/src/renderers/js-experimental/fragments/type.ts index e8f319759..1cc7ad07a 100644 --- a/src/renderers/js-experimental/fragments/type.ts +++ b/src/renderers/js-experimental/fragments/type.ts @@ -1,13 +1,14 @@ import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate } from './common'; -export function getTypeFragment(scope: { - name: string; - manifest: TypeManifest; - nameApi: NameApi; - docs?: string[]; -}): Fragment { +export function getTypeFragment( + scope: Pick & { + name: string; + manifest: TypeManifest; + docs?: string[]; + } +): Fragment { const { name, manifest, nameApi, docs = [] } = scope; const typeFragment = fragmentFromTemplate('type.njk', { strictName: nameApi.dataType(name), diff --git a/src/renderers/js-experimental/fragments/typeCodec.ts b/src/renderers/js-experimental/fragments/typeCodec.ts index 2ef7e8a68..09953553e 100644 --- a/src/renderers/js-experimental/fragments/typeCodec.ts +++ b/src/renderers/js-experimental/fragments/typeCodec.ts @@ -1,17 +1,18 @@ import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate, mergeFragments } from './common'; import { getTypeDecoderFragment } from './typeDecoder'; import { getTypeEncoderFragment } from './typeEncoder'; -export function getTypeCodecFragment(scope: { - name: string; - manifest: Pick; - nameApi: NameApi; - codecDocs?: string[]; - encoderDocs?: string[]; - decoderDocs?: string[]; -}): Fragment { +export function getTypeCodecFragment( + scope: Pick & { + name: string; + manifest: Pick; + codecDocs?: string[]; + encoderDocs?: string[]; + decoderDocs?: string[]; + } +): Fragment { const { name, manifest, nameApi } = scope; return mergeFragments( [ diff --git a/src/renderers/js-experimental/fragments/typeDataEnumHelpers.ts b/src/renderers/js-experimental/fragments/typeDataEnumHelpers.ts index c911b9b06..9981b9101 100644 --- a/src/renderers/js-experimental/fragments/typeDataEnumHelpers.ts +++ b/src/renderers/js-experimental/fragments/typeDataEnumHelpers.ts @@ -1,12 +1,13 @@ import { TypeNode, isDataEnum, isNode } from '../../../nodes'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragment, fragmentFromTemplate } from './common'; -export function getTypeDataEnumHelpersFragment(scope: { - name: string; - typeNode: TypeNode; - nameApi: NameApi; -}): Fragment { +export function getTypeDataEnumHelpersFragment( + scope: Pick & { + name: string; + typeNode: TypeNode; + } +): Fragment { const { name, typeNode, nameApi } = scope; const isDataEnumNode = isNode(typeNode, 'enumTypeNode') && isDataEnum(typeNode); diff --git a/src/renderers/js-experimental/fragments/typeDecoder.ts b/src/renderers/js-experimental/fragments/typeDecoder.ts index 7d1abcc69..1b9b55e2f 100644 --- a/src/renderers/js-experimental/fragments/typeDecoder.ts +++ b/src/renderers/js-experimental/fragments/typeDecoder.ts @@ -1,13 +1,14 @@ import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate } from './common'; -export function getTypeDecoderFragment(scope: { - name: string; - manifest: Pick; - nameApi: NameApi; - docs?: string[]; -}): Fragment { +export function getTypeDecoderFragment( + scope: Pick & { + name: string; + manifest: Pick; + docs?: string[]; + } +): Fragment { const { name, manifest, nameApi, docs = [] } = scope; return fragmentFromTemplate('typeDecoder.njk', { strictName: nameApi.dataType(name), diff --git a/src/renderers/js-experimental/fragments/typeEncoder.ts b/src/renderers/js-experimental/fragments/typeEncoder.ts index c3f576df7..5e97151c5 100644 --- a/src/renderers/js-experimental/fragments/typeEncoder.ts +++ b/src/renderers/js-experimental/fragments/typeEncoder.ts @@ -1,13 +1,14 @@ import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, fragmentFromTemplate } from './common'; -export function getTypeEncoderFragment(scope: { - name: string; - manifest: Pick; - nameApi: NameApi; - docs?: string[]; -}): Fragment { +export function getTypeEncoderFragment( + scope: Pick & { + name: string; + manifest: Pick; + docs?: string[]; + } +): Fragment { const { name, manifest, nameApi, docs = [] } = scope; return fragmentFromTemplate('typeEncoder.njk', { strictName: nameApi.dataType(name), diff --git a/src/renderers/js-experimental/fragments/typeWithCodec.ts b/src/renderers/js-experimental/fragments/typeWithCodec.ts index 976efcbef..1e0958617 100644 --- a/src/renderers/js-experimental/fragments/typeWithCodec.ts +++ b/src/renderers/js-experimental/fragments/typeWithCodec.ts @@ -1,18 +1,19 @@ import { TypeManifest } from '../TypeManifest'; -import { NameApi } from '../nameTransformers'; +import type { GlobalFragmentScope } from '../getRenderMapVisitor'; import { Fragment, mergeFragments } from './common'; import { getTypeFragment } from './type'; import { getTypeCodecFragment } from './typeCodec'; -export function getTypeWithCodecFragment(scope: { - name: string; - manifest: TypeManifest; - nameApi: NameApi; - typeDocs?: string[]; - codecDocs?: string[]; - encoderDocs?: string[]; - decoderDocs?: string[]; -}): Fragment { +export function getTypeWithCodecFragment( + scope: Pick & { + name: string; + manifest: TypeManifest; + typeDocs?: string[]; + codecDocs?: string[]; + encoderDocs?: string[]; + decoderDocs?: string[]; + } +): Fragment { return mergeFragments( [ getTypeFragment({ ...scope, docs: scope.typeDocs }), diff --git a/src/renderers/js-experimental/fragments/valueNode.ts b/src/renderers/js-experimental/fragments/valueNode.ts deleted file mode 100644 index 02c22e878..000000000 --- a/src/renderers/js-experimental/fragments/valueNode.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ValueNode } from '../../../nodes'; -import { visit } from '../../../visitors'; -import { NameApi } from '../nameTransformers'; -import { renderValueNodeVisitor } from '../renderValueNodeVisitor'; -import { Fragment } from './common'; - -export function getValueNodeFragment( - value: ValueNode, - nameApi: NameApi -): Fragment { - return visit(value, renderValueNodeVisitor(nameApi)); -} diff --git a/src/renderers/js-experimental/getRenderMapVisitor.ts b/src/renderers/js-experimental/getRenderMapVisitor.ts index c10431eaa..9c50e2d93 100644 --- a/src/renderers/js-experimental/getRenderMapVisitor.ts +++ b/src/renderers/js-experimental/getRenderMapVisitor.ts @@ -17,6 +17,7 @@ import { LinkableDictionary, logWarn, mainCase, + MainCaseString, pipe, RenderMap, resolveTemplate, @@ -45,13 +46,21 @@ import { getTypeDataEnumHelpersFragment, getTypeWithCodecFragment, } from './fragments'; -import { getTypeManifestVisitor } from './getTypeManifestVisitor'; +import { + getTypeManifestVisitor, + TypeManifestVisitor, +} from './getTypeManifestVisitor'; import { ImportMap } from './ImportMap'; import { DEFAULT_NAME_TRANSFORMERS, getNameApi, + NameApi, NameTransformers, } from './nameTransformers'; +import { + renderValueNodeVisitor, + ValueNodeVisitor, +} from './renderValueNodeVisitor'; const DEFAULT_PRETTIER_OPTIONS: PrettierOptions = { semi: true, @@ -71,6 +80,17 @@ export type GetRenderMapOptions = { dependencyMap?: Record; asyncResolvers?: string[]; nameTransformers?: Partial; + nonScalarEnums?: string[]; +}; + +export type GlobalFragmentScope = { + nameApi: NameApi; + linkables: LinkableDictionary; + typeManifestVisitor: TypeManifestVisitor; + valueNodeVisitor: ValueNodeVisitor; + asyncResolvers: MainCaseString[]; + nonScalarEnums: MainCaseString[]; + renderParentInstructions: boolean; }; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { @@ -89,11 +109,30 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { ...options.prettierOptions, }; const dependencyMap = options.dependencyMap ?? {}; - const asyncResolvers = options.asyncResolvers ?? []; - - const typeManifestVisitor = getTypeManifestVisitor(nameApi); + const asyncResolvers = (options.asyncResolvers ?? []).map(mainCase); + const nonScalarEnums = (options.nonScalarEnums ?? []).map(mainCase); + + const valueNodeVisitor = renderValueNodeVisitor({ + nameApi, + linkables, + nonScalarEnums, + }); + const typeManifestVisitor = getTypeManifestVisitor({ + nameApi, + valueNodeVisitor, + }); const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor(); + const globalScope: GlobalFragmentScope = { + nameApi, + linkables, + typeManifestVisitor, + valueNodeVisitor, + asyncResolvers, + nonScalarEnums, + renderParentInstructions, + }; + const render = ( template: string, context?: object, @@ -247,13 +286,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { throw new Error('Account must be visited inside a program.'); } - const scope = { - pdaNode: node, - programNode: program, - typeManifestVisitor, - nameApi, - }; - + const scope = { ...globalScope, pdaNode: node, programNode: program }; const pdaFunctionFragment = getPdaFunctionFragment(scope); const imports = new ImportMap().mergeWith(pdaFunctionFragment); @@ -272,11 +305,10 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { } const scope = { + ...globalScope, accountNode: node, programNode: program, typeManifest: visit(node, typeManifestVisitor), - nameApi, - linkables, }; const accountTypeFragment = getAccountTypeFragment(scope); @@ -310,15 +342,13 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { } const scope = { + ...globalScope, instructionNode: node, programNode: program, renamedArgs: getRenamedArgsMap(node), dataArgsManifest: visit(node.dataArgs, typeManifestVisitor), extraArgsManifest: visit(node.extraArgs, typeManifestVisitor), resolvedInputs: visit(node, resolvedInstructionInputVisitor), - asyncResolvers, - nameApi, - linkables, }; // Fragments. @@ -381,14 +411,14 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { visitDefinedType(node) { const scope = { - typeNode: node.data, + ...globalScope, + typeNode: node.type, name: node.name, manifest: visit(node, typeManifestVisitor), typeDocs: node.docs, encoderDocs: [], decoderDocs: [], codecDocs: [], - nameApi, }; const typeWithCodecFragment = getTypeWithCodecFragment(scope); diff --git a/src/renderers/js-experimental/getTypeManifestVisitor.ts b/src/renderers/js-experimental/getTypeManifestVisitor.ts index f573d7088..184ad6e5f 100644 --- a/src/renderers/js-experimental/getTypeManifestVisitor.ts +++ b/src/renderers/js-experimental/getTypeManifestVisitor.ts @@ -1,5 +1,5 @@ import { - REGISTERED_TYPE_NODE_KEYS, + REGISTERED_TYPE_NODE_KINDS, SizeNode, isNode, isScalarEnum, @@ -10,10 +10,17 @@ import { camelCase, pascalCase, pipe } from '../../shared'; import { Visitor, extendVisitor, staticVisitor, visit } from '../../visitors'; import { ImportMap } from './ImportMap'; import { TypeManifest, mergeManifests } from './TypeManifest'; -import { Fragment, fragment, getValueNodeFragment } from './fragments'; +import { Fragment, fragment } from './fragments'; import { NameApi } from './nameTransformers'; +import { ValueNodeVisitor } from './renderValueNodeVisitor'; -export function getTypeManifestVisitor(nameApi: NameApi) { +export type TypeManifestVisitor = ReturnType; + +export function getTypeManifestVisitor(input: { + nameApi: NameApi; + valueNodeVisitor: ValueNodeVisitor; +}) { + const { nameApi, valueNodeVisitor } = input; let parentName: { strict: string; loose: string } | null = null; return pipe( @@ -27,7 +34,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { decoder: fragment(''), } as TypeManifest), [ - ...REGISTERED_TYPE_NODE_KEYS, + ...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode', @@ -83,13 +90,13 @@ export function getTypeManifestVisitor(nameApi: NameApi) { strict: nameApi.dataType(definedType.name), loose: nameApi.dataArgsType(definedType.name), }; - const manifest = visit(definedType.data, self); + const manifest = visit(definedType.type, self); parentName = null; return manifest; }, visitArrayType(arrayType, { self }) { - const childManifest = visit(arrayType.child, self); + const childManifest = visit(arrayType.item, self); childManifest.looseType.mapRender((r) => `Array<${r}>`); childManifest.strictType.mapRender((r) => `Array<${r}>`); const sizeManifest = getArrayLikeSizeOption(arrayType.size, self); @@ -276,7 +283,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { const struct = structTypeNode([ structFieldTypeNode({ name: 'fields', - child: enumTupleVariantType.tuple, + type: enumTupleVariantType.tuple, }), ]); const structManifest = visit(struct, self); @@ -316,7 +323,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { }, visitOptionType(optionType, { self }) { - const childManifest = visit(optionType.child, self); + const childManifest = visit(optionType.item, self); childManifest.strictType .mapRender((r) => `Option<${r}>`) .addImports('solanaOptions', 'Option'); @@ -362,7 +369,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { }, visitSetType(setType, { self }) { - const childManifest = visit(setType.child, self); + const childManifest = visit(setType.item, self); childManifest.strictType.mapRender((r) => `Set<${r}>`); childManifest.looseType.mapRender((r) => `Set<${r}>`); @@ -389,7 +396,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { const currentParentName = parentName; parentName = null; const optionalFields = structType.fields.filter( - (f) => f.defaultsTo !== null + (f) => !!f.defaultValue ); const mergedManifest = mergeManifests( @@ -408,7 +415,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { if (!encoderType || optionalFields.length > 0) { const nonDefaultsMergedManifest = mergeManifests( structType.fields.map((field) => - visit({ ...field, defaultsTo: null }, self) + visit({ ...field, defaultValue: undefined }, self) ), (renders) => `{ ${renders.join('')} }`, (renders) => `([${renders.join(', ')}])` @@ -433,15 +440,15 @@ export function getTypeManifestVisitor(nameApi: NameApi) { const defaultValues = optionalFields .map((f) => { const key = camelCase(f.name); - const defaultsTo = f.defaultsTo as NonNullable< - typeof f.defaultsTo + const defaultValue = f.defaultValue as NonNullable< + typeof f.defaultValue >; - const { render: renderedValue, imports } = getValueNodeFragment( - defaultsTo.value, - nameApi + const { render: renderedValue, imports } = visit( + defaultValue, + valueNodeVisitor ); mergedManifest.encoder.mergeImportsWith(imports); - return defaultsTo.strategy === 'omitted' + return f.defaultValueStrategy === 'omitted' ? `${key}: ${renderedValue}` : `${key}: value.${key} ?? ${renderedValue}`; }) @@ -457,7 +464,7 @@ export function getTypeManifestVisitor(nameApi: NameApi) { visitStructFieldType(structFieldType, { self }) { const name = camelCase(structFieldType.name); - const childManifest = visit(structFieldType.child, self); + const childManifest = visit(structFieldType.type, self); const docblock = createDocblock(structFieldType.docs); const originalLooseType = childManifest.looseType.render; childManifest.strictType.mapRender( @@ -470,12 +477,12 @@ export function getTypeManifestVisitor(nameApi: NameApi) { childManifest.decoder.mapRender((r) => `['${name}', ${r}]`); // No default value. - if (structFieldType.defaultsTo === null) { + if (!structFieldType.defaultValue) { return childManifest; } // Optional default value. - if (structFieldType.defaultsTo.strategy === 'optional') { + if (structFieldType.defaultValueStrategy !== 'omitted') { childManifest.looseType.setRender( `${docblock}${name}?: ${originalLooseType}; ` ); @@ -488,9 +495,9 @@ export function getTypeManifestVisitor(nameApi: NameApi) { }, visitTupleType(tupleType, { self }) { - const children = tupleType.children.map((item) => visit(item, self)); + const items = tupleType.items.map((item) => visit(item, self)); const mergedManifest = mergeManifests( - children, + items, (types) => `[${types.join(', ')}]`, (codecs) => `[${codecs.join(', ')}]` ); diff --git a/src/renderers/js-experimental/renderValueNodeVisitor.ts b/src/renderers/js-experimental/renderValueNodeVisitor.ts index 7d753c30d..b62835356 100644 --- a/src/renderers/js-experimental/renderValueNodeVisitor.ts +++ b/src/renderers/js-experimental/renderValueNodeVisitor.ts @@ -1,12 +1,17 @@ -import { RegisteredValueNodes } from '../../nodes'; -import { pascalCase } from '../../shared'; +import { RegisteredValueNodeKind, isNode, isScalarEnum } from '../../nodes'; +import { LinkableDictionary, MainCaseString, pascalCase } from '../../shared'; import { Visitor, visit } from '../../visitors'; import { Fragment, fragment, mergeFragments } from './fragments'; import { NameApi } from './nameTransformers'; -export function renderValueNodeVisitor( - nameApi: NameApi -): Visitor { +export type ValueNodeVisitor = ReturnType; + +export function renderValueNodeVisitor(input: { + nameApi: NameApi; + linkables: LinkableDictionary; + nonScalarEnums: MainCaseString[]; +}): Visitor { + const { nameApi, linkables, nonScalarEnums } = input; return { visitArrayValue(node) { return mergeFragments( @@ -18,19 +23,25 @@ export function renderValueNodeVisitor( return fragment(JSON.stringify(node.boolean)); }, visitEnumValue(node) { - const enumName = nameApi.dataType(node.enumType); - const enumFunction = nameApi.dataEnumFunction(node.enumType); + const enumName = nameApi.dataType(node.enum.name); + const enumFunction = nameApi.dataEnumFunction(node.enum.name); const variantName = pascalCase(node.variant); - const importFrom = node.importFrom ?? 'generatedTypes'; + const importFrom = node.enum.importFrom ?? 'generatedTypes'; + + const enumNode = linkables.get(node.enum); + const isScalar = + enumNode && isNode(enumNode, 'enumTypeNode') + ? isScalarEnum(enumNode) + : !nonScalarEnums.includes(node.enum.name); - if (node.value === 'scalar') { + if (!node.value && isScalar) { return fragment(`${enumName}.${variantName}`).addImports( importFrom, enumName ); } - if (node.value === 'empty') { + if (!node.value) { return fragment(`${enumFunction}('${variantName}')`).addImports( importFrom, enumFunction @@ -42,17 +53,18 @@ export function renderValueNodeVisitor( .addImports(importFrom, enumFunction); }, visitMapValue(node) { - const entryFragments = node.entries.map(([k, v]) => - mergeFragments( - [visit(k, this), visit(v, this)], - (renders) => `[${renders.join(', ')}]` - ) - ); + const entryFragments = node.entries.map((entry) => visit(entry, this)); return mergeFragments( entryFragments, (renders) => `new Map([${renders.join(', ')}])` ); }, + visitMapEntryValue(node) { + return mergeFragments( + [visit(node.key, this), visit(node.value, this)], + (renders) => `[${renders.join(', ')}]` + ); + }, visitNoneValue() { return fragment('none()').addImports('solanaOptions', 'none'); }, @@ -80,14 +92,14 @@ export function renderValueNodeVisitor( return fragment(JSON.stringify(node.string)); }, visitStructValue(node) { - const fieldFragments = Object.entries(node.fields).map(([k, v]) => - visit(v, this).mapRender((r) => `${k}: ${r}`) - ); return mergeFragments( - fieldFragments, + node.fields.map((field) => visit(field, this)), (renders) => `{ ${renders.join(', ')} }` ); }, + visitStructFieldValue(node) { + return visit(node.value, this).mapRender((r) => `${node.name}: ${r}`); + }, visitTupleValue(node) { return mergeFragments( node.items.map((v) => visit(v, this)), diff --git a/src/renderers/js/getRenderMapVisitor.ts b/src/renderers/js/getRenderMapVisitor.ts index 15a76cf48..50985be72 100644 --- a/src/renderers/js/getRenderMapVisitor.ts +++ b/src/renderers/js/getRenderMapVisitor.ts @@ -19,6 +19,7 @@ import { ImportFrom, LinkableDictionary, logWarn, + mainCase, pascalCase, pipe, RenderMap, @@ -57,6 +58,7 @@ export type GetJavaScriptRenderMapOptions = { formatCode?: boolean; prettierOptions?: PrettierOptions; dependencyMap?: Record; + nonScalarEnums?: string[]; }; export function getRenderMapVisitor( @@ -66,9 +68,6 @@ export function getRenderMapVisitor( const byteSizeVisitor = getByteSizeVisitor(linkables); let program: ProgramNode | null = null; - const valueNodeVisitor = renderValueNodeVisitor(); - const typeManifestVisitor = getTypeManifestVisitor(); - const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor(); const renderParentInstructions = options.renderParentInstructions ?? false; const formatCode = options.formatCode ?? true; const prettierOptions = { @@ -89,6 +88,14 @@ export function getRenderMapVisitor( generatedErrors: '../errors', generatedTypes: '../types', }; + const nonScalarEnums = (options.nonScalarEnums ?? []).map(mainCase); + + const valueNodeVisitor = renderValueNodeVisitor({ + linkables, + nonScalarEnums, + }); + const typeManifestVisitor = getTypeManifestVisitor(valueNodeVisitor); + const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor(); function getInstructionAccountType( account: ResolvedInstructionAccount @@ -289,8 +296,8 @@ export function getRenderMapVisitor( const discriminatorField = node.data.struct.fields.find( (f) => f.name === discriminator.name ); - const discriminatorValue = discriminatorField?.defaultsTo?.value - ? visit(discriminatorField.defaultsTo.value, valueNodeVisitor) + const discriminatorValue = discriminatorField?.defaultValue + ? visit(discriminatorField.defaultValue, valueNodeVisitor) : undefined; if (discriminatorValue) { imports.mergeWith(discriminatorValue.imports); @@ -403,20 +410,20 @@ export function getRenderMapVisitor( const hasDataArgs = !!node.dataArgs.link || node.dataArgs.struct.fields.filter( - (field) => field.defaultsTo?.strategy !== 'omitted' + (field) => field.defaultValueStrategy !== 'omitted' ).length > 0; const hasExtraArgs = !!node.extraArgs.link || node.extraArgs.struct.fields.filter( - (field) => field.defaultsTo?.strategy !== 'omitted' + (field) => field.defaultValueStrategy !== 'omitted' ).length > 0; const hasAnyArgs = hasDataArgs || hasExtraArgs; const hasArgDefaults = Object.keys(node.argDefaults).length > 0; const hasArgResolvers = Object.values(node.argDefaults).some( isNodeFilter('resolverValueNode') ); - const hasAccountResolvers = node.accounts.some(({ defaultsTo }) => - isNode(defaultsTo, 'resolverValueNode') + const hasAccountResolvers = node.accounts.some(({ defaultValue }) => + isNode(defaultValue, 'resolverValueNode') ); const hasByteResolver = node.bytesCreatedOnChain?.kind === 'resolver'; const hasRemainingAccountsResolver = @@ -460,6 +467,7 @@ export function getRenderMapVisitor( ).map((input: ResolvedInstructionInput) => { const renderedInput = renderInstructionDefaults( input, + valueNodeVisitor, node.optionalAccountStrategy, argObject ); @@ -468,7 +476,7 @@ export function getRenderMapVisitor( return { ...input, render: renderedInput.render }; }); const resolvedInputsWithDefaults = resolvedInputs.filter( - (input) => input.defaultsTo !== undefined && input.render !== '' + (input) => input.defaultValue !== undefined && input.render !== '' ); const argsWithDefaults = resolvedInputsWithDefaults .filter((input) => input.kind === 'argument') @@ -476,7 +484,7 @@ export function getRenderMapVisitor( // Accounts. const accounts = node.accounts.map((account) => { - const hasDefaultValue = !!account.defaultsTo; + const hasDefaultValue = !!account.defaultValue; const resolvedAccount = resolvedInputs.find( (input) => input.kind === 'instructionAccountNode' && @@ -597,7 +605,7 @@ export function getRenderMapVisitor( }), typeManifest, isDataEnum: - isNode(node.data, 'enumTypeNode') && isDataEnum(node.data), + isNode(node.type, 'enumTypeNode') && isDataEnum(node.type), }) ); }, diff --git a/src/renderers/js/getTypeManifestVisitor.ts b/src/renderers/js/getTypeManifestVisitor.ts index a12187350..41c398aa3 100644 --- a/src/renderers/js/getTypeManifestVisitor.ts +++ b/src/renderers/js/getTypeManifestVisitor.ts @@ -1,6 +1,6 @@ import { ArrayTypeNode, - REGISTERED_TYPE_NODE_KEYS, + REGISTERED_TYPE_NODE_KINDS, isInteger, isNode, isScalarEnum, @@ -23,9 +23,10 @@ export type JavaScriptTypeManifest = { serializerImports: JavaScriptImportMap; }; -export function getTypeManifestVisitor() { +export function getTypeManifestVisitor( + valueNodeVisitor: ReturnType +) { let parentName: { strict: string; loose: string } | null = null; - const valueNodeVisitor = renderValueNodeVisitor(); return pipe( staticVisitor( @@ -40,7 +41,7 @@ export function getTypeManifestVisitor() { serializerImports: new JavaScriptImportMap(), } as JavaScriptTypeManifest), [ - ...REGISTERED_TYPE_NODE_KEYS, + ...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode', @@ -96,13 +97,13 @@ export function getTypeManifestVisitor() { strict: pascalCase(definedType.name), loose: `${pascalCase(definedType.name)}Args`, }; - const manifest = visit(definedType.data, self); + const manifest = visit(definedType.type, self); parentName = null; return manifest; }, visitArrayType(arrayType, { self }) { - const childManifest = visit(arrayType.child, self); + const childManifest = visit(arrayType.item, self); childManifest.serializerImports.add('umiSerializers', 'array'); const sizeOption = getArrayLikeSizeOption( arrayType.size, @@ -269,7 +270,7 @@ export function getTypeManifestVisitor() { const struct = structTypeNode([ structFieldTypeNode({ name: 'fields', - child: enumTupleVariantType.tuple, + type: enumTupleVariantType.tuple, }), ]); const type = visit(struct, self); @@ -301,7 +302,7 @@ export function getTypeManifestVisitor() { }, visitOptionType(optionType, { self }) { - const childManifest = visit(optionType.child, self); + const childManifest = visit(optionType.item, self); childManifest.strictImports.add('umi', 'Option'); childManifest.looseImports.add('umi', 'OptionOrNullable'); childManifest.serializerImports.add('umiSerializers', 'option'); @@ -338,7 +339,7 @@ export function getTypeManifestVisitor() { }, visitSetType(setType, { self }) { - const childManifest = visit(setType.child, self); + const childManifest = visit(setType.item, self); childManifest.serializerImports.add('umiSerializers', 'set'); const sizeOption = getArrayLikeSizeOption( setType.size, @@ -384,7 +385,7 @@ export function getTypeManifestVisitor() { }; const optionalFields = structType.fields.filter( - (f) => f.defaultsTo !== null + (f) => !!f.defaultValue ); if (optionalFields.length === 0) { return baseManifest; @@ -393,15 +394,15 @@ export function getTypeManifestVisitor() { const defaultValues = optionalFields .map((f) => { const key = camelCase(f.name); - const defaultsTo = f.defaultsTo as NonNullable< - typeof f.defaultsTo + const defaultValue = f.defaultValue as NonNullable< + typeof f.defaultValue >; const { render: renderedValue, imports } = visit( - defaultsTo.value, + defaultValue, valueNodeVisitor ); baseManifest.serializerImports.mergeWith(imports); - if (defaultsTo.strategy === 'omitted') { + if (f.defaultValueStrategy === 'omitted') { return `${key}: ${renderedValue}`; } return `${key}: value.${key} ?? ${renderedValue}`; @@ -421,7 +422,7 @@ export function getTypeManifestVisitor() { visitStructFieldType(structFieldType, { self }) { const name = camelCase(structFieldType.name); - const fieldChild = visit(structFieldType.child, self); + const fieldChild = visit(structFieldType.type, self); const docblock = createDocblock(structFieldType.docs); const baseField = { ...fieldChild, @@ -429,10 +430,10 @@ export function getTypeManifestVisitor() { looseType: `${docblock}${name}: ${fieldChild.looseType}; `, serializer: `['${name}', ${fieldChild.serializer}]`, }; - if (structFieldType.defaultsTo === null) { + if (!structFieldType.defaultValue) { return baseField; } - if (structFieldType.defaultsTo.strategy === 'optional') { + if (structFieldType.defaultValueStrategy !== 'omitted') { return { ...baseField, looseType: `${docblock}${name}?: ${fieldChild.looseType}; `, @@ -446,19 +447,17 @@ export function getTypeManifestVisitor() { }, visitTupleType(tupleType, { self }) { - const children = tupleType.children.map((item) => visit(item, self)); - const mergedManifest = mergeManifests(children); + const items = tupleType.items.map((item) => visit(item, self)); + const mergedManifest = mergeManifests(items); mergedManifest.serializerImports.add('umiSerializers', 'tuple'); - const childrenSerializers = children + const itemSerializers = items .map((child) => child.serializer) .join(', '); return { ...mergedManifest, - strictType: `[${children - .map((item) => item.strictType) - .join(', ')}]`, - looseType: `[${children.map((item) => item.looseType).join(', ')}]`, - serializer: `tuple([${childrenSerializers}])`, + strictType: `[${items.map((item) => item.strictType).join(', ')}]`, + looseType: `[${items.map((item) => item.looseType).join(', ')}]`, + serializer: `tuple([${itemSerializers}])`, }; }, @@ -558,9 +557,9 @@ export function getTypeManifestVisitor() { `integer types. Got type [${amountType.number.toString()}].` ); } - const { identifier, decimals } = amountType; - const idAndDecimals = `'${identifier}', ${decimals}`; - const isSolAmount = identifier === 'SOL' && decimals === 9; + const { unit, decimals } = amountType; + const idAndDecimals = `'${unit ?? 'Unknown'}', ${decimals}`; + const isSolAmount = unit === 'SOL' && decimals === 9; const amountTypeString = isSolAmount ? 'SolAmount' : `Amount<${idAndDecimals}>`; diff --git a/src/renderers/js/getValidatorBagVisitor.ts b/src/renderers/js/getValidatorBagVisitor.ts index be458b124..58b64e427 100644 --- a/src/renderers/js/getValidatorBagVisitor.ts +++ b/src/renderers/js/getValidatorBagVisitor.ts @@ -156,7 +156,7 @@ export function getValidatorBagVisitor(): Visitor { [pascalCaseName]: 'type', [`${pascalCaseName}Args`]: 'type', [`fetch${pascalCaseName}`]: 'function', - ...(isNode(node.data, 'enumTypeNode') && isDataEnum(node.data) + ...(isNode(node.type, 'enumTypeNode') && isDataEnum(node.type) ? { [camelCaseName]: 'function', [`is${pascalCaseName}`]: 'function', diff --git a/src/renderers/js/renderInstructionDefaults.ts b/src/renderers/js/renderInstructionDefaults.ts index df6e59c1c..b5bce4cae 100644 --- a/src/renderers/js/renderInstructionDefaults.ts +++ b/src/renderers/js/renderInstructionDefaults.ts @@ -1,5 +1,5 @@ import { InstructionInputValueNode, isNode } from '../../nodes'; -import { MainCaseString, camelCase, pascalCase } from '../../shared'; +import { camelCase, pascalCase } from '../../shared'; import { ResolvedInstructionInput, visit } from '../../visitors'; import { JavaScriptContextMap } from './JavaScriptContextMap'; import { JavaScriptImportMap } from './JavaScriptImportMap'; @@ -7,6 +7,7 @@ import { renderValueNodeVisitor } from './renderValueNodeVisitor'; export function renderInstructionDefaults( input: ResolvedInstructionInput, + valueNodeVisitor: ReturnType, optionalAccountStrategy: 'programId' | 'omitted', argObject: string ): { @@ -14,17 +15,16 @@ export function renderInstructionDefaults( interfaces: JavaScriptContextMap; render: string; } { - const valueNodeVisitor = renderValueNodeVisitor(); const imports = new JavaScriptImportMap(); const interfaces = new JavaScriptContextMap(); - if (!input.defaultsTo) { + if (!input.defaultValue) { return { imports, interfaces, render: '' }; } - const { defaultsTo } = input; + const { defaultValue } = input; const render = ( - defaultValue: string, + renderedValue: string, isWritable?: boolean ): { imports: JavaScriptImportMap; @@ -34,19 +34,19 @@ export function renderInstructionDefaults( const inputName = camelCase(input.name); if ( input.kind === 'instructionAccountNode' && - isNode(defaultsTo, 'resolverValueNode') + isNode(defaultValue, 'resolverValueNode') ) { return { imports, interfaces, - render: `resolvedAccounts.${inputName} = { ...resolvedAccounts.${inputName}, ...${defaultValue} };`, + render: `resolvedAccounts.${inputName} = { ...resolvedAccounts.${inputName}, ...${renderedValue} };`, }; } if (input.kind === 'instructionAccountNode' && isWritable === undefined) { return { imports, interfaces, - render: `resolvedAccounts.${inputName}.value = ${defaultValue};`, + render: `resolvedAccounts.${inputName}.value = ${renderedValue};`, }; } if (input.kind === 'instructionAccountNode') { @@ -54,7 +54,7 @@ export function renderInstructionDefaults( imports, interfaces, render: - `resolvedAccounts.${inputName}.value = ${defaultValue};\n` + + `resolvedAccounts.${inputName}.value = ${renderedValue};\n` + `resolvedAccounts.${inputName}.isWritable = ${ isWritable ? 'true' : 'false' }`, @@ -63,13 +63,13 @@ export function renderInstructionDefaults( return { imports, interfaces, - render: `${argObject}.${inputName} = ${defaultValue};`, + render: `${argObject}.${inputName} = ${renderedValue};`, }; }; - switch (defaultsTo.kind) { + switch (defaultValue.kind) { case 'accountValueNode': - const name = camelCase(defaultsTo.name); + const name = camelCase(defaultValue.name); if (input.kind === 'instructionAccountNode') { imports.add('shared', 'expectSome'); if (input.resolvedIsSigner && !input.isSigner) { @@ -80,41 +80,38 @@ export function renderInstructionDefaults( imports.add('shared', 'expectPublicKey'); return render(`expectPublicKey(resolvedAccounts.${name}.value)`); case 'pdaValueNode': - const pdaFunction = `find${pascalCase(defaultsTo.pda.name)}Pda`; - const pdaImportFrom = defaultsTo.pda.importFrom ?? 'generatedAccounts'; + const pdaFunction = `find${pascalCase(defaultValue.pda.name)}Pda`; + const pdaImportFrom = defaultValue.pda.importFrom ?? 'generatedAccounts'; imports.add(pdaImportFrom, pdaFunction); interfaces.add('eddsa'); const pdaArgs = ['context']; - const pdaSeeds = Object.keys(defaultsTo.seeds).map( - (seed: string): string => { - const seedValue = defaultsTo.seeds[seed as MainCaseString]; - if (isNode(seedValue, 'accountValueNode')) { - imports.add('shared', 'expectPublicKey'); - return `${seed}: expectPublicKey(resolvedAccounts.${camelCase( - seedValue.name - )}.value)`; - } - if (isNode(seedValue, 'argumentValueNode')) { - imports.add('shared', 'expectSome'); - return `${seed}: expectSome(${argObject}.${camelCase( - seedValue.name - )})`; - } - const valueManifest = visit(seedValue, valueNodeVisitor); - imports.mergeWith(valueManifest.imports); - return `${seed}: ${valueManifest.render}`; + const pdaSeeds = defaultValue.seeds.map((seed): string => { + if (isNode(seed.value, 'accountValueNode')) { + imports.add('shared', 'expectPublicKey'); + return `${seed.name}: expectPublicKey(resolvedAccounts.${camelCase( + seed.value.name + )}.value)`; } - ); + if (isNode(seed.value, 'argumentValueNode')) { + imports.add('shared', 'expectSome'); + return `${seed.name}: expectSome(${argObject}.${camelCase( + seed.value.name + )})`; + } + const valueManifest = visit(seed.value, valueNodeVisitor); + imports.mergeWith(valueManifest.imports); + return `${seed.name}: ${valueManifest.render}`; + }); if (pdaSeeds.length > 0) { pdaArgs.push(`{ ${pdaSeeds.join(', ')} }`); } return render(`${pdaFunction}(${pdaArgs.join(', ')})`); case 'publicKeyValueNode': imports.add('umi', 'publicKey'); - return render(`publicKey('${defaultsTo.publicKey}')`); + return render(`publicKey('${defaultValue.publicKey}')`); case 'programLinkNode': - const importFrom = defaultsTo.importFrom ?? 'generatedPrograms'; - const functionName = `get${pascalCase(defaultsTo.name)}ProgramId`; + const importFrom = defaultValue.importFrom ?? 'generatedPrograms'; + const functionName = `get${pascalCase(defaultValue.name)}ProgramId`; imports.add(importFrom, functionName); return render(`${functionName}(context)`, false); case 'programIdValueNode': @@ -141,18 +138,18 @@ export function renderInstructionDefaults( case 'accountBumpValueNode': imports.add('shared', 'expectPda'); return render( - `expectPda(resolvedAccounts.${camelCase(defaultsTo.name)}.value)[1]` + `expectPda(resolvedAccounts.${camelCase(defaultValue.name)}.value)[1]` ); case 'argumentValueNode': imports.add('shared', 'expectSome'); - return render(`expectSome(${argObject}.${camelCase(defaultsTo.name)})`); + return render(`expectSome(${argObject}.${camelCase(defaultValue.name)})`); case 'resolverValueNode': - const resolverName = camelCase(defaultsTo.name); + const resolverName = camelCase(defaultValue.name); const isWritable = input.kind === 'instructionAccountNode' && input.isWritable ? 'true' : 'false'; - imports.add(defaultsTo.importFrom ?? 'hooked', resolverName); + imports.add(defaultValue.importFrom ?? 'hooked', resolverName); interfaces.add(['eddsa', 'identity', 'payer']); return render( `${resolverName}(context, resolvedAccounts, ${argObject}, programId, ${isWritable})` @@ -160,14 +157,16 @@ export function renderInstructionDefaults( case 'conditionalValueNode': const ifTrueRenderer = renderNestedInstructionDefault( input, + valueNodeVisitor, optionalAccountStrategy, - defaultsTo.ifTrue, + defaultValue.ifTrue, argObject ); const ifFalseRenderer = renderNestedInstructionDefault( input, + valueNodeVisitor, optionalAccountStrategy, - defaultsTo.ifFalse, + defaultValue.ifFalse, argObject ); if (!ifTrueRenderer && !ifFalseRenderer) { @@ -184,14 +183,14 @@ export function renderInstructionDefaults( const negatedCondition = !ifTrueRenderer; let condition = 'true'; - if (isNode(defaultsTo.condition, 'resolverValueNode')) { - const conditionalResolverName = camelCase(defaultsTo.condition.name); + if (isNode(defaultValue.condition, 'resolverValueNode')) { + const conditionalResolverName = camelCase(defaultValue.condition.name); const conditionalIsWritable = input.kind === 'instructionAccountNode' && input.isWritable ? 'true' : 'false'; imports.add( - defaultsTo.condition.importFrom ?? 'hooked', + defaultValue.condition.importFrom ?? 'hooked', conditionalResolverName ); interfaces.add(['eddsa', 'identity', 'payer']); @@ -199,13 +198,13 @@ export function renderInstructionDefaults( condition = negatedCondition ? `!${condition}` : condition; } else { const comparedInputName = isNode( - defaultsTo.condition, + defaultValue.condition, 'accountValueNode' ) - ? `resolvedAccounts.${camelCase(defaultsTo.condition.name)}.value` - : `${argObject}.${camelCase(defaultsTo.condition.name)}`; - if (defaultsTo.value) { - const comparedValue = visit(defaultsTo.value, valueNodeVisitor); + ? `resolvedAccounts.${camelCase(defaultValue.condition.name)}.value` + : `${argObject}.${camelCase(defaultValue.condition.name)}`; + if (defaultValue.value) { + const comparedValue = visit(defaultValue.value, valueNodeVisitor); imports.mergeWith(comparedValue.imports); const operator = negatedCondition ? '!==' : '==='; condition = `${comparedInputName} ${operator} ${comparedValue.render}`; @@ -232,7 +231,7 @@ export function renderInstructionDefaults( }\n}`, }; default: - const valueManifest = visit(defaultsTo, valueNodeVisitor); + const valueManifest = visit(defaultValue, valueNodeVisitor); imports.mergeWith(valueManifest.imports); return render(valueManifest.render); } @@ -240,8 +239,9 @@ export function renderInstructionDefaults( function renderNestedInstructionDefault( input: ResolvedInstructionInput, + valueNodeVisitor: ReturnType, optionalAccountStrategy: 'programId' | 'omitted', - defaultsTo: InstructionInputValueNode | undefined, + defaultValue: InstructionInputValueNode | undefined, argObject: string ): | { @@ -250,9 +250,10 @@ function renderNestedInstructionDefault( render: string; } | undefined { - if (!defaultsTo) return undefined; + if (!defaultValue) return undefined; return renderInstructionDefaults( - { ...input, defaultsTo }, + { ...input, defaultValue }, + valueNodeVisitor, optionalAccountStrategy, argObject ); diff --git a/src/renderers/js/renderValueNodeVisitor.ts b/src/renderers/js/renderValueNodeVisitor.ts index fdd85e5a8..f9ae43b35 100644 --- a/src/renderers/js/renderValueNodeVisitor.ts +++ b/src/renderers/js/renderValueNodeVisitor.ts @@ -1,15 +1,24 @@ +import { RegisteredValueNodeKind, isNode, isScalarEnum } from '../../nodes'; +import { + LinkableDictionary, + MainCaseString, + camelCase, + pascalCase, +} from '../../shared'; import { Visitor, visit } from '../../visitors'; -import { RegisteredValueNodes } from '../../nodes'; -import { camelCase, pascalCase } from '../../shared'; import { JavaScriptImportMap } from './JavaScriptImportMap'; -export function renderValueNodeVisitor(): Visitor< +export function renderValueNodeVisitor(input: { + linkables: LinkableDictionary; + nonScalarEnums: MainCaseString[]; +}): Visitor< { imports: JavaScriptImportMap; render: string; }, - keyof RegisteredValueNodes + RegisteredValueNodeKind > { + const { linkables, nonScalarEnums } = input; return { visitArrayValue(node) { const list = node.items.map((v) => visit(v, this)); @@ -28,21 +37,27 @@ export function renderValueNodeVisitor(): Visitor< }, visitEnumValue(node) { const imports = new JavaScriptImportMap(); - const enumName = pascalCase(node.enumType); + const enumName = pascalCase(node.enum.name); const variantName = pascalCase(node.variant); - const importFrom = node.importFrom ?? 'generatedTypes'; + const importFrom = node.enum.importFrom ?? 'generatedTypes'; - if (node.value === 'scalar') { + const enumNode = linkables.get(node.enum); + const isScalar = + enumNode && isNode(enumNode, 'enumTypeNode') + ? isScalarEnum(enumNode) + : !nonScalarEnums.includes(node.enum.name); + + if (!node.value && isScalar) { return { imports: imports.add(importFrom, enumName), render: `${enumName}.${variantName}`, }; } - const enumFn = camelCase(node.enumType); + const enumFn = camelCase(node.enum.name); imports.add(importFrom, enumFn); - if (node.value === 'empty') { + if (!node.value) { return { imports, render: `${enumFn}('${variantName}')` }; } @@ -56,14 +71,7 @@ export function renderValueNodeVisitor(): Visitor< }; }, visitMapValue(node) { - const map = node.entries.map(([k, v]) => { - const mapKey = visit(k, this); - const mapValue = visit(v, this); - return { - imports: mapKey.imports.mergeWith(mapValue.imports), - render: `[${mapKey.render}, ${mapValue.render}]`, - }; - }); + const map = node.entries.map((entry) => visit(entry, this)); return { imports: new JavaScriptImportMap().mergeWith( ...map.map((c) => c.imports) @@ -71,6 +79,14 @@ export function renderValueNodeVisitor(): Visitor< render: `new Map([${map.map((c) => c.render).join(', ')}])`, }; }, + visitMapEntryValue(node) { + const mapKey = visit(node.key, this); + const mapValue = visit(node.value, this); + return { + imports: mapKey.imports.mergeWith(mapValue.imports), + render: `[${mapKey.render}, ${mapValue.render}]`, + }; + }, visitNoneValue() { return { imports: new JavaScriptImportMap().add('umi', 'none'), @@ -112,13 +128,7 @@ export function renderValueNodeVisitor(): Visitor< }; }, visitStructValue(node) { - const struct = Object.entries(node.fields).map(([k, v]) => { - const structValue = visit(v, this); - return { - imports: structValue.imports, - render: `${k}: ${structValue.render}`, - }; - }); + const struct = node.fields.map((field) => visit(field, this)); return { imports: new JavaScriptImportMap().mergeWith( ...struct.map((c) => c.imports) @@ -126,6 +136,13 @@ export function renderValueNodeVisitor(): Visitor< render: `{ ${struct.map((c) => c.render).join(', ')} }`, }; }, + visitStructFieldValue(node) { + const structValue = visit(node.value, this); + return { + imports: structValue.imports, + render: `${node.name}: ${structValue.render}`, + }; + }, visitTupleValue(node) { const list = node.items.map((v) => visit(v, this)); return { diff --git a/src/renderers/js/templates/definedTypesPageDataEnums.njk b/src/renderers/js/templates/definedTypesPageDataEnums.njk index b6ba87e06..f3366e2ed 100644 --- a/src/renderers/js/templates/definedTypesPageDataEnums.njk +++ b/src/renderers/js/templates/definedTypesPageDataEnums.njk @@ -2,7 +2,7 @@ {% set strictName = definedType.name | pascalCase %} {% set looseName = definedType.name | pascalCase + 'Args' %} // Data Enum Helpers. - {% for variant in definedType.data.variants %} + {% for variant in definedType.type.variants %} {% if variant.kind === 'enumStructVariantTypeNode' %} export function {{ definedType.name | camelCase }}(kind: '{{ variant.name | pascalCase }}', data: GetDataEnumKindContent<{{ looseName }}, '{{ variant.name | pascalCase }}'>): GetDataEnumKind<{{ looseName }}, '{{ variant.name | pascalCase }}'>; {% elif variant.kind === 'enumTupleVariantTypeNode' %} diff --git a/src/renderers/rust/getRenderMapVisitor.ts b/src/renderers/rust/getRenderMapVisitor.ts index b032e608f..0cf171212 100644 --- a/src/renderers/rust/getRenderMapVisitor.ts +++ b/src/renderers/rust/getRenderMapVisitor.ts @@ -225,26 +225,28 @@ export function getRenderMapVisitor(options: GetRustRenderMapOptions = {}) { pascalCase(node.dataArgs.name) + pascalCase(field.name) ); typeManifestVisitor.setNestedStruct(true); - const manifest = visit(field.child, typeManifestVisitor); + const manifest = visit(field.type, typeManifestVisitor); imports.mergeWith(manifest.imports); - const innerOptionType = isNode(field.child, 'optionTypeNode') + const innerOptionType = isNode(field.type, 'optionTypeNode') ? manifest.type.slice('Option<'.length, -1) : null; typeManifestVisitor.setParentName(null); typeManifestVisitor.setNestedStruct(false); let renderValue: string | null = null; - if (field.defaultsTo) { + if (field.defaultValue) { const { imports: argImports, render: value } = renderValueNode( - field.defaultsTo.value + field.defaultValue ); imports.mergeWith(argImports); renderValue = value; } - hasArgs = hasArgs || field.defaultsTo?.strategy !== 'omitted'; + const hasDefaultValue = !!field.defaultValue; + hasArgs = hasArgs || field.defaultValueStrategy !== 'omitted'; hasOptional = - hasOptional || field.defaultsTo?.strategy === 'optional'; + hasOptional || + (hasDefaultValue && field.defaultValueStrategy !== 'omitted'); const name = accountsAndArgsConflicts.includes(field.name) ? `${field.name}_arg` @@ -253,8 +255,10 @@ export function getRenderMapVisitor(options: GetRustRenderMapOptions = {}) { instructionArgs.push({ name, type: manifest.type, - default: field.defaultsTo?.strategy === 'omitted', - optional: field.defaultsTo?.strategy === 'optional', + default: + hasDefaultValue && field.defaultValueStrategy === 'omitted', + optional: + hasDefaultValue && field.defaultValueStrategy !== 'omitted', innerOptionType, value: renderValue, }); diff --git a/src/renderers/rust/getTypeManifestVisitor.ts b/src/renderers/rust/getTypeManifestVisitor.ts index 94a0cac15..6cc01e2e0 100644 --- a/src/renderers/rust/getTypeManifestVisitor.ts +++ b/src/renderers/rust/getTypeManifestVisitor.ts @@ -1,5 +1,5 @@ import { - REGISTERED_TYPE_NODE_KEYS, + REGISTERED_TYPE_NODE_KINDS, arrayTypeNode, isNode, isScalarEnum, @@ -28,7 +28,7 @@ export function getTypeManifestVisitor() { type: values.map((v) => v.type).join('\n'), }), [ - ...REGISTERED_TYPE_NODE_KEYS, + ...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode', @@ -81,7 +81,7 @@ export function getTypeManifestVisitor() { visitDefinedType(definedType, { self }) { parentName = pascalCase(definedType.name); - const manifest = visit(definedType.data, self); + const manifest = visit(definedType.type, self); parentName = null; manifest.imports.add([ 'borsh::BorshSerialize', @@ -96,8 +96,8 @@ export function getTypeManifestVisitor() { 'PartialEq', ]; if ( - isNode(definedType.data, 'enumTypeNode') && - isScalarEnum(definedType.data) + isNode(definedType.type, 'enumTypeNode') && + isScalarEnum(definedType.type) ) { traits.push('PartialOrd', 'Hash'); } @@ -117,7 +117,7 @@ export function getTypeManifestVisitor() { }, visitArrayType(arrayType, { self }) { - const childManifest = visit(arrayType.child, self); + const childManifest = visit(arrayType.item, self); if (isNode(arrayType.size, 'fixedSizeNode')) { return { @@ -263,7 +263,7 @@ export function getTypeManifestVisitor() { }, visitOptionType(optionType, { self }) { - const childManifest = visit(optionType.child, self); + const childManifest = visit(optionType.item, self); if ( optionType.prefix.format === 'u8' && @@ -280,7 +280,7 @@ export function getTypeManifestVisitor() { }, visitSetType(setType, { self }) { - const childManifest = visit(setType.child, self); + const childManifest = visit(setType.item, self); childManifest.imports.add('std::collections::HashSet'); return { ...childManifest, @@ -339,7 +339,7 @@ export function getTypeManifestVisitor() { nestedStruct = true; inlineStruct = false; - const fieldManifest = visit(structFieldType.child, self); + const fieldManifest = visit(structFieldType.type, self); parentName = originalParentName; inlineStruct = originalInlineStruct; @@ -353,11 +353,11 @@ export function getTypeManifestVisitor() { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; } else if ( - (structFieldType.child.kind === 'arrayTypeNode' || - structFieldType.child.kind === 'bytesTypeNode' || - structFieldType.child.kind === 'stringTypeNode') && - isNode(structFieldType.child.size, 'fixedSizeNode') && - structFieldType.child.size.size > 32 + (structFieldType.type.kind === 'arrayTypeNode' || + structFieldType.type.kind === 'bytesTypeNode' || + structFieldType.type.kind === 'stringTypeNode') && + isNode(structFieldType.type.size, 'fixedSizeNode') && + structFieldType.type.size.size > 32 ) { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; @@ -372,12 +372,12 @@ export function getTypeManifestVisitor() { }, visitTupleType(tupleType, { self }) { - const children = tupleType.children.map((item) => visit(item, self)); - const mergedManifest = mergeManifests(children); + const items = tupleType.items.map((item) => visit(item, self)); + const mergedManifest = mergeManifests(items); return { ...mergedManifest, - type: `(${children.map((item) => item.type).join(', ')})`, + type: `(${items.map((item) => item.type).join(', ')})`, }; }, @@ -398,10 +398,7 @@ export function getTypeManifestVisitor() { }, visitBytesType(bytesType, { self }) { - const arrayType = arrayTypeNode(numberTypeNode('u8'), { - size: bytesType.size, - }); - + const arrayType = arrayTypeNode(numberTypeNode('u8'), bytesType.size); return visit(arrayType, self); }, diff --git a/src/renderers/rust/renderValueNodeVisitor.ts b/src/renderers/rust/renderValueNodeVisitor.ts index e10dcdbba..339328632 100644 --- a/src/renderers/rust/renderValueNodeVisitor.ts +++ b/src/renderers/rust/renderValueNodeVisitor.ts @@ -1,7 +1,7 @@ -import { RustImportMap } from './RustImportMap'; -import { Visitor, visit } from '../../visitors'; -import { RegisteredValueNodes, ValueNode } from '../../nodes'; +import { RegisteredValueNodeKind, ValueNode } from '../../nodes'; import { pascalCase } from '../../shared'; +import { Visitor, visit } from '../../visitors'; +import { RustImportMap } from './RustImportMap'; export function renderValueNode( value: ValueNode, @@ -18,7 +18,7 @@ export function renderValueNodeVisitor(useStr: boolean = false): Visitor< imports: RustImportMap; render: string; }, - keyof RegisteredValueNodes + RegisteredValueNodeKind > { return { visitArrayValue(node) { @@ -36,11 +36,11 @@ export function renderValueNodeVisitor(useStr: boolean = false): Visitor< }, visitEnumValue(node) { const imports = new RustImportMap(); - const enumName = pascalCase(node.enumType); + const enumName = pascalCase(node.enum.name); const variantName = pascalCase(node.variant); - const importFrom = node.importFrom ?? 'generatedTypes'; + const importFrom = node.enum.importFrom ?? 'generatedTypes'; imports.add(`${importFrom}::${enumName}`); - if (node.value === 'scalar' || node.value === 'empty') { + if (!node.value) { return { imports, render: `${enumName}::${variantName}` }; } const enumValue = visit(node.value, this); @@ -51,20 +51,21 @@ export function renderValueNodeVisitor(useStr: boolean = false): Visitor< }; }, visitMapValue(node) { - const map = node.entries.map(([k, v]) => { - const mapKey = visit(k, this); - const mapValue = visit(v, this); - return { - imports: mapKey.imports.mergeWith(mapValue.imports), - render: `[${mapKey.render}, ${mapValue.render}]`, - }; - }); + const map = node.entries.map((entry) => visit(entry, this)); const imports = new RustImportMap().add('std::collection::HashMap'); return { imports: imports.mergeWith(...map.map((c) => c.imports)), render: `HashMap::from([${map.map((c) => c.render).join(', ')}])`, }; }, + visitMapEntryValue(node) { + const mapKey = visit(node.key, this); + const mapValue = visit(node.value, this); + return { + imports: mapKey.imports.mergeWith(mapValue.imports), + render: `[${mapKey.render}, ${mapValue.render}]`, + }; + }, visitNoneValue() { return { imports: new RustImportMap(), @@ -107,18 +108,19 @@ export function renderValueNodeVisitor(useStr: boolean = false): Visitor< }; }, visitStructValue(node) { - const struct = Object.entries(node.fields).map(([k, v]) => { - const structValue = visit(v, this); - return { - imports: structValue.imports, - render: `${k}: ${structValue.render}`, - }; - }); + const struct = node.fields.map((field) => visit(field, this)); return { imports: new RustImportMap().mergeWith(...struct.map((c) => c.imports)), render: `{ ${struct.map((c) => c.render).join(', ')} }`, }; }, + visitStructFieldValue(node) { + const structValue = visit(node.value, this); + return { + imports: structValue.imports, + render: `${node.name}: ${structValue.render}`, + }; + }, visitTupleValue(node) { const tuple = node.items.map((v) => visit(v, this)); return { diff --git a/src/renderers/rust/templates/instructionsPageBuilder.njk b/src/renderers/rust/templates/instructionsPageBuilder.njk index ce3ed1484..5838b9d44 100644 --- a/src/renderers/rust/templates/instructionsPageBuilder.njk +++ b/src/renderers/rust/templates/instructionsPageBuilder.njk @@ -10,11 +10,11 @@ {% if account.isSigner %} {% set modifiers = modifiers + ', signer' if modifiers.length > 0 else 'signer' %} {% endif %} - {% if account.isOptional or account.defaultsTo.kind === 'publicKeyValueNode' %} + {% if account.isOptional or account.defaultValue.kind === 'publicKeyValueNode' %} {% set modifiers = modifiers + ', optional' if modifiers.length > 0 else 'optional' %} {% endif %} {{ '/// ' + loop.index0 + '. `[' + modifiers + ']` ' + account.name | snakeCase }} - {{- " (default to `" + account.defaultsTo.publicKey + "`)" if account.defaultsTo.kind === 'publicKeyValueNode' }} + {{- " (default to `" + account.defaultValue.publicKey + "`)" if account.defaultValue.kind === 'publicKeyValueNode' }} {% endfor %} #[derive(Default)] pub struct {{ instruction.name | pascalCase }}Builder { @@ -41,7 +41,7 @@ impl {{ instruction.name | pascalCase }}Builder { {% if account.isOptional %} {{ '/// `[optional account]`\n' -}} {% else %} - {{ "/// `[optional account, default to '" + account.defaultsTo.publicKey + "']`\n" if account.defaultsTo.kind === 'publicKeyValueNode' -}} + {{ "/// `[optional account, default to '" + account.defaultValue.publicKey + "']`\n" if account.defaultValue.kind === 'publicKeyValueNode' -}} {% endif %} {{- macros.docblock(account.docs) -}} #[inline(always)] @@ -96,10 +96,10 @@ impl {{ instruction.name | pascalCase }}Builder { {% for account in instruction.accounts %} {% if account.isOptional %} {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}, - {% elif account.defaultsTo.kind === 'programId' %} + {% elif account.defaultValue.kind === 'programId' %} {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}, {# Program ID set on the instruction creation. #} - {% elif account.defaultsTo.kind === 'publicKeyValueNode' %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.unwrap_or(solana_program::pubkey!("{{ account.defaultsTo.publicKey }}")), + {% elif account.defaultValue.kind === 'publicKeyValueNode' %} + {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.unwrap_or(solana_program::pubkey!("{{ account.defaultValue.publicKey }}")), {% else %} {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.expect("{{ account.name | snakeCase }} is not set"), {% endif %} diff --git a/src/shared/GpaField.ts b/src/shared/GpaField.ts index c3a08e2ce..eae7ad582 100644 --- a/src/shared/GpaField.ts +++ b/src/shared/GpaField.ts @@ -1,4 +1,4 @@ -import type { AccountNode, RegisteredTypeNodes, TypeNode } from '../nodes'; +import type { AccountNode, RegisteredTypeNodeKind, TypeNode } from '../nodes'; import { Visitor, visit } from '../visitors'; export type GpaField = { @@ -11,16 +11,16 @@ export function getGpaFieldsFromAccount( node: AccountNode, sizeVisitor: Visitor< number | null, - keyof RegisteredTypeNodes | 'definedTypeLinkNode' + RegisteredTypeNodeKind | 'definedTypeLinkNode' > ): GpaField[] { let offset: number | null = 0; return node.data.struct.fields.map((field): GpaField => { const fieldOffset = offset; if (offset !== null) { - const newOffset = visit(field.child, sizeVisitor); + const newOffset = visit(field.type, sizeVisitor); offset = newOffset !== null ? offset + newOffset : null; } - return { name: field.name, offset: fieldOffset, type: field.child }; + return { name: field.name, offset: fieldOffset, type: field.type }; }); } diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 83b2e2d4c..a7caf370d 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -17,6 +17,12 @@ export type Mutable = { export type DontInfer = T extends any ? T : never; +export function getNodeKinds>( + obj: TObj +): (keyof TObj)[] { + return Object.keys(obj) as (keyof TObj)[]; +} + export function capitalize(str: string): string { if (str.length === 0) return str; return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); diff --git a/src/visitors/bottomUpTransformerVisitor.ts b/src/visitors/bottomUpTransformerVisitor.ts index fbf100cc1..6d10fdf4a 100644 --- a/src/visitors/bottomUpTransformerVisitor.ts +++ b/src/visitors/bottomUpTransformerVisitor.ts @@ -1,4 +1,4 @@ -import { Node, RegisteredNodes } from '../nodes'; +import { Node, NodeKind } from '../nodes'; import { NodeSelector, NodeStack, @@ -21,14 +21,14 @@ export type BottomUpNodeTransformerWithSelector = { }; export function bottomUpTransformerVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes + TNodeKind extends NodeKind = NodeKind >( transformers: ( | BottomUpNodeTransformer | BottomUpNodeTransformerWithSelector )[], - nodeKeys?: TNodeKeys[] -): Visitor { + nodeKeys?: TNodeKind[] +): Visitor { const transformerFunctions = transformers.map( (transformer): BottomUpNodeTransformer => typeof transformer === 'function' diff --git a/src/visitors/consoleLogVisitor.ts b/src/visitors/consoleLogVisitor.ts index 57e12003c..26df5b720 100644 --- a/src/visitors/consoleLogVisitor.ts +++ b/src/visitors/consoleLogVisitor.ts @@ -1,10 +1,10 @@ -import { RegisteredNodes } from '../nodes'; -import { Visitor } from './visitor'; +import { NodeKind } from '../nodes'; import { mapVisitor } from './mapVisitor'; +import { Visitor } from './visitor'; -export function consoleLogVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->(visitor: Visitor): Visitor { +export function consoleLogVisitor( + visitor: Visitor +): Visitor { // eslint-disable-next-line no-console return mapVisitor(visitor, (value) => console.log(value)); } diff --git a/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts b/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts index f45a154f2..251b85551 100644 --- a/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts +++ b/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts @@ -47,13 +47,13 @@ export function createSubInstructionsFromEnumArgsVisitor( } let argType: EnumTypeNode; - if (isNode(argField.child, 'enumTypeNode')) { - argType = argField.child; + if (isNode(argField.type, 'enumTypeNode')) { + argType = argField.type; } else if ( - isNode(argField.child, 'definedTypeLinkNode') && - linkables.has(argField.child) + isNode(argField.type, 'definedTypeLinkNode') && + linkables.has(argField.type) ) { - const linkedType = linkables.get(argField.child)?.data ?? null; + const linkedType = linkables.get(argField.type)?.type ?? null; assertIsNode(linkedType, 'enumTypeNode'); argType = linkedType; } else { @@ -71,25 +71,23 @@ export function createSubInstructionsFromEnumArgsVisitor( subFields.push( structFieldTypeNode({ name: `${subName}Discriminator`, - child: numberTypeNode('u8'), - defaultsTo: { - strategy: 'omitted', - value: numberValueNode(index), - }, + type: numberTypeNode('u8'), + defaultValue: numberValueNode(index), + defaultValueStrategy: 'omitted', }) ); if (isNode(variant, 'enumStructVariantTypeNode')) { subFields.push( structFieldTypeNode({ ...argField, - child: variant.struct, + type: variant.struct, }) ); } else if (isNode(variant, 'enumTupleVariantTypeNode')) { subFields.push( structFieldTypeNode({ ...argField, - child: variant.tuple, + type: variant.tuple, }) ); } diff --git a/src/visitors/deleteNodesVisitor.ts b/src/visitors/deleteNodesVisitor.ts index 483fad743..a2e687c19 100644 --- a/src/visitors/deleteNodesVisitor.ts +++ b/src/visitors/deleteNodesVisitor.ts @@ -1,14 +1,15 @@ +import { NodeKind } from '../nodes'; import { NodeSelector } from '../shared'; -import { RegisteredNodes } from '../nodes'; import { TopDownNodeTransformerWithSelector, topDownTransformerVisitor, } from './topDownTransformerVisitor'; -export function deleteNodesVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->(selectors: NodeSelector[], nodeKeys?: TNodeKeys[]) { - return topDownTransformerVisitor( +export function deleteNodesVisitor( + selectors: NodeSelector[], + nodeKeys?: TNodeKind[] +) { + return topDownTransformerVisitor( selectors.map( (selector): TopDownNodeTransformerWithSelector => ({ select: selector, diff --git a/src/visitors/extendVisitor.ts b/src/visitors/extendVisitor.ts index ff37a9855..1d3037ae6 100644 --- a/src/visitors/extendVisitor.ts +++ b/src/visitors/extendVisitor.ts @@ -1,5 +1,10 @@ +import { + Node, + NodeDictionary, + NodeKind, + REGISTERED_NODE_KINDS, +} from '../nodes'; import { DontInfer } from '../shared'; -import { REGISTERED_NODES_KEYS, RegisteredNodes, Node } from '../nodes'; import { GetVisitorFunctionName, Visitor, @@ -8,33 +13,30 @@ import { export type VisitorOverrideFunction< TReturn, - TNodeKeys extends keyof RegisteredNodes, + TNodeKind extends NodeKind, TNode extends Node > = ( node: TNode, scope: { next: (node: TNode) => TReturn; - self: Visitor; + self: Visitor; } ) => TReturn; -export type VisitorOverrides< - TReturn, - TNodeKeys extends keyof RegisteredNodes -> = { - [K in TNodeKeys as GetVisitorFunctionName]?: VisitorOverrideFunction< +export type VisitorOverrides = { + [K in TNodeKind as GetVisitorFunctionName]?: VisitorOverrideFunction< TReturn, - TNodeKeys, - RegisteredNodes[K] + TNodeKind, + NodeDictionary[K] >; }; -export function extendVisitor( - visitor: Visitor, - overrides: DontInfer> -): Visitor { +export function extendVisitor( + visitor: Visitor, + overrides: DontInfer> +): Visitor { const registeredVisitFunctions = - REGISTERED_NODES_KEYS.map(getVisitFunctionName); + REGISTERED_NODE_KINDS.map(getVisitFunctionName); const overriddenFunctions = Object.fromEntries( Object.keys(overrides).flatMap((key) => { @@ -42,7 +44,7 @@ export function extendVisitor( return []; } - const castedKey = key as GetVisitorFunctionName; + const castedKey = key as GetVisitorFunctionName; if (!visitor[castedKey]) { throw new Error( @@ -54,12 +56,12 @@ export function extendVisitor( [ castedKey, function extendedVisitNode( - this: Visitor, + this: Visitor, node: TNode ) { const extendedFunction = overrides[ castedKey - ] as VisitorOverrideFunction; + ] as VisitorOverrideFunction; const nextFunction = visitor[castedKey] as unknown as ( node: TNode ) => TReturn; @@ -71,7 +73,7 @@ export function extendVisitor( ], ]; }) - ) as Partial>; + ) as Partial>; return { ...visitor, diff --git a/src/visitors/flattenStructVisitor.ts b/src/visitors/flattenStructVisitor.ts index ab4eb4b21..f0f1aae33 100644 --- a/src/visitors/flattenStructVisitor.ts +++ b/src/visitors/flattenStructVisitor.ts @@ -38,8 +38,8 @@ export const flattenStruct = ( options === '*' || camelCaseOptions.includes(camelCase(field.name)); const inlinedFields = node.fields.reduce( (all, one) => { - if (isNode(one.child, 'structTypeNode') && shouldInline(one)) { - all.push(...one.child.fields); + if (isNode(one.type, 'structTypeNode') && shouldInline(one)) { + all.push(...one.type.fields); } else { all.push(one); } diff --git a/src/visitors/getByteSizeVisitor.ts b/src/visitors/getByteSizeVisitor.ts index 2777a3657..46b985b35 100644 --- a/src/visitors/getByteSizeVisitor.ts +++ b/src/visitors/getByteSizeVisitor.ts @@ -1,6 +1,6 @@ import { - REGISTERED_TYPE_NODE_KEYS, - RegisteredTypeNodes, + REGISTERED_TYPE_NODE_KINDS, + RegisteredTypeNodeKind, isNode, isScalarEnum, } from '../nodes'; @@ -9,7 +9,7 @@ import { mergeVisitor } from './mergeVisitor'; import { Visitor, visit } from './visitor'; export type ByteSizeVisitorKeys = - | keyof RegisteredTypeNodes + | RegisteredTypeNodeKind | 'definedTypeLinkNode' | 'definedTypeNode' | 'accountDataNode' @@ -32,7 +32,7 @@ export function getByteSizeVisitor( () => null as number | null, (_, values) => sumSizes(values), [ - ...REGISTERED_TYPE_NODE_KEYS, + ...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountDataNode', @@ -61,7 +61,7 @@ export function getByteSizeVisitor( return visitedDefinedTypes.get(node.name)!; } definedTypeStack.push(node.name); - const child = visit(node.data, this); + const child = visit(node.type, this); definedTypeStack.pop(); visitedDefinedTypes.set(node.name, child); return child; @@ -70,8 +70,8 @@ export function getByteSizeVisitor( visitArrayType(node) { if (!isNode(node.size, 'fixedSizeNode')) return null; const fixedSize = node.size.size; - const childSize = visit(node.child, this); - const arraySize = childSize !== null ? childSize * fixedSize : null; + const itemSize = visit(node.item, this); + const arraySize = itemSize !== null ? itemSize * fixedSize : null; return fixedSize === 0 ? 0 : arraySize; }, @@ -115,8 +115,8 @@ export function getByteSizeVisitor( visitOptionType(node) { if (!node.fixed) return null; const prefixSize = visit(node.prefix, this) as number; - const childSize = visit(node.child, this); - return childSize !== null ? childSize + prefixSize : null; + const itemSize = visit(node.item, this); + return itemSize !== null ? itemSize + prefixSize : null; }, visitBytesType(node) { diff --git a/src/visitors/getDebugStringVisitor.ts b/src/visitors/getDebugStringVisitor.ts index 725e76c49..6b891f006 100644 --- a/src/visitors/getDebugStringVisitor.ts +++ b/src/visitors/getDebugStringVisitor.ts @@ -72,7 +72,7 @@ function getNodeDetails(node: Node): string[] { case 'numberTypeNode': return [node.format, ...(node.endian === 'be' ? ['be'] : [])]; case 'amountTypeNode': - return [node.identifier, node.decimals.toString()]; + return [node.decimals.toString(), ...(node.unit ? [node.unit] : [])]; case 'stringTypeNode': return [node.encoding]; case 'fixedSizeNode': diff --git a/src/visitors/getDefaultValidatorBagVisitor.ts b/src/visitors/getDefaultValidatorBagVisitor.ts index 6af5d46e0..88965e434 100644 --- a/src/visitors/getDefaultValidatorBagVisitor.ts +++ b/src/visitors/getDefaultValidatorBagVisitor.ts @@ -102,15 +102,15 @@ export function getDefaultValidatorBagVisitor(): Visitor { } // Check arg defaults. - Object.entries(node.argDefaults).forEach(([name, defaultsTo]) => { - if (isNode(defaultsTo, 'accountBumpValueNode')) { + Object.entries(node.argDefaults).forEach(([name, defaultValue]) => { + if (isNode(defaultValue, 'accountBumpValueNode')) { const defaultAccount = node.accounts.find( - (account) => account.name === defaultsTo.name + (account) => account.name === defaultValue.name ); if (defaultAccount && defaultAccount.isSigner !== false) { bag.error( `Argument ${name} cannot default to the bump attribute of ` + - `the [${defaultsTo.name}] account as it may be a Signer.`, + `the [${defaultValue.name}] account as it may be a Signer.`, node, stack ); @@ -225,7 +225,7 @@ export function getDefaultValidatorBagVisitor(): Visitor { visitTupleType(node, { next }) { const bag = new ValidatorBag(); - if (node.children.length === 0) { + if (node.items.length === 0) { bag.warn('Tuple has no items.', node, stack); } return bag.mergeWith([next(node)]); diff --git a/src/visitors/getDefinedTypeHistogramVisitor.ts b/src/visitors/getDefinedTypeHistogramVisitor.ts index 0ff8b5f0e..022ce0af6 100644 --- a/src/visitors/getDefinedTypeHistogramVisitor.ts +++ b/src/visitors/getDefinedTypeHistogramVisitor.ts @@ -85,7 +85,7 @@ export function getDefinedTypeHistogramVisitor(): Visitor visitDefinedType(node, { self }) { mode = 'definedType'; stackLevel = 0; - const histogram = visit(node.data, self); + const histogram = visit(node.type, self); mode = null; return histogram; }, diff --git a/src/visitors/getResolvedInstructionInputsVisitor.ts b/src/visitors/getResolvedInstructionInputsVisitor.ts index 6552d24de..18b7842c3 100644 --- a/src/visitors/getResolvedInstructionInputsVisitor.ts +++ b/src/visitors/getResolvedInstructionInputsVisitor.ts @@ -15,7 +15,7 @@ type InstructionInput = InstructionArgument | InstructionAccountNode; type InstructionArgument = { kind: 'argument'; name: string; - defaultsTo: InstructionInputValueNode; + defaultValue: InstructionInputValueNode; }; type InstructionDependency = ArgumentValueNode | AccountValueNode; @@ -104,10 +104,10 @@ export function getResolvedInstructionInputsVisitor(): Visitor< resolvedIsOptional: account.isOptional, }; - switch (localResolved.defaultsTo?.kind) { + switch (localResolved.defaultValue?.kind) { case 'accountValueNode': const defaultAccount = visitedAccounts.get( - localResolved.defaultsTo.name + localResolved.defaultValue.name )!; const resolvedIsPublicKey = account.isSigner === false && defaultAccount.isSigner === false; @@ -131,14 +131,13 @@ export function getResolvedInstructionInputsVisitor(): Visitor< localResolved.resolvedIsSigner = account.isSigner === false ? false : 'either'; localResolved.resolvedIsOptional = false; - const { seeds } = localResolved.defaultsTo; - Object.keys(seeds).forEach((seedKey) => { - const seed = seeds[seedKey as MainCaseString]; - if (!isNode(seed, 'accountValueNode')) return; - const dependency = visitedAccounts.get(seed.name)!; + const { seeds } = localResolved.defaultValue; + seeds.forEach((seed) => { + if (!isNode(seed.value, 'accountValueNode')) return; + const dependency = visitedAccounts.get(seed.value.name)!; if (dependency.resolvedIsOptional) { const error = - `Cannot use optional account "${seed.name}" as the "${seedKey}" PDA seed ` + + `Cannot use optional account "${seed.value.name}" as the "${seed.name}" PDA seed ` + `for the "${account.name}" account of the "${instruction.name}" instruction.`; throw new Error(error); } @@ -191,7 +190,7 @@ export function getResolvedInstructionInputsVisitor(): Visitor< input = { kind: 'argument', name: dependency.name, - defaultsTo: dependencyArg, + defaultValue: dependencyArg, }; } } @@ -204,40 +203,40 @@ export function getResolvedInstructionInputsVisitor(): Visitor< function getInstructionDependencies( input: InstructionInput ): InstructionDependency[] { - if (!input.defaultsTo) return []; + if (!input.defaultValue) return []; const getNestedDependencies = ( - defaultsTo: InstructionInputValueNode | undefined + defaultValue: InstructionInputValueNode | undefined ): InstructionDependency[] => { - if (!defaultsTo) return []; - return getInstructionDependencies({ ...input, defaultsTo }); + if (!defaultValue) return []; + return getInstructionDependencies({ ...input, defaultValue }); }; if ( - isNode(input.defaultsTo, ['accountValueNode', 'accountBumpValueNode']) + isNode(input.defaultValue, ['accountValueNode', 'accountBumpValueNode']) ) { - return [accountValueNode(input.defaultsTo.name)]; + return [accountValueNode(input.defaultValue.name)]; } - if (isNode(input.defaultsTo, 'pdaValueNode')) { + if (isNode(input.defaultValue, 'pdaValueNode')) { const dependencies = new Map(); - Object.values(input.defaultsTo.seeds).forEach((seed) => { - if (isNode(seed, ['accountValueNode', 'argumentValueNode'])) { - dependencies.set(seed.name, { ...seed }); + input.defaultValue.seeds.forEach((seed) => { + if (isNode(seed.value, ['accountValueNode', 'argumentValueNode'])) { + dependencies.set(seed.value.name, { ...seed.value }); } }); return [...dependencies.values()]; } - if (isNode(input.defaultsTo, 'resolverValueNode')) { - return input.defaultsTo.dependsOn ?? []; + if (isNode(input.defaultValue, 'resolverValueNode')) { + return input.defaultValue.dependsOn ?? []; } - if (isNode(input.defaultsTo, 'conditionalValueNode')) { + if (isNode(input.defaultValue, 'conditionalValueNode')) { return [ - ...getNestedDependencies(input.defaultsTo.condition), - ...getNestedDependencies(input.defaultsTo.ifTrue), - ...getNestedDependencies(input.defaultsTo.ifFalse), + ...getNestedDependencies(input.defaultValue.condition), + ...getNestedDependencies(input.defaultValue.ifTrue), + ...getNestedDependencies(input.defaultValue.ifFalse), ]; } @@ -258,7 +257,7 @@ export function getResolvedInstructionInputsVisitor(): Visitor< ...Object.entries(node.argDefaults).map(([argName, argDefault]) => ({ kind: 'argument' as const, name: argName, - defaultsTo: argDefault, + defaultValue: argDefault, })), ]; diff --git a/src/visitors/identityVisitor.ts b/src/visitors/identityVisitor.ts index a76b738df..41c581e7e 100644 --- a/src/visitors/identityVisitor.ts +++ b/src/visitors/identityVisitor.ts @@ -2,9 +2,9 @@ import { CONDITIONAL_VALUE_BRANCH_NODES, ENUM_VARIANT_TYPE_NODES, Node, + NodeKind, PDA_SEED_NODES, - REGISTERED_NODES_KEYS, - RegisteredNodes, + REGISTERED_NODE_KINDS, SIZE_NODES, TYPE_NODES, VALUE_NODES, @@ -27,10 +27,12 @@ import { instructionDataArgsNode, instructionExtraArgsNode, instructionNode, + mapEntryValueNode, mapTypeNode, mapValueNode, optionTypeNode, pdaNode, + pdaSeedValueNode, pdaValueNode, prefixedSizeNode, programNode, @@ -43,6 +45,7 @@ import { someValueNode, stringTypeNode, structFieldTypeNode, + structFieldValueNode, structTypeNode, structValueNode, tupleTypeNode, @@ -52,12 +55,10 @@ import { import { staticVisitor } from './staticVisitor'; import { Visitor, visit as baseVisit } from './visitor'; -export function identityVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->( - nodeKeys: TNodeKeys[] = REGISTERED_NODES_KEYS as TNodeKeys[] -): Visitor { - const castedNodeKeys: (keyof RegisteredNodes)[] = nodeKeys; +export function identityVisitor( + nodeKeys: TNodeKind[] = REGISTERED_NODE_KINDS as TNodeKind[] +): Visitor { + const castedNodeKeys: NodeKind[] = nodeKeys; const visitor = staticVisitor( (node) => ({ ...node }), castedNodeKeys @@ -181,10 +182,10 @@ export function identityVisitor< if (castedNodeKeys.includes('definedTypeNode')) { visitor.visitDefinedType = function visitDefinedType(node) { - const data = visit(this)(node.data); - if (data === null) return null; - assertIsNode(data, TYPE_NODES); - return definedTypeNode({ ...node, data }); + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + return definedTypeNode({ ...node, type }); }; } @@ -193,10 +194,10 @@ export function identityVisitor< const size = visit(this)(node.size); if (size === null) return null; assertIsNode(size, SIZE_NODES); - const child = visit(this)(node.child); - if (child === null) return null; - assertIsNode(child, TYPE_NODES); - return arrayTypeNode(child, { size }); + const item = visit(this)(node.item); + if (item === null) return null; + assertIsNode(item, TYPE_NODES); + return arrayTypeNode(item, size); }; } @@ -244,7 +245,7 @@ export function identityVisitor< const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, TYPE_NODES); - return mapTypeNode(key, value, { ...node, size }); + return mapTypeNode(key, value, size, node.idlMap); }; } @@ -253,10 +254,10 @@ export function identityVisitor< const prefix = visit(this)(node.prefix); if (prefix === null) return null; assertIsNode(prefix, 'numberTypeNode'); - const child = visit(this)(node.child); - if (child === null) return null; - assertIsNode(child, TYPE_NODES); - return optionTypeNode(child, { ...node, prefix }); + const item = visit(this)(node.item); + if (item === null) return null; + assertIsNode(item, TYPE_NODES); + return optionTypeNode(item, { ...node, prefix }); }; } @@ -274,10 +275,10 @@ export function identityVisitor< const size = visit(this)(node.size); if (size === null) return null; assertIsNode(size, SIZE_NODES); - const child = visit(this)(node.child); - if (child === null) return null; - assertIsNode(child, TYPE_NODES); - return setTypeNode(child, { ...node, size }); + const item = visit(this)(node.item); + if (item === null) return null; + assertIsNode(item, TYPE_NODES); + return setTypeNode(item, size, node.idlSet); }; } @@ -293,27 +294,21 @@ export function identityVisitor< if (castedNodeKeys.includes('structFieldTypeNode')) { visitor.visitStructFieldType = function visitStructFieldType(node) { - const child = visit(this)(node.child); - if (child === null) return null; - assertIsNode(child, TYPE_NODES); - const defaultsToValue = node.defaultsTo?.value - ? visit(this)(node.defaultsTo.value) - : null; - if (defaultsToValue) assertIsNode(defaultsToValue, VALUE_NODES); - const defaultsTo = defaultsToValue - ? { - strategy: node.defaultsTo?.strategy ?? 'optional', - value: defaultsToValue, - } + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + const defaultValue = node.defaultValue + ? visit(this)(node.defaultValue) ?? undefined : undefined; - return structFieldTypeNode({ ...node, child, defaultsTo }); + if (defaultValue) assertIsNode(defaultValue, VALUE_NODES); + return structFieldTypeNode({ ...node, type, defaultValue }); }; } if (castedNodeKeys.includes('tupleTypeNode')) { visitor.visitTupleType = function visitTupleType(node) { return tupleTypeNode( - node.children + node.items .map((child) => visit(this)(child)) .filter(removeNullAndAssertIsNodeFilter(TYPE_NODES)) ); @@ -343,7 +338,7 @@ export function identityVisitor< const number = visit(this)(node.number); if (number === null) return null; assertIsNode(number, 'numberTypeNode'); - return amountTypeNode(number, node.identifier, node.decimals); + return amountTypeNode(number, node.decimals, node.unit); }; } @@ -386,30 +381,40 @@ export function identityVisitor< if (castedNodeKeys.includes('enumValueNode')) { visitor.visitEnumValue = function visitEnumValue(node) { + const enumLink = visit(this)(node.enum); + if (enumLink === null) return null; + assertIsNode(enumLink, ['definedTypeLinkNode']); if (typeof node.value === 'string') return { ...node }; - const value = visit(this)(node.value); - if (value === null) return null; - assertIsNode(value, ['structValueNode', 'tupleValueNode']); - return enumValueNode(node.enumType, node.variant, value, node.importFrom); + const value = node.value ? visit(this)(node.value) : null; + if (value !== null) { + assertIsNode(value, ['structValueNode', 'tupleValueNode']); + } + return enumValueNode(enumLink, node.variant, value ?? undefined); }; } if (castedNodeKeys.includes('mapValueNode')) { visitor.visitMapValue = function visitMapValue(node) { return mapValueNode( - node.entries.flatMap(([k, v]) => { - const key = visit(this)(k); - if (key === null) return []; - assertIsNode(key, VALUE_NODES); - const value = visit(this)(v); - if (value === null) return []; - assertIsNode(value, VALUE_NODES); - return [[key, value]]; - }) + node.entries + .map(visit(this)) + .filter(removeNullAndAssertIsNodeFilter('mapEntryValueNode')) ); }; } + if (castedNodeKeys.includes('mapEntryValueNode')) { + visitor.visitMapEntryValue = function visitMapEntryValue(node) { + const key = visit(this)(node.key); + if (key === null) return null; + assertIsNode(key, VALUE_NODES); + const value = visit(this)(node.value); + if (value === null) return null; + assertIsNode(value, VALUE_NODES); + return mapEntryValueNode(key, value); + }; + } + if (castedNodeKeys.includes('setValueNode')) { visitor.visitSetValue = function visitSetValue(node) { return setValueNode( @@ -432,18 +437,22 @@ export function identityVisitor< if (castedNodeKeys.includes('structValueNode')) { visitor.visitStructValue = function visitStructValue(node) { return structValueNode( - Object.fromEntries( - Object.entries(node.fields).flatMap(([k, v]) => { - const value = visit(this)(v); - if (value === null) return []; - assertIsNode(value, VALUE_NODES); - return [[k, value]]; - }) - ) + node.fields + .map(visit(this)) + .filter(removeNullAndAssertIsNodeFilter('structFieldValueNode')) ); }; } + if (castedNodeKeys.includes('structFieldValueNode')) { + visitor.visitStructFieldValue = function visitStructFieldValue(node) { + const value = visit(this)(node.value); + if (value === null) return null; + assertIsNode(value, VALUE_NODES); + return structFieldValueNode(node.name, value); + }; + } + if (castedNodeKeys.includes('tupleValueNode')) { visitor.visitTupleValue = function visitTupleValue(node) { return tupleValueNode( @@ -521,23 +530,25 @@ export function identityVisitor< const pda = visit(this)(node.pda); if (pda === null) return null; assertIsNode(pda, 'pdaLinkNode'); - return pdaValueNode( - pda, - Object.fromEntries( - Object.entries(node.seeds).flatMap(([k, v]) => { - const value = visit(this)(v); - if (value === null) return []; - assertIsNode(value, [ - ...VALUE_NODES, - 'accountValueNode', - 'argumentValueNode', - ]); - return [[k, value]]; - }) - ) - ); + const seeds = node.seeds + .map(visit(this)) + .filter(removeNullAndAssertIsNodeFilter('pdaSeedValueNode')); + return pdaValueNode(pda, seeds); + }; + } + + if (castedNodeKeys.includes('pdaSeedValueNode')) { + visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { + const value = visit(this)(node.value); + if (value === null) return null; + assertIsNode(value, [ + ...VALUE_NODES, + 'accountValueNode', + 'argumentValueNode', + ]); + return pdaSeedValueNode(node.name, value); }; } - return visitor as Visitor; + return visitor as Visitor; } diff --git a/src/visitors/interceptVisitor.ts b/src/visitors/interceptVisitor.ts index b2bf68ba3..da92b367d 100644 --- a/src/visitors/interceptVisitor.ts +++ b/src/visitors/interceptVisitor.ts @@ -1,4 +1,4 @@ -import { Node, REGISTERED_NODES_KEYS, RegisteredNodes } from '../nodes'; +import { Node, NodeKind, REGISTERED_NODE_KINDS } from '../nodes'; import { GetVisitorFunctionName, Visitor, @@ -10,28 +10,25 @@ export type VisitorInterceptor = ( next: (node: TNode) => TReturn ) => TReturn; -export function interceptVisitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes ->( - visitor: Visitor, +export function interceptVisitor( + visitor: Visitor, interceptor: VisitorInterceptor -): Visitor { +): Visitor { const registeredVisitFunctions = - REGISTERED_NODES_KEYS.map(getVisitFunctionName); + REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap((key) => { if (!(registeredVisitFunctions as string[]).includes(key)) { return []; } - const castedKey = key as GetVisitorFunctionName; + const castedKey = key as GetVisitorFunctionName; return [ [ castedKey, function interceptedVisitNode( - this: Visitor, + this: Visitor, node: TNode ) { const baseFunction = visitor[castedKey] as unknown as ( @@ -42,5 +39,5 @@ export function interceptVisitor< ], ]; }) - ) as Visitor; + ) as Visitor; } diff --git a/src/visitors/mapVisitor.ts b/src/visitors/mapVisitor.ts index ac775c187..a95fb19f2 100644 --- a/src/visitors/mapVisitor.ts +++ b/src/visitors/mapVisitor.ts @@ -1,20 +1,16 @@ -import { REGISTERED_NODES_KEYS, RegisteredNodes } from '../nodes'; +import { NodeDictionary, NodeKind, REGISTERED_NODE_KINDS } from '../nodes'; import { GetVisitorFunctionName, Visitor, getVisitFunctionName, } from './visitor'; -export function mapVisitor< - TReturnFrom, - TReturnTo, - TNodeKeys extends keyof RegisteredNodes ->( - visitor: Visitor, +export function mapVisitor( + visitor: Visitor, map: (from: TReturnFrom) => TReturnTo -): Visitor { +): Visitor { const registeredVisitFunctions = - REGISTERED_NODES_KEYS.map(getVisitFunctionName); + REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap((key) => { if (!(registeredVisitFunctions as string[]).includes(key)) { @@ -24,14 +20,14 @@ export function mapVisitor< return [ [ key, - (node: RegisteredNodes[TNodeKeys]) => + (node: NodeDictionary[TNodeKind]) => map( - (visitor[key as GetVisitorFunctionName] as Function)( + (visitor[key as GetVisitorFunctionName] as Function)( node ) ), ], ]; }) - ) as unknown as Visitor; + ) as unknown as Visitor; } diff --git a/src/visitors/mergeVisitor.ts b/src/visitors/mergeVisitor.ts index 3e91dd3ae..c0cadb045 100644 --- a/src/visitors/mergeVisitor.ts +++ b/src/visitors/mergeVisitor.ts @@ -1,16 +1,13 @@ -import { Node, REGISTERED_NODES_KEYS, RegisteredNodes } from '../nodes'; -import { Visitor, visit as baseVisit } from './visitor'; +import { Node, NodeKind, REGISTERED_NODE_KINDS } from '../nodes'; import { staticVisitor } from './staticVisitor'; +import { Visitor, visit as baseVisit } from './visitor'; -export function mergeVisitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->( +export function mergeVisitor( leafValue: (node: Node) => TReturn, merge: (node: Node, values: TReturn[]) => TReturn, - nodeKeys: TNodeKeys[] = REGISTERED_NODES_KEYS as TNodeKeys[] -): Visitor { - const castedNodeKeys: (keyof RegisteredNodes)[] = nodeKeys; + nodeKeys: TNodeKind[] = REGISTERED_NODE_KINDS as TNodeKind[] +): Visitor { + const castedNodeKeys: NodeKind[] = nodeKeys; const visitor = staticVisitor(leafValue, castedNodeKeys) as Visitor; const visit = (v: Visitor) => @@ -92,7 +89,7 @@ export function mergeVisitor< if (castedNodeKeys.includes('definedTypeNode')) { visitor.visitDefinedType = function visitDefinedType(node) { - return merge(node, visit(this)(node.data)); + return merge(node, visit(this)(node.type)); }; } @@ -100,7 +97,7 @@ export function mergeVisitor< visitor.visitArrayType = function visitArrayType(node) { return merge(node, [ ...visit(this)(node.size), - ...visit(this)(node.child), + ...visit(this)(node.item), ]); }; } @@ -144,7 +141,7 @@ export function mergeVisitor< visitor.visitOptionType = function visitOptionType(node) { return merge(node, [ ...visit(this)(node.prefix), - ...visit(this)(node.child), + ...visit(this)(node.item), ]); }; } @@ -159,7 +156,7 @@ export function mergeVisitor< visitor.visitSetType = function visitSetType(node) { return merge(node, [ ...visit(this)(node.size), - ...visit(this)(node.child), + ...visit(this)(node.item), ]); }; } @@ -173,15 +170,15 @@ export function mergeVisitor< if (castedNodeKeys.includes('structFieldTypeNode')) { visitor.visitStructFieldType = function visitStructFieldType(node) { return merge(node, [ - ...visit(this)(node.child), - ...(node.defaultsTo ? visit(this)(node.defaultsTo.value) : []), + ...visit(this)(node.type), + ...(node.defaultValue ? visit(this)(node.defaultValue) : []), ]); }; } if (castedNodeKeys.includes('tupleTypeNode')) { visitor.visitTupleType = function visitTupleType(node) { - return merge(node, node.children.flatMap(visit(this))); + return merge(node, node.items.flatMap(visit(this))); }; } @@ -229,18 +226,25 @@ export function mergeVisitor< if (castedNodeKeys.includes('enumValueNode')) { visitor.visitEnumValue = function visitEnumValue(node) { - return typeof node.value === 'string' - ? leafValue(node) - : merge(node, visit(this)(node.value)); + return merge(node, [ + ...visit(this)(node.enum), + ...(node.value ? visit(this)(node.value) : []), + ]); }; } if (castedNodeKeys.includes('mapValueNode')) { visitor.visitMapValue = function visitMapValue(node) { - return merge( - node, - node.entries.flatMap(([k, v]) => [...visit(this)(k), ...visit(this)(v)]) - ); + return merge(node, node.entries.flatMap(visit(this))); + }; + } + + if (castedNodeKeys.includes('mapEntryValueNode')) { + visitor.visitMapEntryValue = function visitMapEntryValue(node) { + return merge(node, [ + ...visit(this)(node.key), + ...visit(this)(node.value), + ]); }; } @@ -258,7 +262,13 @@ export function mergeVisitor< if (castedNodeKeys.includes('structValueNode')) { visitor.visitStructValue = function visitStructValue(node) { - return merge(node, Object.values(node.fields).flatMap(visit(this))); + return merge(node, node.fields.flatMap(visit(this))); + }; + } + + if (castedNodeKeys.includes('structFieldValueNode')) { + visitor.visitStructFieldValue = function visitStructFieldValue(node) { + return merge(node, visit(this)(node.value)); }; } @@ -304,10 +314,16 @@ export function mergeVisitor< visitor.visitPdaValue = function visitPdaValue(node) { return merge(node, [ ...visit(this)(node.pda), - ...Object.values(node.seeds).flatMap(visit(this)), + ...node.seeds.flatMap(visit(this)), ]); }; } - return visitor as Visitor; + if (castedNodeKeys.includes('pdaSeedValueNode')) { + visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { + return merge(node, visit(this)(node.value)); + }; + } + + return visitor as Visitor; } diff --git a/src/visitors/recordLinkablesVisitor.ts b/src/visitors/recordLinkablesVisitor.ts index 49b61ee58..80cc1710c 100644 --- a/src/visitors/recordLinkablesVisitor.ts +++ b/src/visitors/recordLinkablesVisitor.ts @@ -1,5 +1,5 @@ import { - RegisteredNodes, + NodeKind, getAllAccounts, getAllDefinedTypes, getAllPdas, @@ -8,13 +8,10 @@ import { LinkableDictionary } from '../shared'; import { VisitorOverrides, extendVisitor } from './extendVisitor'; import { Visitor } from './visitor'; -export function recordLinkablesVisitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes ->( - visitor: Visitor, +export function recordLinkablesVisitor( + visitor: Visitor, linkables: LinkableDictionary -): Visitor { +): Visitor { const overriddenFunctions: VisitorOverrides< TReturn, 'rootNode' | 'programNode' | 'pdaNode' | 'accountNode' | 'definedTypeNode' @@ -64,6 +61,6 @@ export function recordLinkablesVisitor< } return extendVisitor( visitor, - overriddenFunctions as VisitorOverrides + overriddenFunctions as VisitorOverrides ); } diff --git a/src/visitors/recordNodeStackVisitor.ts b/src/visitors/recordNodeStackVisitor.ts index 3a0e649bf..9d3e0ea13 100644 --- a/src/visitors/recordNodeStackVisitor.ts +++ b/src/visitors/recordNodeStackVisitor.ts @@ -1,15 +1,12 @@ -import { RegisteredNodes } from '../nodes'; +import { NodeKind } from '../nodes'; import { NodeStack } from '../shared'; import { interceptVisitor } from './interceptVisitor'; import { Visitor } from './visitor'; -export function recordNodeStackVisitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes ->( - visitor: Visitor, +export function recordNodeStackVisitor( + visitor: Visitor, stack: NodeStack -): Visitor { +): Visitor { return interceptVisitor(visitor, (node, next) => { stack.push(node); const newNode = next(node); diff --git a/src/visitors/removeDocsVisitor.ts b/src/visitors/removeDocsVisitor.ts index 5b0a861b4..78eef86cc 100644 --- a/src/visitors/removeDocsVisitor.ts +++ b/src/visitors/removeDocsVisitor.ts @@ -1,10 +1,10 @@ -import { RegisteredNodes } from '../nodes'; +import { NodeKind } from '../nodes'; import { identityVisitor } from './identityVisitor'; import { interceptVisitor } from './interceptVisitor'; -export function removeDocsVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->(nodeKeys?: TNodeKeys[]) { +export function removeDocsVisitor( + nodeKeys?: TNodeKind[] +) { return interceptVisitor(identityVisitor(nodeKeys), (node, next) => { if ('docs' in node) { return { ...node, docs: [] }; diff --git a/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts b/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts index 361e30f9c..e0f73f82a 100644 --- a/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts +++ b/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts @@ -47,7 +47,8 @@ export function setAccountDiscriminatorFromFieldVisitor( ...node.data.struct.fields.slice(0, fieldIndex), structFieldTypeNode({ ...fieldNode, - defaultsTo: { strategy: 'omitted', value }, + defaultValue: value, + defaultValueStrategy: 'omitted', }), ...node.data.struct.fields.slice(fieldIndex + 1), ]), diff --git a/src/visitors/setAnchorDiscriminatorsVisitor.ts b/src/visitors/setAnchorDiscriminatorsVisitor.ts index ae605062b..344f976e6 100644 --- a/src/visitors/setAnchorDiscriminatorsVisitor.ts +++ b/src/visitors/setAnchorDiscriminatorsVisitor.ts @@ -43,13 +43,9 @@ export function setAnchorDiscriminatorsVisitor() { const discriminatorField = structFieldTypeNode({ name: 'discriminator', - child: arrayTypeNode(numberTypeNode('u8'), { - size: fixedSizeNode(8), - }), - defaultsTo: { - strategy: 'omitted', - value: getAnchorAccountDiscriminator(node.idlName), - }, + type: arrayTypeNode(numberTypeNode('u8'), fixedSizeNode(8)), + defaultValue: getAnchorAccountDiscriminator(node.idlName), + defaultValueStrategy: 'omitted', }); return accountNode({ @@ -71,13 +67,9 @@ export function setAnchorDiscriminatorsVisitor() { const discriminatorField = structFieldTypeNode({ name: 'discriminator', - child: arrayTypeNode(numberTypeNode('u8'), { - size: fixedSizeNode(8), - }), - defaultsTo: { - strategy: 'omitted', - value: getAnchorInstructionDiscriminator(node.idlName), - }, + type: arrayTypeNode(numberTypeNode('u8'), fixedSizeNode(8)), + defaultValue: getAnchorInstructionDiscriminator(node.idlName), + defaultValueStrategy: 'omitted', }); return instructionNode({ diff --git a/src/visitors/setInstructionAccountDefaultValuesVisitor.ts b/src/visitors/setInstructionAccountDefaultValuesVisitor.ts index 8426ab077..a41cf6ecb 100644 --- a/src/visitors/setInstructionAccountDefaultValuesVisitor.ts +++ b/src/visitors/setInstructionAccountDefaultValuesVisitor.ts @@ -2,12 +2,12 @@ import { InstructionAccountNode, InstructionNode, VALUE_NODES, - getDefaultSeedValuesFromPda, instructionNode, isNode, } from '../nodes'; import { InstructionInputValueNode, + addDefaultSeedValuesFromPdaWhenMissing, identityValueNode, payerValueNode, programIdValueNode, @@ -22,7 +22,7 @@ export type InstructionAccountDefaultRule = { /** The name of the instruction account or a pattern to match on it. */ account: string | RegExp; /** The default value to assign to it. */ - defaultsTo: InstructionInputValueNode; + defaultValue: InstructionInputValueNode; /** @defaultValue Defaults to searching accounts on all instructions. */ instruction?: string; /** @defaultValue `false`. */ @@ -33,41 +33,41 @@ export const DEFAULT_INSTRUCTION_ACCOUNT_DEFAULT_RULES: InstructionAccountDefaul [ { account: /^payer|feePayer$/, - defaultsTo: payerValueNode(), + defaultValue: payerValueNode(), ignoreIfOptional: true, }, { account: /^authority$/, - defaultsTo: identityValueNode(), + defaultValue: identityValueNode(), ignoreIfOptional: true, }, { account: /^programId$/, - defaultsTo: programIdValueNode(), + defaultValue: programIdValueNode(), ignoreIfOptional: true, }, { account: /^systemProgram|splSystemProgram$/, - defaultsTo: publicKeyValueNode('11111111111111111111111111111111'), + defaultValue: publicKeyValueNode('11111111111111111111111111111111'), ignoreIfOptional: true, }, { account: /^tokenProgram|splTokenProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ), ignoreIfOptional: true, }, { account: /^ataProgram|splAtaProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' ), ignoreIfOptional: true, }, { account: /^tokenMetadataProgram|mplTokenMetadataProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s' ), ignoreIfOptional: true, @@ -75,84 +75,84 @@ export const DEFAULT_INSTRUCTION_ACCOUNT_DEFAULT_RULES: InstructionAccountDefaul { account: /^(tokenAuth|mplTokenAuth|authorization|mplAuthorization|auth|mplAuth)RulesProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg' ), ignoreIfOptional: true, }, { account: /^candyMachineProgram|mplCandyMachineProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR' ), ignoreIfOptional: true, }, { account: /^candyGuardProgram|mplCandyGuardProgram$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g' ), ignoreIfOptional: true, }, { account: /^clockSysvar|sysvarClock$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarC1ock11111111111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^epochScheduleSysvar|sysvarEpochSchedule$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarEpochSchedu1e111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^(instructions?Sysvar|sysvarInstructions?)(Account)?$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'Sysvar1nstructions1111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^recentBlockhashesSysvar|sysvarRecentBlockhashes$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarRecentB1ockHashes11111111111111111111' ), ignoreIfOptional: true, }, { account: /^rent|rentSysvar|sysvarRent$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarRent111111111111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^rewardsSysvar|sysvarRewards$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarRewards111111111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^slotHashesSysvar|sysvarSlotHashes$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarS1otHashes111111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^slotHistorySysvar|sysvarSlotHistory$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarS1otHistory11111111111111111111111111' ), ignoreIfOptional: true, }, { account: /^stakeHistorySysvar|sysvarStakeHistory$/, - defaultsTo: publicKeyValueNode( + defaultValue: publicKeyValueNode( 'SysvarStakeHistory1111111111111111111111111' ), ignoreIfOptional: true, @@ -204,48 +204,46 @@ export function setInstructionAccountDefaultValuesVisitor( } if ( (rule.ignoreIfOptional ?? false) && - (account.isOptional || !!account.defaultsTo) + (account.isOptional || !!account.defaultValue) ) { return account; } - if (isNode(rule.defaultsTo, 'pdaValueNode')) { - const foundAccount = linkables.get(rule.defaultsTo.pda); - const defaultsTo = { - ...rule.defaultsTo, - seeds: { - ...(foundAccount - ? getDefaultSeedValuesFromPda(foundAccount) - : {}), - ...rule.defaultsTo.seeds, - }, + if (isNode(rule.defaultValue, 'pdaValueNode')) { + const foundPda = linkables.get(rule.defaultValue.pda); + const defaultValue = { + ...rule.defaultValue, + seeds: foundPda + ? addDefaultSeedValuesFromPdaWhenMissing( + foundPda, + rule.defaultValue.seeds + ) + : rule.defaultValue.seeds, }; if (rule.instruction) { - return { ...account, defaultsTo }; + return { ...account, defaultValue }; } - const allSeedsAreValid = Object.entries(defaultsTo.seeds).every( - ([, seed]) => { - if (isNode(seed, VALUE_NODES)) return true; - if (isNode(seed, 'accountValueNode')) { - return node.accounts.some( - (a) => a.name === mainCase(seed.name) - ); - } - if (node.dataArgs.link) return true; - return node.dataArgs.struct.fields.some( - (f) => f.name === mainCase(seed.name) + const allSeedsAreValid = defaultValue.seeds.every((seed) => { + if (isNode(seed.value, VALUE_NODES)) return true; + if (isNode(seed.value, 'accountValueNode')) { + return node.accounts.some( + (a) => a.name === mainCase(seed.name) ); } - ); + if (node.dataArgs.link) return true; + return node.dataArgs.struct.fields.some( + (f) => f.name === mainCase(seed.name) + ); + }); if (allSeedsAreValid) { - return { ...account, defaultsTo }; + return { ...account, defaultValue }; } return account; } - return { ...account, defaultsTo: rule.defaultsTo }; + return { ...account, defaultValue: rule.defaultValue }; } ); diff --git a/src/visitors/setInstructionDiscriminatorsVisitor.ts b/src/visitors/setInstructionDiscriminatorsVisitor.ts index b7cbfb37c..e8b07f16f 100644 --- a/src/visitors/setInstructionDiscriminatorsVisitor.ts +++ b/src/visitors/setInstructionDiscriminatorsVisitor.ts @@ -39,12 +39,10 @@ export function setInstructionDiscriminatorsVisitor( assertIsNode(node, 'instructionNode'); const discriminatorField = structFieldTypeNode({ name: discriminator.name ?? 'discriminator', - child: discriminator.type ?? numberTypeNode('u8'), + type: discriminator.type ?? numberTypeNode('u8'), docs: discriminator.docs ?? [], - defaultsTo: { - strategy: discriminator.strategy ?? 'omitted', - value: discriminator.value, - }, + defaultValue: discriminator.value, + defaultValueStrategy: discriminator.strategy ?? 'omitted', }); return instructionNode({ diff --git a/src/visitors/setNumberWrappersVisitor.ts b/src/visitors/setNumberWrappersVisitor.ts index 7eb4bfe20..d1f9b2a59 100644 --- a/src/visitors/setNumberWrappersVisitor.ts +++ b/src/visitors/setNumberWrappersVisitor.ts @@ -12,7 +12,7 @@ import { export type NumberWrapper = | { kind: 'DateTime' } | { kind: 'SolAmount' } - | { kind: 'Amount'; identifier: string; decimals: number }; + | { kind: 'Amount'; decimals: number; unit?: string }; type NumberWrapperMap = Record; @@ -29,7 +29,7 @@ export function setNumberWrappersVisitor(map: NumberWrapperMap) { case 'SolAmount': return solAmountTypeNode(node); case 'Amount': - return amountTypeNode(node, wrapper.identifier, wrapper.decimals); + return amountTypeNode(node, wrapper.decimals, wrapper.unit); default: throw new Error(`Invalid number wrapper kind: ${wrapper}`); } diff --git a/src/visitors/setStructDefaultValuesVisitor.ts b/src/visitors/setStructDefaultValuesVisitor.ts index 4562f614b..92f14f831 100644 --- a/src/visitors/setStructDefaultValuesVisitor.ts +++ b/src/visitors/setStructDefaultValuesVisitor.ts @@ -12,7 +12,8 @@ import { type StructDefaultValueMap = Record>; type StructDefaultValue = - | (ValueNode & { strategy?: 'optional' | 'omitted' }) + | ValueNode + | { value: ValueNode; strategy?: 'optional' | 'omitted' } | null; export function setStructDefaultValuesVisitor(map: StructDefaultValueMap) { @@ -25,14 +26,19 @@ export function setStructDefaultValuesVisitor(map: StructDefaultValueMap) { const fields = node.fields.map((field): StructFieldTypeNode => { const defaultValue = defaultValues[field.name]; if (defaultValue === undefined) return field; + if (defaultValue === null) { + return structFieldTypeNode({ + ...field, + defaultValue: undefined, + defaultValueStrategy: undefined, + }); + } return structFieldTypeNode({ ...field, - defaultsTo: !defaultValue - ? null - : { - strategy: defaultValue.strategy ?? 'optional', - value: defaultValue, - }, + defaultValue: + 'kind' in defaultValue ? defaultValue : defaultValue.value, + defaultValueStrategy: + 'kind' in defaultValue ? undefined : defaultValue.strategy, }); }); return structTypeNode(fields); diff --git a/src/visitors/singleNodeVisitor.ts b/src/visitors/singleNodeVisitor.ts index 6db6a4ad1..f201cd15e 100644 --- a/src/visitors/singleNodeVisitor.ts +++ b/src/visitors/singleNodeVisitor.ts @@ -1,4 +1,4 @@ -import { RegisteredNodes, RootNode } from '../nodes'; +import { NodeDictionary, NodeKind, RootNode } from '../nodes'; import { GetVisitorFunctionName, Visitor, @@ -7,10 +7,10 @@ import { export function singleNodeVisitor< TReturn, - TNodeKey extends keyof RegisteredNodes = keyof RegisteredNodes + TNodeKey extends NodeKind = NodeKind >( key: TNodeKey, - fn: (node: RegisteredNodes[TNodeKey]) => TReturn + fn: (node: NodeDictionary[TNodeKey]) => TReturn ): Visitor { const visitor = {} as Visitor; visitor[getVisitFunctionName(key)] = fn as unknown as Visitor< diff --git a/src/visitors/staticVisitor.ts b/src/visitors/staticVisitor.ts index e5260643d..82173e009 100644 --- a/src/visitors/staticVisitor.ts +++ b/src/visitors/staticVisitor.ts @@ -1,13 +1,10 @@ -import { Node, REGISTERED_NODES_KEYS, RegisteredNodes } from '../nodes'; +import { Node, NodeKind, REGISTERED_NODE_KINDS } from '../nodes'; import { Visitor, getVisitFunctionName } from './visitor'; -export function staticVisitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->( +export function staticVisitor( fn: (node: Node) => TReturn, - nodeKeys: TNodeKeys[] = REGISTERED_NODES_KEYS as TNodeKeys[] -): Visitor { + nodeKeys: TNodeKind[] = REGISTERED_NODE_KINDS as TNodeKind[] +): Visitor { const visitor = {} as Visitor; nodeKeys.forEach((key) => { visitor[getVisitFunctionName(key)] = fn.bind(visitor); diff --git a/src/visitors/tapVisitor.ts b/src/visitors/tapVisitor.ts index 8c3f8514a..9e4db3800 100644 --- a/src/visitors/tapVisitor.ts +++ b/src/visitors/tapVisitor.ts @@ -1,4 +1,4 @@ -import { RegisteredNodes } from '../nodes'; +import { NodeDictionary, NodeKind } from '../nodes'; import { GetVisitorFunctionName, Visitor, @@ -7,21 +7,21 @@ import { export function tapVisitor< TReturn, - TNodeKey extends keyof RegisteredNodes, + TNodeKey extends NodeKind, TVisitor extends Visitor >( visitor: TVisitor, key: TNodeKey, - tap: (node: RegisteredNodes[TNodeKey]) => void + tap: (node: NodeDictionary[TNodeKey]) => void ): TVisitor { const newVisitor = { ...visitor }; newVisitor[getVisitFunctionName(key)] = function tappedVisitNode( this: TVisitor, - node: RegisteredNodes[TNodeKey] + node: NodeDictionary[TNodeKey] ): TReturn { tap(node); const parentFunction = visitor[getVisitFunctionName(key)] as ( - node: RegisteredNodes[TNodeKey] + node: NodeDictionary[TNodeKey] ) => TReturn; return parentFunction.bind(this)(node); } as TVisitor[GetVisitorFunctionName]; diff --git a/src/visitors/throwValidatorItemsVisitor.ts b/src/visitors/throwValidatorItemsVisitor.ts index 3434ab736..f8b37137a 100644 --- a/src/visitors/throwValidatorItemsVisitor.ts +++ b/src/visitors/throwValidatorItemsVisitor.ts @@ -1,15 +1,15 @@ import chalk from 'chalk'; -import { RegisteredNodes } from '../nodes'; -import { Visitor } from './visitor'; -import { mapVisitor } from './mapVisitor'; +import { NodeKind } from '../nodes'; import { LogLevel, ValidatorBag, getLevelIndex } from '../shared'; +import { mapVisitor } from './mapVisitor'; +import { Visitor } from './visitor'; export function throwValidatorItemsVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes + TNodeKind extends NodeKind = NodeKind >( - visitor: Visitor, + visitor: Visitor, throwLevel: LogLevel = 'error' -): Visitor { +): Visitor { // eslint-disable-next-line no-console return mapVisitor(visitor, (validatorBag) => { const bag = validatorBag.orderByLevel(); diff --git a/src/visitors/topDownTransformerVisitor.ts b/src/visitors/topDownTransformerVisitor.ts index 51c5a6a96..f630b8086 100644 --- a/src/visitors/topDownTransformerVisitor.ts +++ b/src/visitors/topDownTransformerVisitor.ts @@ -1,4 +1,4 @@ -import { Node, RegisteredNodes } from '../nodes'; +import { Node, NodeKind } from '../nodes'; import { NodeSelector, NodeStack, @@ -23,11 +23,11 @@ export type TopDownNodeTransformerWithSelector = { }; export function topDownTransformerVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes + TNodeKind extends NodeKind = NodeKind >( transformers: (TopDownNodeTransformer | TopDownNodeTransformerWithSelector)[], - nodeKeys?: TNodeKeys[] -): Visitor { + nodeKeys?: TNodeKind[] +): Visitor { const transformerFunctions = transformers.map( (transformer): TopDownNodeTransformer => typeof transformer === 'function' diff --git a/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts b/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts index 4137986da..fc43f79b3 100644 --- a/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts +++ b/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts @@ -23,12 +23,12 @@ export function transformDefinedTypesIntoAccountsVisitor( ); const newAccounts = typesToExtract.map((node) => { - assertIsNode(node.data, 'structTypeNode'); + assertIsNode(node.type, 'structTypeNode'); return accountNode({ ...node, data: accountDataNode({ name: `${node.name}AccountData`, - struct: node.data, + struct: node.type, }), size: undefined, discriminator: undefined, diff --git a/src/visitors/transformU8ArraysToBytesVisitor.ts b/src/visitors/transformU8ArraysToBytesVisitor.ts index 6cda30bc8..3dd6d784d 100644 --- a/src/visitors/transformU8ArraysToBytesVisitor.ts +++ b/src/visitors/transformU8ArraysToBytesVisitor.ts @@ -23,7 +23,7 @@ export function transformU8ArraysToBytesVisitor( return pipe(identityVisitor(), (v) => extendVisitor(v, { visitArrayType(node, { self }) { - const child = visit(node.child, self); + const child = visit(node.item, self); assertIsNode(child, TYPE_NODES); if ( @@ -35,7 +35,7 @@ export function transformU8ArraysToBytesVisitor( return bytesTypeNode(fixedSizeNode(node.size.size)); } - return arrayTypeNode(child, { ...node }); + return arrayTypeNode(child, node.size); }, }) ); diff --git a/src/visitors/unwrapDefinedTypesVisitor.ts b/src/visitors/unwrapDefinedTypesVisitor.ts index 79a593d21..9ca699d39 100644 --- a/src/visitors/unwrapDefinedTypesVisitor.ts +++ b/src/visitors/unwrapDefinedTypesVisitor.ts @@ -47,7 +47,7 @@ export function unwrapDefinedTypesVisitor(typesToInline: string[] | '*' = '*') { ); } - return visit(definedType.data, self); + return visit(definedType.type, self); }, }) ); diff --git a/src/visitors/unwrapInstructionArgsDefinedTypesVisitor.ts b/src/visitors/unwrapInstructionArgsDefinedTypesVisitor.ts index ddba522dd..2c4a02b1a 100644 --- a/src/visitors/unwrapInstructionArgsDefinedTypesVisitor.ts +++ b/src/visitors/unwrapInstructionArgsDefinedTypesVisitor.ts @@ -21,7 +21,7 @@ export function unwrapInstructionArgsDefinedTypesVisitor() { // Filter out enums which are better defined as external types. .filter((name) => { const found = allDefinedTypes.find((type) => type.name === name); - return found && !isNode(found.data, 'enumTypeNode'); + return found && !isNode(found.type, 'enumTypeNode'); }); // Inline the identified defined types if any. diff --git a/src/visitors/unwrapTupleEnumWithSingleStructVisitor.ts b/src/visitors/unwrapTupleEnumWithSingleStructVisitor.ts index 07eac8d85..27e9302be 100644 --- a/src/visitors/unwrapTupleEnumWithSingleStructVisitor.ts +++ b/src/visitors/unwrapTupleEnumWithSingleStructVisitor.ts @@ -50,18 +50,18 @@ export function unwrapTupleEnumWithSingleStructVisitor( transform: (node, stack) => { assertIsNode(node, 'enumTupleVariantTypeNode'); if (!shouldUnwrap(node, stack)) return node; - if (node.tuple.children.length !== 1) return node; - let child = node.tuple.children[0]; - if (isNode(child, 'definedTypeLinkNode')) { - if (child.importFrom) return node; - const definedType = definedTypes.get(child.name); + if (node.tuple.items.length !== 1) return node; + let item = node.tuple.items[0]; + if (isNode(item, 'definedTypeLinkNode')) { + if (item.importFrom) return node; + const definedType = definedTypes.get(item.name); if (!definedType) return node; - if (!isNode(definedType.data, 'structTypeNode')) return node; - typesToPotentiallyUnwrap.push(child.name); - child = definedType.data; + if (!isNode(definedType.type, 'structTypeNode')) return node; + typesToPotentiallyUnwrap.push(item.name); + item = definedType.type; } - if (!isNode(child, 'structTypeNode')) return node; - return enumStructVariantTypeNode(node.name, child); + if (!isNode(item, 'structTypeNode')) return node; + return enumStructVariantTypeNode(node.name, item); }, }, ]) diff --git a/src/visitors/unwrapTypeDefinedLinksVisitor.ts b/src/visitors/unwrapTypeDefinedLinksVisitor.ts index ee5cb2815..d1f9e7989 100644 --- a/src/visitors/unwrapTypeDefinedLinksVisitor.ts +++ b/src/visitors/unwrapTypeDefinedLinksVisitor.ts @@ -25,7 +25,7 @@ export function unwrapTypeDefinedLinksVisitor(definedLinksType: string[]) { `Ensure this visitor starts from the root node to access all defined types.` ); } - return definedType.data; + return definedType.type; }, }; }); diff --git a/src/visitors/updateDefinedTypesVisitor.ts b/src/visitors/updateDefinedTypesVisitor.ts index ac10ca77f..f9223f246 100644 --- a/src/visitors/updateDefinedTypesVisitor.ts +++ b/src/visitors/updateDefinedTypesVisitor.ts @@ -39,17 +39,17 @@ export function updateDefinedTypesVisitor( return null; } const { data: dataUpdates, ...otherUpdates } = updates; - let newData = node.data; - if (isNode(node.data, 'structTypeNode')) { - newData = renameStructNode(node.data, dataUpdates ?? {}); - } else if (isNode(node.data, 'enumTypeNode')) { - newData = renameEnumNode(node.data, dataUpdates ?? {}); + let newType = node.type; + if (isNode(node.type, 'structTypeNode')) { + newType = renameStructNode(node.type, dataUpdates ?? {}); + } else if (isNode(node.type, 'enumTypeNode')) { + newType = renameEnumNode(node.type, dataUpdates ?? {}); } return definedTypeNode({ ...node, ...otherUpdates, name: newName ?? node.name, - data: newData, + type: newType, }); }, }, diff --git a/src/visitors/updateInstructionsVisitor.ts b/src/visitors/updateInstructionsVisitor.ts index 7140b6bf4..98f18967a 100644 --- a/src/visitors/updateInstructionsVisitor.ts +++ b/src/visitors/updateInstructionsVisitor.ts @@ -8,8 +8,8 @@ import { InstructionNodeInput, TYPE_NODES, TypeNode, + addDefaultSeedValuesFromPdaWhenMissing, assertIsNode, - getDefaultSeedValuesFromPda, instructionAccountNode, instructionDataArgsNode, instructionExtraArgsNode, @@ -41,8 +41,8 @@ export type InstructionMetadataUpdates = Partial< export type InstructionAccountUpdates = Record< string, - Partial> & { - defaultsTo?: InstructionInputValueNode | null; + Partial> & { + defaultValue?: InstructionInputValueNode | null; } >; @@ -52,7 +52,7 @@ export type InstructionArgUpdates = Record< name?: string; docs?: string[]; type?: TypeNode; - defaultsTo?: InstructionInputValueNode | null; + defaultValue?: InstructionInputValueNode | null; } >; @@ -110,31 +110,30 @@ function handleInstructionAccount( ): InstructionAccountNode { const accountUpdate = accountUpdates?.[account.name]; if (!accountUpdate) return account; - const { defaultsTo, ...acountWithoutDefault } = { + const { defaultValue, ...acountWithoutDefault } = { ...account, ...accountUpdate, }; - if (defaultsTo === null) { + if (defaultValue === null) { return instructionAccountNode(acountWithoutDefault); } - if (isNode(defaultsTo, 'pdaValueNode')) { - const foundPda = linkables.get(defaultsTo.pda); + if (isNode(defaultValue, 'pdaValueNode')) { + const foundPda = linkables.get(defaultValue.pda); return { ...acountWithoutDefault, name: mainCase(acountWithoutDefault.name), - defaultsTo: { - ...defaultsTo, - seeds: { - ...(foundPda ? getDefaultSeedValuesFromPda(foundPda) : {}), - ...defaultsTo.seeds, - }, + defaultValue: { + ...defaultValue, + seeds: foundPda + ? addDefaultSeedValuesFromPdaWhenMissing(foundPda, defaultValue.seeds) + : defaultValue.seeds, }, }; } - return instructionAccountNode({ ...acountWithoutDefault, defaultsTo }); + return instructionAccountNode({ ...acountWithoutDefault, defaultValue }); } function handleInstructionArgs( @@ -158,7 +157,7 @@ function handleInstructionArgs( usedArgs.add(field.name); return structFieldTypeNode({ ...field, - child: argUpdate.type ?? field.child, + type: argUpdate.type ?? field.type, name: argUpdate.name ?? field.name, docs: argUpdate.docs ?? field.docs, }); @@ -174,7 +173,7 @@ function handleInstructionArgs( usedArgs.add(field.name); return structFieldTypeNode({ ...field, - child: argUpdate.type ?? field.child, + type: argUpdate.type ?? field.type, name: argUpdate.name ?? field.name, docs: argUpdate.docs ?? field.docs, }); @@ -184,11 +183,11 @@ function handleInstructionArgs( const newExtraFields = Object.entries(argUpdates) .filter(([argName]) => !usedArgs.has(argName)) .map(([argName, argUpdate]) => { - const child = argUpdate.type ?? null; - assertIsNode(child, TYPE_NODES); + const { type } = argUpdate; + assertIsNode(type, TYPE_NODES); return structFieldTypeNode({ name: argUpdate.name ?? argName, - child, + type, docs: argUpdate.docs ?? [], }); }); @@ -201,11 +200,11 @@ function handleInstructionArgs( const newArgDefaults = instruction.argDefaults; Object.entries(argUpdates).forEach(([argName, argUpdate]) => { - if (argUpdate?.defaultsTo === undefined) return; - if (argUpdate.defaultsTo === null) { + if (argUpdate?.defaultValue === undefined) return; + if (argUpdate.defaultValue === null) { delete newArgDefaults[argName as MainCaseString]; } else { - newArgDefaults[argName as MainCaseString] = argUpdate.defaultsTo; + newArgDefaults[argName as MainCaseString] = argUpdate.defaultValue; } }); diff --git a/src/visitors/useCustomAccountSerializerVisitor.ts b/src/visitors/useCustomAccountSerializerVisitor.ts index a67166067..687777c98 100644 --- a/src/visitors/useCustomAccountSerializerVisitor.ts +++ b/src/visitors/useCustomAccountSerializerVisitor.ts @@ -44,7 +44,7 @@ export function useCustomAccountSerializerVisitor( if (!options || !options.extract) return; const newType = definedTypeNode({ name: options.extractAs, - data: account.data.struct, + type: account.data.struct, idlName: account.idlName, docs: account.docs, internal: options.extractedTypeShouldBeInternal, diff --git a/src/visitors/useCustomInstructionSerializerVisitor.ts b/src/visitors/useCustomInstructionSerializerVisitor.ts index 8717167de..1d759b749 100644 --- a/src/visitors/useCustomInstructionSerializerVisitor.ts +++ b/src/visitors/useCustomInstructionSerializerVisitor.ts @@ -44,7 +44,7 @@ export function useCustomInstructionSerializerVisitor( if (!options || !options.extract) return; const newType = definedTypeNode({ name: options.extractAs, - data: instruction.dataArgs.struct, + type: instruction.dataArgs.struct, idlName: instruction.idlName, docs: instruction.docs, internal: options.extractedTypeShouldBeInternal, diff --git a/src/visitors/visitor.ts b/src/visitors/visitor.ts index 4066f5b6e..e8bee849e 100644 --- a/src/visitors/visitor.ts +++ b/src/visitors/visitor.ts @@ -1,12 +1,14 @@ -import { Node, REGISTERED_NODES_KEYS, RegisteredNodes } from '../nodes'; +import { + Node, + NodeDictionary, + NodeKind, + REGISTERED_NODE_KINDS, +} from '../nodes'; import { KinobiError, pascalCase } from '../shared'; -export type Visitor< - TReturn, - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes -> = { - [K in TNodeKeys as GetVisitorFunctionName]: ( - node: RegisteredNodes[K] +export type Visitor = { + [K in TNodeKind as GetVisitorFunctionName]: ( + node: NodeDictionary[K] ) => TReturn; }; @@ -43,7 +45,7 @@ export function visitOrElse( } export function getVisitFunctionName(node: T) { - if (!REGISTERED_NODES_KEYS.includes(node)) { + if (!REGISTERED_NODE_KINDS.includes(node)) { throw new KinobiError(`Unrecognized node [${node}]`); } diff --git a/src/visitors/voidVisitor.ts b/src/visitors/voidVisitor.ts index 8533f4858..47fb6bb92 100644 --- a/src/visitors/voidVisitor.ts +++ b/src/visitors/voidVisitor.ts @@ -1,10 +1,10 @@ -import { RegisteredNodes } from '../nodes'; -import { Visitor } from './visitor'; +import { NodeKind } from '../nodes'; import { mergeVisitor } from './mergeVisitor'; +import { Visitor } from './visitor'; -export function voidVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->(nodeKeys?: TNodeKeys[]): Visitor { +export function voidVisitor( + nodeKeys?: TNodeKind[] +): Visitor { return mergeVisitor( () => undefined, () => undefined, diff --git a/src/visitors/writeRenderMapVisitor.ts b/src/visitors/writeRenderMapVisitor.ts index 78a30bc8a..ea400682f 100644 --- a/src/visitors/writeRenderMapVisitor.ts +++ b/src/visitors/writeRenderMapVisitor.ts @@ -1,13 +1,11 @@ -import { RegisteredNodes } from '../nodes'; +import { NodeKind } from '../nodes'; import { RenderMap } from '../shared'; import { mapVisitor } from './mapVisitor'; import { Visitor } from './visitor'; -export function writeRenderMapVisitor< - TNodeKeys extends keyof RegisteredNodes = keyof RegisteredNodes ->( - visitor: Visitor, +export function writeRenderMapVisitor( + visitor: Visitor, path: string -): Visitor { +): Visitor { return mapVisitor(visitor, (renderMap) => renderMap.write(path)); } diff --git a/test/shared/NodeSelector.test.ts b/test/shared/NodeSelector.test.ts index ebe5acaa4..6804582f9 100644 --- a/test/shared/NodeSelector.test.ts +++ b/test/shared/NodeSelector.test.ts @@ -50,19 +50,19 @@ const tree = rootNode([ struct: structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'mint', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'amount', - child: numberTypeNode('u64'), + type: numberTypeNode('u64'), }), structFieldTypeNode({ name: 'delegatedAmount', - child: optionTypeNode(numberTypeNode('u64'), { + type: optionTypeNode(numberTypeNode('u64'), { prefix: numberTypeNode('u32'), }), }), @@ -95,7 +95,7 @@ const tree = rootNode([ struct: structTypeNode([ structFieldTypeNode({ name: 'amount', - child: numberTypeNode('u64'), + type: numberTypeNode('u64'), }), ]), }), @@ -131,19 +131,19 @@ const tree = rootNode([ struct: structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'opened', - child: booleanTypeNode(numberTypeNode('u64')), + type: booleanTypeNode(numberTypeNode('u64')), }), structFieldTypeNode({ name: 'amount', - child: numberTypeNode('u64'), + type: numberTypeNode('u64'), }), structFieldTypeNode({ name: 'wrappingPaper', - child: definedTypeLinkNode('wrappingPaper'), + type: definedTypeLinkNode('wrappingPaper'), }), ]), }), @@ -177,7 +177,7 @@ const tree = rootNode([ definedTypes: [ definedTypeNode({ name: 'wrappingPaper', - data: enumTypeNode([ + type: enumTypeNode([ enumEmptyVariantTypeNode('blue'), enumEmptyVariantTypeNode('red'), enumStructVariantTypeNode( @@ -185,7 +185,7 @@ const tree = rootNode([ structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), }), ]) ), @@ -270,12 +270,12 @@ const splTokenProgram = tree.programs[0]; const christmasProgram = tree.programs[1]; const tokenAccount = splTokenProgram.accounts[0]; const tokenDelegatedAmountOption = tokenAccount.data.struct.fields[3] - .child as OptionTypeNode; + .type as OptionTypeNode; const mintTokenInstruction = splTokenProgram.instructions[0]; const giftAccount = christmasProgram.accounts[0]; const openGiftInstruction = christmasProgram.instructions[0]; const wrappingPaper = christmasProgram.definedTypes[0]; -const wrappingPaperEnum = wrappingPaper.data as EnumTypeNode; +const wrappingPaperEnum = wrappingPaper.type as EnumTypeNode; const wrappingPaperEnumGold = wrappingPaperEnum .variants[2] as EnumStructVariantTypeNode; @@ -317,46 +317,46 @@ test(macro, 'christmasProgram.wrappingPaper.gold.owner', [ // Select all descendants of a node. test(macro, 'wrappingPaper.*', [ - giftAccount.data.struct.fields[3].child, + giftAccount.data.struct.fields[3].type, wrappingPaperEnum, wrappingPaperEnum.variants[0], wrappingPaperEnum.variants[1], wrappingPaperEnum.variants[2], wrappingPaperEnumGold.struct, wrappingPaperEnumGold.struct.fields[0], - wrappingPaperEnumGold.struct.fields[0].child, + wrappingPaperEnumGold.struct.fields[0].type, ]); test(macro, 'wrappingPaper.[structFieldTypeNode]', [ wrappingPaperEnumGold.struct.fields[0], ]); test(macro, 'wrappingPaper.blue', [wrappingPaperEnum.variants[0]]); test(macro, 'amount.*', [ - tokenAccount.data.struct.fields[2].child, - mintTokenInstruction.dataArgs.struct.fields[0].child, - giftAccount.data.struct.fields[2].child, + tokenAccount.data.struct.fields[2].type, + mintTokenInstruction.dataArgs.struct.fields[0].type, + giftAccount.data.struct.fields[2].type, ]); test(macro, '[instructionNode].amount.*', [ - mintTokenInstruction.dataArgs.struct.fields[0].child, + mintTokenInstruction.dataArgs.struct.fields[0].type, ]); test(macro, '[structFieldTypeNode].*', [ - tokenAccount.data.struct.fields[0].child, - tokenAccount.data.struct.fields[1].child, - tokenAccount.data.struct.fields[2].child, - tokenAccount.data.struct.fields[3].child, + tokenAccount.data.struct.fields[0].type, + tokenAccount.data.struct.fields[1].type, + tokenAccount.data.struct.fields[2].type, + tokenAccount.data.struct.fields[3].type, tokenDelegatedAmountOption.prefix, - tokenDelegatedAmountOption.child, - mintTokenInstruction.dataArgs.struct.fields[0].child, - giftAccount.data.struct.fields[0].child, - giftAccount.data.struct.fields[1].child, - (giftAccount.data.struct.fields[1].child as BooleanTypeNode).size, - giftAccount.data.struct.fields[2].child, - giftAccount.data.struct.fields[3].child, - wrappingPaperEnumGold.struct.fields[0].child, + tokenDelegatedAmountOption.item, + mintTokenInstruction.dataArgs.struct.fields[0].type, + giftAccount.data.struct.fields[0].type, + giftAccount.data.struct.fields[1].type, + (giftAccount.data.struct.fields[1].type as BooleanTypeNode).size, + giftAccount.data.struct.fields[2].type, + giftAccount.data.struct.fields[3].type, + wrappingPaperEnumGold.struct.fields[0].type, ]); test(macro, '[structFieldTypeNode].*.*', [ tokenDelegatedAmountOption.prefix, - tokenDelegatedAmountOption.child, - (giftAccount.data.struct.fields[1].child as BooleanTypeNode).size, + tokenDelegatedAmountOption.item, + (giftAccount.data.struct.fields[1].type as BooleanTypeNode).size, ]); // Select using functions. diff --git a/test/testFile.cjs b/test/testFile.cjs index e50f75dcc..16dfebb9b 100644 --- a/test/testFile.cjs +++ b/test/testFile.cjs @@ -81,22 +81,22 @@ kinobi.update( 'mplTokenAuthRules.Create': { name: 'CreateRuleSet', args: { - ruleSetBump: { defaultsTo: k.accountBumpValueNode('ruleSetPda') }, + ruleSetBump: { defaultValue: k.accountBumpValueNode('ruleSetPda') }, }, }, 'mplCandyMachineCore.Update': { name: 'UpdateCandyMachine' }, CreateMetadataAccount: { bytesCreatedOnChain: k.bytesFromAccount('Metadata'), accounts: { - metadata: { defaultsTo: k.pdaValueNode('metadata') }, + metadata: { defaultValue: k.pdaValueNode('metadata') }, }, args: { - metadataBump: { defaultsTo: k.accountBumpValueNode('metadata') }, + metadataBump: { defaultValue: k.accountBumpValueNode('metadata') }, }, }, CreateMetadataAccountV3: { accounts: { - metadata: { defaultsTo: k.pdaValueNode('metadata') }, + metadata: { defaultValue: k.pdaValueNode('metadata') }, }, }, CreateMasterEditionV3: { @@ -105,28 +105,31 @@ kinobi.update( 'mplCandyMachineCore.Mint': { name: 'MintFromCandyMachine', accounts: { - nftMintAuthority: { defaultsTo: k.identityValueNode() }, + nftMintAuthority: { defaultValue: k.identityValueNode() }, }, }, Dummy: { accounts: { - mintAuthority: { defaultsTo: k.accountValueNode('updateAuthority') }, - edition: { defaultsTo: k.accountValueNode('payer') }, - foo: { defaultsTo: k.accountValueNode('bar') }, + mintAuthority: { defaultValue: k.accountValueNode('updateAuthority') }, + edition: { defaultValue: k.accountValueNode('payer') }, + foo: { defaultValue: k.accountValueNode('bar') }, bar: { - defaultsTo: k.programIdValueNode(), + defaultValue: k.programIdValueNode(), isOptional: true, }, delegateRecord: { - defaultsTo: k.conditionalValueNode({ + defaultValue: k.conditionalValueNode({ condition: k.accountValueNode('delegate'), - ifTrue: k.pdaValueNode('delegateRecord', { - role: k.enumValueNode('delegateRole', 'Collection'), - }), + ifTrue: k.pdaValueNode('delegateRecord', [ + k.pdaSeedValueNode( + 'role', + k.enumValueNode('delegateRole', 'Collection') + ), + ]), }), }, tokenOrAtaProgram: { - defaultsTo: k.conditionalValueNode({ + defaultValue: k.conditionalValueNode({ condition: k.resolverValueNode('resolveTokenOrAta', [ k.argumentValueNode('proof'), ]), @@ -142,13 +145,11 @@ kinobi.update( args: { identityArg: { type: k.publicKeyTypeNode(), - defaultsTo: k.identityValueNode(), + defaultValue: k.identityValueNode(), }, proof: { - type: k.arrayTypeNode(k.publicKeyTypeNode(), { - size: k.remainderSizeNode(), - }), - defaultsTo: k.arrayValueNode([]), + type: k.arrayTypeNode(k.publicKeyTypeNode(), k.remainderSizeNode()), + defaultValue: k.arrayValueNode([]), }, }, remainingAccounts: k.remainingAccountsFromArg('proof'), @@ -157,7 +158,7 @@ kinobi.update( Transfer: { accounts: { masterEdition: { - defaultsTo: k.resolverValueNode( + defaultValue: k.resolverValueNode( 'resolveMasterEditionFromTokenStandard', [k.accountValueNode('mint'), k.argumentValueNode('tokenStandard')] ), @@ -166,7 +167,7 @@ kinobi.update( args: { tokenStandard: { type: k.definedTypeLinkNode('tokenStandard'), - defaultsTo: k.enumValueNode('tokenStandard', 'NonFungible'), + defaultValue: k.enumValueNode('tokenStandard', 'NonFungible'), }, }, }, @@ -230,8 +231,8 @@ kinobi.update( 'DelegateArgs.SaleV1.amount': { kind: 'SolAmount' }, 'CandyMachineData.sellerFeeBasisPoints': { kind: 'Amount', - identifier: '%', decimals: 2, + unit: '%', }, }) ); diff --git a/test/visitors/extendVisitor.test.ts b/test/visitors/extendVisitor.test.ts index 7b08569a9..4118e4be7 100644 --- a/test/visitors/extendVisitor.test.ts +++ b/test/visitors/extendVisitor.test.ts @@ -50,7 +50,7 @@ test('it can visit itself using the exposed self argument', (t) => { ); const visitor = extendVisitor(baseVisitor, { visitTupleType: (node, { self }) => - (node.children.length > 1 ? visit(node.children[0], self) : 0) + 1, + (node.items.length > 1 ? visit(node.items[0], self) : 0) + 1, }); // When we visit the tree using that visitor. diff --git a/test/visitors/getByteSizeVisitor.test.ts b/test/visitors/getByteSizeVisitor.test.ts index c5ac6d634..c86a4a4da 100644 --- a/test/visitors/getByteSizeVisitor.test.ts +++ b/test/visitors/getByteSizeVisitor.test.ts @@ -46,10 +46,10 @@ test( 'it gets the size of fixed structs', macro, structTypeNode([ - structFieldTypeNode({ name: 'age', child: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'firstname', - child: stringTypeNode({ size: fixedSizeNode(42) }), + type: stringTypeNode({ size: fixedSizeNode(42) }), }), ]), 4 + 42 @@ -58,8 +58,8 @@ test( 'it gets the size of variable structs', macro, structTypeNode([ - structFieldTypeNode({ name: 'age', child: numberTypeNode('u32') }), - structFieldTypeNode({ name: 'firstname', child: stringTypeNode() }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'firstname', type: stringTypeNode() }), ]), null ); @@ -85,8 +85,8 @@ test( enumStructVariantTypeNode( 'B', structTypeNode([ - structFieldTypeNode({ name: 'x', child: numberTypeNode('u16') }), - structFieldTypeNode({ name: 'y', child: numberTypeNode('u16') }), + structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }), ]) ), ], diff --git a/test/visitors/getDebugStringVisitor.test.ts b/test/visitors/getDebugStringVisitor.test.ts index 9b59af81f..ee6ea3ec9 100644 --- a/test/visitors/getDebugStringVisitor.test.ts +++ b/test/visitors/getDebugStringVisitor.test.ts @@ -21,21 +21,21 @@ test('it returns a string representing the main information of a node for debugg structTypeNode([ structFieldTypeNode({ name: 'firstname', - child: stringTypeNode({ + type: stringTypeNode({ size: prefixedSizeNode(numberTypeNode('u64')), encoding: 'utf8', }), }), - structFieldTypeNode({ name: 'age', child: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'wallet', - child: optionTypeNode(publicKeyTypeNode(), { + type: optionTypeNode(publicKeyTypeNode(), { prefix: numberTypeNode('u16'), }), }), structFieldTypeNode({ name: 'industry', - child: enumTypeNode([ + type: enumTypeNode([ enumEmptyVariantTypeNode('programming'), enumEmptyVariantTypeNode('crypto'), enumEmptyVariantTypeNode('music'), @@ -61,21 +61,21 @@ test('it can create indented strings', (t) => { structTypeNode([ structFieldTypeNode({ name: 'firstname', - child: stringTypeNode({ + type: stringTypeNode({ size: prefixedSizeNode(numberTypeNode('u64')), encoding: 'utf8', }), }), - structFieldTypeNode({ name: 'age', child: numberTypeNode('u32') }), + structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'wallet', - child: optionTypeNode(publicKeyTypeNode(), { + type: optionTypeNode(publicKeyTypeNode(), { prefix: numberTypeNode('u16'), }), }), structFieldTypeNode({ name: 'industry', - child: enumTypeNode([ + type: enumTypeNode([ enumEmptyVariantTypeNode('programming'), enumEmptyVariantTypeNode('crypto'), enumEmptyVariantTypeNode('music'), diff --git a/test/visitors/getDefaultValidatorBagVisitor.test.ts b/test/visitors/getDefaultValidatorBagVisitor.test.ts index 4e540bc6d..2c815a2be 100644 --- a/test/visitors/getDefaultValidatorBagVisitor.test.ts +++ b/test/visitors/getDefaultValidatorBagVisitor.test.ts @@ -44,8 +44,8 @@ test('it validates nested nodes', (t) => { const node = tupleTypeNode([ tupleTypeNode([]), structTypeNode([ - structFieldTypeNode({ name: 'owner', child: publicKeyTypeNode() }), - structFieldTypeNode({ name: 'owner', child: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), ]), ]); @@ -53,8 +53,8 @@ test('it validates nested nodes', (t) => { const bag = visit(node, getDefaultValidatorBagVisitor()); // Then we expect the following validation errors. - const tupleNode = node.children[0]; - const structNode = node.children[1]; + const tupleNode = node.items[0]; + const structNode = node.items[1]; t.deepEqual( bag, new ValidatorBag() diff --git a/test/visitors/getDefinedTypeHistogramVisitor.test.ts b/test/visitors/getDefinedTypeHistogramVisitor.test.ts index de2bf7156..3a10011f4 100644 --- a/test/visitors/getDefinedTypeHistogramVisitor.test.ts +++ b/test/visitors/getDefinedTypeHistogramVisitor.test.ts @@ -23,11 +23,11 @@ test('it counts the amount of times defined types are used within the tree', (t) definedTypes: [ definedTypeNode({ name: 'myStruct', - data: structTypeNode([]), + type: structTypeNode([]), }), definedTypeNode({ name: 'myEnum', - data: enumTypeNode([]), + type: enumTypeNode([]), }), ], accounts: [ @@ -38,11 +38,11 @@ test('it counts the amount of times defined types are used within the tree', (t) struct: structTypeNode([ structFieldTypeNode({ name: 'field1', - child: definedTypeLinkNode('myStruct'), + type: definedTypeLinkNode('myStruct'), }), structFieldTypeNode({ name: 'field2', - child: definedTypeLinkNode('myEnum'), + type: definedTypeLinkNode('myEnum'), }), ]), }), @@ -57,7 +57,7 @@ test('it counts the amount of times defined types are used within the tree', (t) struct: structTypeNode([ structFieldTypeNode({ name: 'arg1', - child: definedTypeLinkNode('myStruct'), + type: definedTypeLinkNode('myStruct'), }), ]), }), diff --git a/test/visitors/getResolvedInstructionInputsVisitor.test.ts b/test/visitors/getResolvedInstructionInputsVisitor.test.ts index 7925dee13..7c85b46dc 100644 --- a/test/visitors/getResolvedInstructionInputsVisitor.test.ts +++ b/test/visitors/getResolvedInstructionInputsVisitor.test.ts @@ -22,7 +22,7 @@ test('it returns all instruction accounts in order of resolution', (t) => { name: 'owner', isSigner: true, isWritable: false, - defaultsTo: accountValueNode('authority'), + defaultValue: accountValueNode('authority'), }), instructionAccountNode({ name: 'authority', @@ -67,7 +67,7 @@ test('it sets the resolved signer to either when a non signer defaults to a sign name: 'owner', isSigner: false, isWritable: false, - defaultsTo: accountValueNode('authority'), + defaultValue: accountValueNode('authority'), }), instructionAccountNode({ name: 'authority', @@ -103,7 +103,7 @@ test('it sets the resolved signer to either when a signer defaults to a non sign name: 'owner', isSigner: true, isWritable: false, - defaultsTo: accountValueNode('authority'), + defaultValue: accountValueNode('authority'), }), instructionAccountNode({ name: 'authority', @@ -146,10 +146,10 @@ test('it includes instruction data arguments with default values', (t) => { dataArgs: instructionDataArgsNode({ name: 'myInstructionData', struct: structTypeNode([ - structFieldTypeNode({ name: 'ownerArg', child: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'ownerArg', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'argWithoutDefaults', - child: numberTypeNode('u8'), + type: numberTypeNode('u8'), }), ]), }), @@ -173,7 +173,7 @@ test('it includes instruction data arguments with default values', (t) => { { kind: 'argument', name: 'ownerArg', - defaultsTo: accountValueNode('owner'), + defaultValue: accountValueNode('owner'), dependsOn: [accountValueNode('owner')], }, ]); @@ -202,10 +202,10 @@ test('it includes instruction extra arguments with default values', (t) => { extraArgs: instructionExtraArgsNode({ name: 'myInstructionExtra', struct: structTypeNode([ - structFieldTypeNode({ name: 'ownerArg', child: publicKeyTypeNode() }), + structFieldTypeNode({ name: 'ownerArg', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'argWithoutDefaults', - child: numberTypeNode('u8'), + type: numberTypeNode('u8'), }), ]), }), @@ -229,7 +229,7 @@ test('it includes instruction extra arguments with default values', (t) => { { kind: 'argument', name: 'ownerArg', - defaultsTo: accountValueNode('owner'), + defaultValue: accountValueNode('owner'), dependsOn: [accountValueNode('owner')], }, ]); diff --git a/test/visitors/getUniqueHashStringVisitor.test.ts b/test/visitors/getUniqueHashStringVisitor.test.ts index cf8735d13..bcc98afb6 100644 --- a/test/visitors/getUniqueHashStringVisitor.test.ts +++ b/test/visitors/getUniqueHashStringVisitor.test.ts @@ -22,9 +22,9 @@ test('it returns a unique string representing the whole node', (t) => { // Then we expect the following string. t.deepEqual( result, - '{"children":[' + + '{"items":[' + '{"endian":"le","format":"u32","kind":"numberTypeNode"},' + - '{"children":[{"endian":"le","format":"u32","kind":"numberTypeNode"},{"kind":"publicKeyTypeNode"}],"kind":"tupleTypeNode"}' + + '{"items":[{"endian":"le","format":"u32","kind":"numberTypeNode"},{"kind":"publicKeyTypeNode"}],"kind":"tupleTypeNode"}' + '],"kind":"tupleTypeNode"}' ); }); @@ -34,7 +34,7 @@ test('it returns a unique string whilst discard docs', (t) => { const node = structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: ['The owner of the account.'], }), ]); @@ -46,7 +46,7 @@ test('it returns a unique string whilst discard docs', (t) => { t.deepEqual( result, '{"fields":[' + - '{"child":{"kind":"publicKeyTypeNode"},"defaultsTo":null,"docs":[],"kind":"structFieldTypeNode","name":"owner"}' + + '{"docs":[],"kind":"structFieldTypeNode","name":"owner","type":{"kind":"publicKeyTypeNode"}}' + '],"kind":"structTypeNode"}' ); }); diff --git a/test/visitors/identityVisitor.test.ts b/test/visitors/identityVisitor.test.ts index 3bab8782f..a93d8dc9b 100644 --- a/test/visitors/identityVisitor.test.ts +++ b/test/visitors/identityVisitor.test.ts @@ -22,8 +22,8 @@ test('it visits all nodes and returns different instances of the same nodes', (t // But the nodes are different instances. t.not(result, node); assertIsNode(result, 'tupleTypeNode'); - t.not(result.children[0], node.children[0]); - t.not(result.children[1], node.children[1]); + t.not(result.items[0], node.items[0]); + t.not(result.items[1], node.items[1]); }); test('it can remove nodes by returning null', (t) => { @@ -63,8 +63,8 @@ test('it can create partial visitors', (t) => { t.deepEqual(result, node); t.not(result, node); assertIsNode(result, 'tupleTypeNode'); - t.not(result.children[0], node.children[0]); - t.not(result.children[1], node.children[1]); + t.not(result.items[0], node.items[0]); + t.not(result.items[1], node.items[1]); // But the unsupported node was not visited. t.deepEqual(events, ['visiting:tupleTypeNode', 'visiting:numberTypeNode']); diff --git a/test/visitors/mapVisitor.test.ts b/test/visitors/mapVisitor.test.ts index 5ac5bc6f5..852ac78dc 100644 --- a/test/visitors/mapVisitor.test.ts +++ b/test/visitors/mapVisitor.test.ts @@ -25,8 +25,8 @@ test('it maps the return value of a visitor to another', (t) => { // Then we expect the following results when visiting different nodes. t.is(visit(node, visitorB), 47); - t.is(visit(node.children[0], visitorB), 14); - t.is(visit(node.children[1], visitorB), 17); + t.is(visit(node.items[0], visitorB), 14); + t.is(visit(node.items[1], visitorB), 17); }); test('it creates partial visitors from partial visitors', (t) => { @@ -48,5 +48,5 @@ test('it creates partial visitors from partial visitors', (t) => { // Then we expect an error when visiting an unsupported node. // @ts-expect-error - t.throws(() => visit(node.children[1], visitorB)); + t.throws(() => visit(node.items[1], visitorB)); }); diff --git a/test/visitors/recordLinkablesVisitor.test.ts b/test/visitors/recordLinkablesVisitor.test.ts index 338518dd5..e61a2da27 100644 --- a/test/visitors/recordLinkablesVisitor.test.ts +++ b/test/visitors/recordLinkablesVisitor.test.ts @@ -25,7 +25,7 @@ test('it record all linkable nodes it finds when traversing the tree', (t) => { pdas: [pdaNode('pdaA', [])], accounts: [accountNode({ name: 'accountA' })], definedTypes: [ - definedTypeNode({ name: 'typeA', data: structTypeNode([]) }), + definedTypeNode({ name: 'typeA', type: structTypeNode([]) }), ], }), programNode({ @@ -34,7 +34,7 @@ test('it record all linkable nodes it finds when traversing the tree', (t) => { pdas: [pdaNode('pdaB', [])], accounts: [accountNode({ name: 'accountB' })], definedTypes: [ - definedTypeNode({ name: 'typeB', data: structTypeNode([]) }), + definedTypeNode({ name: 'typeB', type: structTypeNode([]) }), ], }), ]); diff --git a/test/visitors/recordNodeStackVisitor.test.ts b/test/visitors/recordNodeStackVisitor.test.ts index 7c502c049..30ff1750e 100644 --- a/test/visitors/recordNodeStackVisitor.test.ts +++ b/test/visitors/recordNodeStackVisitor.test.ts @@ -17,7 +17,7 @@ test('it records the current node stack of a visit', (t) => { // Given the following tree. const node = definedTypeNode({ name: 'myType', - data: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), + type: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), }); // And a visitor that records the current node stack and stores the number stacks in an array. @@ -35,7 +35,7 @@ test('it records the current node stack of a visit', (t) => { // Then we expect the number stacks to have been recorded. t.is(numberStacks.length, 1); - t.deepEqual(numberStacks[0].all(), [node, node.data]); + t.deepEqual(numberStacks[0].all(), [node, node.type]); // And the current node stack to be empty. t.true(stack.isEmpty()); @@ -45,7 +45,7 @@ test('it includes the current node when applied last', (t) => { // Given the following tree. const node = definedTypeNode({ name: 'myType', - data: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), + type: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), }); // And a visitor that records the current node stack as the last visitor modifier. @@ -66,7 +66,7 @@ test('it includes the current node when applied last', (t) => { t.is(numberStacks.length, 1); t.deepEqual(numberStacks[0].all(), [ node, - node.data, - (node.data as TupleTypeNode).children[0], + node.type, + (node.type as TupleTypeNode).items[0], ]); }); diff --git a/test/visitors/removeDocsVisitor.test.ts b/test/visitors/removeDocsVisitor.test.ts index 618775761..eeb3e27a7 100644 --- a/test/visitors/removeDocsVisitor.test.ts +++ b/test/visitors/removeDocsVisitor.test.ts @@ -13,17 +13,17 @@ test('it empties the docs array of any node that contains docs', (t) => { const node = structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: ['The owner of the account.'], }), structFieldTypeNode({ name: 'authority', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: ['The wallet allowed to modify the account.'], }), structFieldTypeNode({ name: 'amount', - child: numberTypeNode('u64'), + type: numberTypeNode('u64'), docs: ['The amount of tokens in basis points.'], }), ]); @@ -37,17 +37,17 @@ test('it empties the docs array of any node that contains docs', (t) => { structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: [], }), structFieldTypeNode({ name: 'authority', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: [], }), structFieldTypeNode({ name: 'amount', - child: numberTypeNode('u64'), + type: numberTypeNode('u64'), docs: [], }), ]) @@ -59,7 +59,7 @@ test('it can create partial visitors', (t) => { const node = structTypeNode([ structFieldTypeNode({ name: 'owner', - child: publicKeyTypeNode(), + type: publicKeyTypeNode(), docs: ['The owner of the account.'], }), ]); diff --git a/test/visitors/singleNodeVisitor.test.ts b/test/visitors/singleNodeVisitor.test.ts index a543bd351..285af43b5 100644 --- a/test/visitors/singleNodeVisitor.test.ts +++ b/test/visitors/singleNodeVisitor.test.ts @@ -20,7 +20,7 @@ test('it visits a single node and return a custom value', (t) => { // And a visitor that counts the number of direct items in a tuple node. const visitor = singleNodeVisitor( 'tupleTypeNode', - (node) => node.children.length + (node) => node.items.length ); // When we visit the tree using that visitor. diff --git a/test/visitors/staticVisitor.test.ts b/test/visitors/staticVisitor.test.ts index 5bd39a6e0..83c1f8704 100644 --- a/test/visitors/staticVisitor.test.ts +++ b/test/visitors/staticVisitor.test.ts @@ -16,8 +16,8 @@ test('it returns the same value for any visited node', (t) => { // Then we expect the following results when visiting different nodes. t.is(visit(node, visitor), 'tupleTypeNode'); - t.is(visit(node.children[0], visitor), 'numberTypeNode'); - t.is(visit(node.children[1], visitor), 'publicKeyTypeNode'); + t.is(visit(node.items[0], visitor), 'numberTypeNode'); + t.is(visit(node.items[1], visitor), 'publicKeyTypeNode'); }); test('it can create partial visitor', (t) => { @@ -32,9 +32,9 @@ test('it can create partial visitor', (t) => { // Then we expect the following results when visiting supported nodes. t.is(visit(node, visitor), 'tupleTypeNode'); - t.is(visit(node.children[0], visitor), 'numberTypeNode'); + t.is(visit(node.items[0], visitor), 'numberTypeNode'); // But expect an error when visiting an unsupported node. // @ts-expect-error - t.throws(() => visit(node.children[1], visitor)); + t.throws(() => visit(node.items[1], visitor)); }); diff --git a/test/visitors/topDownTransformerVisitor.test.ts b/test/visitors/topDownTransformerVisitor.test.ts index 6533a5d45..27b567d25 100644 --- a/test/visitors/topDownTransformerVisitor.test.ts +++ b/test/visitors/topDownTransformerVisitor.test.ts @@ -81,7 +81,7 @@ test('it can create partial transformer visitors', (t) => { assertIsNode(node, 'tupleTypeNode'); return tupleTypeNode([ numberTypeNode('u64'), - ...node.children, + ...node.items, ]) as unknown as typeof node; }, }, diff --git a/test/visitors/visitor.test.ts b/test/visitors/visitor.test.ts index f7c8178e1..e3b4b8878 100644 --- a/test/visitors/visitor.test.ts +++ b/test/visitors/visitor.test.ts @@ -24,7 +24,7 @@ test('it can create visitors as plain objects', (t) => { 'tupleTypeNode' | 'numberTypeNode' | 'publicKeyTypeNode' > = { visitTupleType(node) { - const castedChildren = node.children as ( + const castedChildren = node.items as ( | TupleTypeNode | NumberTypeNode | PublicKeyTypeNode @@ -56,7 +56,7 @@ test('it can use visitOrElse to fallback if a nested node is not supported by th // Such that it falls back to 42 for any other node. const visitor: Visitor = { visitTupleType(node) { - return node.children + return node.items .map((child) => visitOrElse(child, this, () => 42)) .reduce((a, b) => a + b, 1); },