From 8eaf605135cc857609e4d9591dfa8632b9ad0966 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Apr 2024 11:11:35 +0100 Subject: [PATCH] Add preOffsetTypeNode and postOffsetTypeNode (#197) --- .changeset/happy-ducks-behave.md | 5 +++ src/nodes/typeNodes/NestedTypeNode.ts | 13 ++++++-- src/nodes/typeNodes/PostOffsetTypeNode.ts | 20 ++++++++++++ src/nodes/typeNodes/PreOffsetTypeNode.ts | 20 ++++++++++++ src/nodes/typeNodes/TypeNode.ts | 6 ++++ src/nodes/typeNodes/index.ts | 2 ++ src/visitors/getDebugStringVisitor.ts | 4 +++ src/visitors/identityVisitor.ts | 20 ++++++++++++ src/visitors/mergeVisitor.ts | 12 +++++++ .../typeNodes/PostOffsetTypeNode.test.ts | 32 +++++++++++++++++++ .../nodes/typeNodes/PreOffsetTypeNode.test.ts | 32 +++++++++++++++++++ 11 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 .changeset/happy-ducks-behave.md create mode 100644 src/nodes/typeNodes/PostOffsetTypeNode.ts create mode 100644 src/nodes/typeNodes/PreOffsetTypeNode.ts create mode 100644 test/visitors/nodes/typeNodes/PostOffsetTypeNode.test.ts create mode 100644 test/visitors/nodes/typeNodes/PreOffsetTypeNode.test.ts diff --git a/.changeset/happy-ducks-behave.md b/.changeset/happy-ducks-behave.md new file mode 100644 index 00000000..e91855f5 --- /dev/null +++ b/.changeset/happy-ducks-behave.md @@ -0,0 +1,5 @@ +--- +"@metaplex-foundation/kinobi": minor +--- + +Add preOffsetTypeNode and postOffsetTypeNode diff --git a/src/nodes/typeNodes/NestedTypeNode.ts b/src/nodes/typeNodes/NestedTypeNode.ts index 5f13dd16..58bfa0fc 100644 --- a/src/nodes/typeNodes/NestedTypeNode.ts +++ b/src/nodes/typeNodes/NestedTypeNode.ts @@ -1,19 +1,24 @@ import { Node, isNode } from '../Node'; import { FixedSizeTypeNode } from './FixedSizeTypeNode'; +import { PostOffsetTypeNode } from './PostOffsetTypeNode'; +import { PreOffsetTypeNode } from './PreOffsetTypeNode'; import { SizePrefixTypeNode } from './SizePrefixTypeNode'; import { TYPE_NODES, TypeNode } from './TypeNode'; export type NestedTypeNode = | TType - | ((FixedSizeTypeNode | SizePrefixTypeNode) & { - type: NestedTypeNode; - }); + | FixedSizeTypeNode> + | PostOffsetTypeNode> + | PreOffsetTypeNode> + | SizePrefixTypeNode>; export function resolveNestedTypeNode( typeNode: NestedTypeNode ): TType { switch (typeNode.kind) { case 'fixedSizeTypeNode': + case 'postOffsetTypeNode': + case 'preOffsetTypeNode': case 'sizePrefixTypeNode': return resolveNestedTypeNode( typeNode.type as NestedTypeNode @@ -32,6 +37,8 @@ export function transformNestedTypeNode< ): NestedTypeNode { switch (typeNode.kind) { case 'fixedSizeTypeNode': + case 'postOffsetTypeNode': + case 'preOffsetTypeNode': case 'sizePrefixTypeNode': return { ...typeNode, diff --git a/src/nodes/typeNodes/PostOffsetTypeNode.ts b/src/nodes/typeNodes/PostOffsetTypeNode.ts new file mode 100644 index 00000000..017803c2 --- /dev/null +++ b/src/nodes/typeNodes/PostOffsetTypeNode.ts @@ -0,0 +1,20 @@ +import { TypeNode } from './TypeNode'; + +export interface PostOffsetTypeNode { + readonly kind: 'postOffsetTypeNode'; + + // Children. + readonly type: TType; + + // Data. + readonly offset: number; + readonly strategy?: 'relative' | 'absolute' | 'padded' | 'preOffset'; +} + +export function postOffsetTypeNode( + type: TType, + offset: number, + strategy?: PostOffsetTypeNode['strategy'] +): PostOffsetTypeNode { + return { kind: 'postOffsetTypeNode', type, offset, strategy }; +} diff --git a/src/nodes/typeNodes/PreOffsetTypeNode.ts b/src/nodes/typeNodes/PreOffsetTypeNode.ts new file mode 100644 index 00000000..94cc68a4 --- /dev/null +++ b/src/nodes/typeNodes/PreOffsetTypeNode.ts @@ -0,0 +1,20 @@ +import { TypeNode } from './TypeNode'; + +export interface PreOffsetTypeNode { + readonly kind: 'preOffsetTypeNode'; + + // Children. + readonly type: TType; + + // Data. + readonly offset: number; + readonly strategy?: 'relative' | 'absolute' | 'padded'; +} + +export function preOffsetTypeNode( + type: TType, + offset: number, + strategy?: PreOffsetTypeNode['strategy'] +): PreOffsetTypeNode { + return { kind: 'preOffsetTypeNode', type, offset, strategy }; +} diff --git a/src/nodes/typeNodes/TypeNode.ts b/src/nodes/typeNodes/TypeNode.ts index 9c239e39..68b51702 100644 --- a/src/nodes/typeNodes/TypeNode.ts +++ b/src/nodes/typeNodes/TypeNode.ts @@ -16,6 +16,8 @@ import { FixedSizeTypeNode } from './FixedSizeTypeNode'; import { MapTypeNode, mapTypeNodeFromIdl } from './MapTypeNode'; import { NumberTypeNode, numberTypeNode } from './NumberTypeNode'; import { OptionTypeNode, optionTypeNodeFromIdl } from './OptionTypeNode'; +import { PostOffsetTypeNode } from './PostOffsetTypeNode'; +import { PreOffsetTypeNode } from './PreOffsetTypeNode'; import { PublicKeyTypeNode, publicKeyTypeNode } from './PublicKeyTypeNode'; import { SetTypeNode, setTypeNodeFromIdl } from './SetTypeNode'; import { SizePrefixTypeNode, sizePrefixTypeNode } from './SizePrefixTypeNode'; @@ -37,6 +39,8 @@ export type StandaloneTypeNode = | MapTypeNode | NumberTypeNode | OptionTypeNode + | PostOffsetTypeNode + | PreOffsetTypeNode | PublicKeyTypeNode | SetTypeNode | SizePrefixTypeNode @@ -55,6 +59,8 @@ export const STANDALONE_TYPE_NODE_KINDS = [ 'mapTypeNode', 'numberTypeNode', 'optionTypeNode', + 'postOffsetTypeNode', + 'preOffsetTypeNode', 'publicKeyTypeNode', 'setTypeNode', 'sizePrefixTypeNode', diff --git a/src/nodes/typeNodes/index.ts b/src/nodes/typeNodes/index.ts index c4fdf2ca..5db37b33 100644 --- a/src/nodes/typeNodes/index.ts +++ b/src/nodes/typeNodes/index.ts @@ -13,6 +13,8 @@ export * from './MapTypeNode'; export * from './NestedTypeNode'; export * from './NumberTypeNode'; export * from './OptionTypeNode'; +export * from './PostOffsetTypeNode'; +export * from './PreOffsetTypeNode'; export * from './PublicKeyTypeNode'; export * from './SetTypeNode'; export * from './SizePrefixTypeNode'; diff --git a/src/visitors/getDebugStringVisitor.ts b/src/visitors/getDebugStringVisitor.ts index 675e7e09..5a3f1929 100644 --- a/src/visitors/getDebugStringVisitor.ts +++ b/src/visitors/getDebugStringVisitor.ts @@ -126,6 +126,10 @@ function getNodeDetails(node: Node): string[] { return [node.size.toString()]; case 'fixedSizeTypeNode': return [node.size.toString()]; + case 'preOffsetTypeNode': + return [node.offset.toString(), node.strategy ?? 'relative']; + case 'postOffsetTypeNode': + return [node.offset.toString(), node.strategy ?? 'relative']; default: return 'name' in node ? [node.name] : []; } diff --git a/src/visitors/identityVisitor.ts b/src/visitors/identityVisitor.ts index ad38a315..af4ef64e 100644 --- a/src/visitors/identityVisitor.ts +++ b/src/visitors/identityVisitor.ts @@ -39,6 +39,8 @@ import { pdaNode, pdaSeedValueNode, pdaValueNode, + postOffsetTypeNode, + preOffsetTypeNode, prefixedCountNode, programNode, removeNullAndAssertIsNodeFilter, @@ -609,5 +611,23 @@ export function identityVisitor( }; } + if (castedNodeKeys.includes('preOffsetTypeNode')) { + visitor.visitPreOffsetType = function visitPreOffsetType(node) { + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + return preOffsetTypeNode(type, node.offset, node.strategy); + }; + } + + if (castedNodeKeys.includes('postOffsetTypeNode')) { + visitor.visitPostOffsetType = function visitPostOffsetType(node) { + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + return postOffsetTypeNode(type, node.offset, node.strategy); + }; + } + return visitor as Visitor; } diff --git a/src/visitors/mergeVisitor.ts b/src/visitors/mergeVisitor.ts index 38f75276..d0bff930 100644 --- a/src/visitors/mergeVisitor.ts +++ b/src/visitors/mergeVisitor.ts @@ -335,5 +335,17 @@ export function mergeVisitor( }; } + if (castedNodeKeys.includes('preOffsetTypeNode')) { + visitor.visitPreOffsetType = function visitPreOffsetType(node) { + return merge(node, visit(this)(node.type)); + }; + } + + if (castedNodeKeys.includes('postOffsetTypeNode')) { + visitor.visitPostOffsetType = function visitPostOffsetType(node) { + return merge(node, visit(this)(node.type)); + }; + } + return visitor as Visitor; } diff --git a/test/visitors/nodes/typeNodes/PostOffsetTypeNode.test.ts b/test/visitors/nodes/typeNodes/PostOffsetTypeNode.test.ts new file mode 100644 index 00000000..ad558bda --- /dev/null +++ b/test/visitors/nodes/typeNodes/PostOffsetTypeNode.test.ts @@ -0,0 +1,32 @@ +import test from 'ava'; +import { postOffsetTypeNode, stringTypeNode } from '../../../../src'; +import { + deleteNodesVisitorMacro, + getDebugStringVisitorMacro, + identityVisitorMacro, + mergeVisitorMacro, +} from '../_setup'; + +const node = postOffsetTypeNode(stringTypeNode(), 42); + +test(mergeVisitorMacro, node, 2); +test(identityVisitorMacro, node); +test(deleteNodesVisitorMacro, node, '[stringTypeNode]', null); +test(deleteNodesVisitorMacro, node, '[postOffsetTypeNode]', null); +test( + getDebugStringVisitorMacro, + node, + ` +postOffsetTypeNode [42.relative] +| stringTypeNode [utf8]` +); + +// Different strategy. +test( + 'getDebugStringVisitor: different strategy', + getDebugStringVisitorMacro, + postOffsetTypeNode(stringTypeNode(), 42, 'absolute'), + ` +postOffsetTypeNode [42.absolute] +| stringTypeNode [utf8]` +); diff --git a/test/visitors/nodes/typeNodes/PreOffsetTypeNode.test.ts b/test/visitors/nodes/typeNodes/PreOffsetTypeNode.test.ts new file mode 100644 index 00000000..5217de25 --- /dev/null +++ b/test/visitors/nodes/typeNodes/PreOffsetTypeNode.test.ts @@ -0,0 +1,32 @@ +import test from 'ava'; +import { preOffsetTypeNode, stringTypeNode } from '../../../../src'; +import { + deleteNodesVisitorMacro, + getDebugStringVisitorMacro, + identityVisitorMacro, + mergeVisitorMacro, +} from '../_setup'; + +const node = preOffsetTypeNode(stringTypeNode(), 42); + +test(mergeVisitorMacro, node, 2); +test(identityVisitorMacro, node); +test(deleteNodesVisitorMacro, node, '[stringTypeNode]', null); +test(deleteNodesVisitorMacro, node, '[preOffsetTypeNode]', null); +test( + getDebugStringVisitorMacro, + node, + ` +preOffsetTypeNode [42.relative] +| stringTypeNode [utf8]` +); + +// Different strategy. +test( + 'getDebugStringVisitor: different strategy', + getDebugStringVisitorMacro, + preOffsetTypeNode(stringTypeNode(), 42, 'absolute'), + ` +preOffsetTypeNode [42.absolute] +| stringTypeNode [utf8]` +);