Skip to content

Commit

Permalink
Refactor nodes for consistency (#130)
Browse files Browse the repository at this point in the history
* Rename StructFieldTypeNode.child to StructFieldTypeNode.type

* Refactor StructFieldTypeNode.defaultTo into defaultValue and defaultValueStrategy

* Refactor AmountTypeNode.identifier to an optional unit attribute

* Rename ArrayTypeNode.child to item

* Refactor mapTypeNode helper

* Rename OptionTypeNode.child to item

* Rename SetTypeNode.child to item

* Rename TupleTypeNode.children to items

* Refactor EnumValueNode

* Remove getValueNodeFragment in favour of ValueNodeVisitor

* Add GlobalFragmentScope in js-experimental render map

* Rename DefinedTypeNode.data to type

* Rename InstructionAccountNode.defaultsTo to defaultValue

* Add comments

* Refactor TypeNode registration

* Refactor Node registration

* Rename NODE_KEYS to NODE_KINDS

* Refactor ValueNode registration

* Update ValueNode.ts

* Update SizeNode.ts

* Use NodeKind instead of NodeKinds in types

* Update PdaSeedNode.ts

* Rename RegisteredNodes to NodeDictionary

* Use NodeKind instead of keyof NodeDictionary

* Update instructionBytesCreatedOnChain.ts

* Update LinkNode.ts

* Update ContextualValueNode.ts

* Add PdaSeedValueNode

* Add MapEntryValueNode

* Add StructFieldValueNode

* Add changeset
  • Loading branch information
lorisleiva authored Jan 2, 2024
1 parent b3ec72c commit 3ef61bb
Show file tree
Hide file tree
Showing 168 changed files with 1,628 additions and 1,340 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-games-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@metaplex-foundation/kinobi': minor
---

Refactor nodes for consistency
6 changes: 5 additions & 1 deletion src/nodes/AccountDataNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
10 changes: 5 additions & 5 deletions src/nodes/DefinedTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type DefinedTypeNode = {
readonly kind: 'definedTypeNode';

// Children.
readonly data: TypeNode;
readonly type: TypeNode;

// Data.
readonly name: MainCaseString;
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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 });
}
2 changes: 2 additions & 0 deletions src/nodes/ErrorNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {

export type ErrorNode = {
readonly kind: 'errorNode';

// Data.
readonly name: MainCaseString;
readonly idlName: string;
readonly code: number;
Expand Down
4 changes: 2 additions & 2 deletions src/nodes/InstructionAccountNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type InstructionAccountNode = {
readonly kind: 'instructionAccountNode';

// Children.
readonly defaultsTo?: InstructionInputValueNode;
readonly defaultValue?: InstructionInputValueNode;

// Data.
readonly name: MainCaseString;
Expand All @@ -33,7 +33,7 @@ export function instructionAccountNode(
isSigner: input.isSigner,
isOptional: input.isOptional ?? false,
docs: input.docs ?? [],
defaultsTo: input.defaultsTo,
defaultValue: input.defaultValue,
};
}

Expand Down
6 changes: 5 additions & 1 deletion src/nodes/InstructionDataArgsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
6 changes: 5 additions & 1 deletion src/nodes/InstructionExtraArgsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
8 changes: 3 additions & 5 deletions src/nodes/InstructionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
Expand Down
64 changes: 30 additions & 34 deletions src/nodes/Node.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getNodeKinds } from '../shared/utils';
import type { AccountDataNode } from './AccountDataNode';
import type { AccountNode } from './AccountNode';
import type { DefinedTypeNode } from './DefinedTypeNode';
Expand Down Expand Up @@ -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<TKeys extends keyof RegisteredNodes>(
export function isNode<TKind extends NodeKind>(
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<TKeys extends keyof RegisteredNodes>(
export function assertIsNode<TKind extends NodeKind>(
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<TKeys extends keyof RegisteredNodes>(
key: TKeys | TKeys[]
): (node: Node | null | undefined) => node is RegisteredNodes[TKeys] {
return (node): node is RegisteredNodes[TKeys] => isNode(node, key);
export function isNodeFilter<TKind extends NodeKind>(
kind: TKind | TKind[]
): (node: Node | null | undefined) => node is NodeDictionary[TKind] {
return (node): node is NodeDictionary[TKind] => isNode(node, kind);
}

export function assertIsNodeFilter<TKeys extends keyof RegisteredNodes>(
key: TKeys | TKeys[]
): (node: Node | null | undefined) => node is RegisteredNodes[TKeys] {
return (node): node is RegisteredNodes[TKeys] => {
assertIsNode(node, key);
export function assertIsNodeFilter<TKind extends NodeKind>(
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<TKind extends NodeKind>(
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;
};
}
6 changes: 5 additions & 1 deletion src/nodes/PdaNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/nodes/RootNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export type IdlInputs = string | Partial<Idl> | (string | Partial<Idl>)[];

export type RootNode = {
readonly kind: 'rootNode';

// Children.
readonly programs: ProgramNode[];
};

Expand Down
2 changes: 2 additions & 0 deletions src/nodes/contextualValueNodes/AccountBumpValueNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared';

export type AccountBumpValueNode = {
readonly kind: 'accountBumpValueNode';

// Data.
readonly name: MainCaseString;
};

Expand Down
2 changes: 2 additions & 0 deletions src/nodes/contextualValueNodes/AccountValueNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared';

export type AccountValueNode = {
readonly kind: 'accountValueNode';

// Data.
readonly name: MainCaseString;
};

Expand Down
2 changes: 2 additions & 0 deletions src/nodes/contextualValueNodes/ArgumentValueNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { MainCaseString, mainCase } from '../../shared';

export type ArgumentValueNode = {
readonly kind: 'argumentValueNode';

// Data.
readonly name: MainCaseString;
};

Expand Down
2 changes: 2 additions & 0 deletions src/nodes/contextualValueNodes/ConditionalValueNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
52 changes: 32 additions & 20 deletions src/nodes/contextualValueNodes/ContextualValueNode.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
Expand All @@ -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,
];
21 changes: 21 additions & 0 deletions src/nodes/contextualValueNodes/PdaSeedValueNode.ts
Original file line number Diff line number Diff line change
@@ -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 };
}
Loading

0 comments on commit 3ef61bb

Please sign in to comment.