Skip to content

Commit

Permalink
Make nodes generic interfaces (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva authored Apr 9, 2024
1 parent 7b50ebd commit 8406a69
Show file tree
Hide file tree
Showing 105 changed files with 1,183 additions and 725 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-knives-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@metaplex-foundation/kinobi": minor
---

Make nodes generic interfaces
49 changes: 39 additions & 10 deletions src/nodes/AccountNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,64 @@ import { InvalidKinobiTreeError, MainCaseString, mainCase } from '../shared';
import { assertIsNode } from './Node';
import { DiscriminatorNode } from './discriminatorNodes';
import { PdaLinkNode, pdaLinkNode } from './linkNodes';
import { StructTypeNode, structTypeNode } from './typeNodes';
import {
ResolveNestedTypeNode,
StructTypeNode,
structTypeNode,
} from './typeNodes';
import { createTypeNodeFromIdl } from './typeNodes/TypeNode';

export type AccountNode = {
export interface AccountNode<
TData extends
ResolveNestedTypeNode<StructTypeNode> = ResolveNestedTypeNode<StructTypeNode>,
TPda extends PdaLinkNode | undefined = PdaLinkNode | undefined,
TDiscriminators extends DiscriminatorNode[] | undefined =
| DiscriminatorNode[]
| undefined,
> {
readonly kind: 'accountNode';

// Children.
readonly data: StructTypeNode;
readonly pda?: PdaLinkNode;
readonly discriminators?: DiscriminatorNode[];
readonly data: TData;
readonly pda?: TPda;
readonly discriminators?: TDiscriminators;

// Data.
readonly name: MainCaseString;
readonly idlName: string;
readonly docs: string[];
readonly size?: number | null;
};
}

export type AccountNodeInput = Omit<Partial<AccountNode>, 'kind' | 'name'> & {
export type AccountNodeInput<
TData extends
ResolveNestedTypeNode<StructTypeNode> = ResolveNestedTypeNode<StructTypeNode>,
TPda extends PdaLinkNode | undefined = PdaLinkNode | undefined,
TDiscriminators extends DiscriminatorNode[] | undefined =
| DiscriminatorNode[]
| undefined,
> = Omit<
Partial<AccountNode<TData, TPda, TDiscriminators>>,
'kind' | 'name'
> & {
readonly name: string;
};

export function accountNode(input: AccountNodeInput): AccountNode {
export function accountNode<
TData extends ResolveNestedTypeNode<StructTypeNode> = StructTypeNode<[]>,
TPda extends PdaLinkNode | undefined = undefined,
const TDiscriminators extends DiscriminatorNode[] | undefined = undefined,
>(
input: AccountNodeInput<TData, TPda, TDiscriminators>
): AccountNode<TData, TPda, TDiscriminators> {
if (!input.name) {
throw new InvalidKinobiTreeError('AccountNode must have a name.');
}
return {
kind: 'accountNode',

// Children.
data: input.data ?? structTypeNode([]),
data: (input.data ?? structTypeNode([])) as TData,
pda: input.pda,
discriminators: input.discriminators,

Expand All @@ -45,7 +72,9 @@ export function accountNode(input: AccountNodeInput): AccountNode {
};
}

export function accountNodeFromIdl(idl: Partial<IdlAccount>): AccountNode {
export function accountNodeFromIdl(
idl: Partial<IdlAccount>
): AccountNode<StructTypeNode> {
const idlName = idl.name ?? '';
const name = mainCase(idlName);
const idlStruct = idl.type ?? { kind: 'struct', fields: [] };
Expand Down
14 changes: 8 additions & 6 deletions src/nodes/DefinedTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,28 @@ import type { IdlDefinedType } from '../idl';
import { InvalidKinobiTreeError, MainCaseString, mainCase } from '../shared';
import { TypeNode, createTypeNodeFromIdl } from './typeNodes/TypeNode';

export type DefinedTypeNode = {
export interface DefinedTypeNode<TType extends TypeNode = TypeNode> {
readonly kind: 'definedTypeNode';

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

// Data.
readonly name: MainCaseString;
readonly idlName: string;
readonly docs: string[];
};
}

export type DefinedTypeNodeInput = {
export type DefinedTypeNodeInput<TType extends TypeNode = TypeNode> = {
readonly name: string;
readonly type: TypeNode;
readonly type: TType;
readonly idlName?: string;
readonly docs?: string[];
};

export function definedTypeNode(input: DefinedTypeNodeInput): DefinedTypeNode {
export function definedTypeNode<TType extends TypeNode>(
input: DefinedTypeNodeInput<TType>
): DefinedTypeNode<TType> {
if (!input.name) {
throw new InvalidKinobiTreeError('DefinedTypeNode must have a name.');
}
Expand Down
4 changes: 2 additions & 2 deletions src/nodes/ErrorNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
mainCase,
} from '../shared';

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

// Data.
Expand All @@ -15,7 +15,7 @@ export type ErrorNode = {
readonly code: number;
readonly message: string;
readonly docs: string[];
};
}

export type ErrorNodeInput = Omit<
PartialExcept<ErrorNode, 'name' | 'code' | 'message'>,
Expand Down
29 changes: 21 additions & 8 deletions src/nodes/InstructionAccountNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,43 @@ import { IdlInstructionAccount } from '../idl';
import { MainCaseString, PartialExcept, mainCase } from '../shared';
import { InstructionInputValueNode } from './contextualValueNodes';

export type InstructionAccountNode = {
export interface InstructionAccountNode<
TDefaultValue extends InstructionInputValueNode | undefined =
| InstructionInputValueNode
| undefined,
> {
readonly kind: 'instructionAccountNode';

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

// Data.
readonly name: MainCaseString;
readonly isWritable: boolean;
readonly isSigner: boolean | 'either';
readonly isOptional: boolean;
readonly docs: string[];
};
}

export type InstructionAccountNodeInput = Omit<
PartialExcept<InstructionAccountNode, 'isWritable' | 'isSigner'>,
export type InstructionAccountNodeInput<
TDefaultValue extends InstructionInputValueNode | undefined =
| InstructionInputValueNode
| undefined,
> = Omit<
PartialExcept<
InstructionAccountNode<TDefaultValue>,
'isWritable' | 'isSigner'
>,
'kind' | 'name'
> & {
readonly name: string;
};

export function instructionAccountNode(
input: InstructionAccountNodeInput
): InstructionAccountNode {
export function instructionAccountNode<
TDefaultValue extends InstructionInputValueNode | undefined = undefined,
>(
input: InstructionAccountNodeInput<TDefaultValue>
): InstructionAccountNode<TDefaultValue> {
return {
kind: 'instructionAccountNode',
name: mainCase(input.name),
Expand Down
26 changes: 18 additions & 8 deletions src/nodes/InstructionArgumentNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,40 @@ import {
} from './typeNodes';
import { VALUE_NODES } from './valueNodes';

export type InstructionArgumentNode = {
export interface InstructionArgumentNode<
TDefaultValue extends InstructionInputValueNode | undefined =
| InstructionInputValueNode
| undefined,
> {
readonly kind: 'instructionArgumentNode';

// Children.
readonly type: TypeNode;
readonly defaultValue?: InstructionInputValueNode;
readonly defaultValue?: TDefaultValue;

// Data.
readonly name: MainCaseString;
readonly docs: string[];
readonly defaultValueStrategy?: 'optional' | 'omitted';
};
}

export type InstructionArgumentNodeInput = {
export type InstructionArgumentNodeInput<
TDefaultValue extends InstructionInputValueNode | undefined =
| InstructionInputValueNode
| undefined,
> = {
readonly name: string;
readonly type: TypeNode;
readonly docs?: string[];
readonly defaultValue?: InstructionInputValueNode;
readonly defaultValue?: TDefaultValue;
readonly defaultValueStrategy?: 'optional' | 'omitted';
};

export function instructionArgumentNode(
input: InstructionArgumentNodeInput
): InstructionArgumentNode {
export function instructionArgumentNode<
TDefaultValue extends InstructionInputValueNode | undefined = undefined,
>(
input: InstructionArgumentNodeInput<TDefaultValue>
): InstructionArgumentNode<TDefaultValue> {
if (!input.name) {
throw new InvalidKinobiTreeError(
'InstructionArgumentNode must have a name.'
Expand Down
26 changes: 16 additions & 10 deletions src/nodes/InstructionByteDeltaNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,34 @@ import { ArgumentValueNode, ResolverValueNode } from './contextualValueNodes';
import { AccountLinkNode } from './linkNodes';
import { NumberValueNode } from './valueNodes';

export type InstructionByteDeltaNode = {
type InstructionByteDeltaNodeValue =
| NumberValueNode
| AccountLinkNode
| ArgumentValueNode
| ResolverValueNode;

export interface InstructionByteDeltaNode<
TValue extends InstructionByteDeltaNodeValue = InstructionByteDeltaNodeValue,
> {
readonly kind: 'instructionByteDeltaNode';

// Children.
readonly value:
| NumberValueNode
| AccountLinkNode
| ArgumentValueNode
| ResolverValueNode;
readonly value: TValue;

// Data.
readonly withHeader: boolean;
readonly subtract?: boolean;
};
}

export function instructionByteDeltaNode(
value: InstructionByteDeltaNode['value'],
export function instructionByteDeltaNode<
TValue extends InstructionByteDeltaNodeValue,
>(
value: TValue,
options: {
withHeader?: boolean;
subtract?: boolean;
} = {}
): InstructionByteDeltaNode {
): InstructionByteDeltaNode<TValue> {
return {
kind: 'instructionByteDeltaNode',
value,
Expand Down
Loading

0 comments on commit 8406a69

Please sign in to comment.