From 6021aa9a366ba6fcf71235a549ee775fc9f28d15 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Apr 2024 14:31:58 +0100 Subject: [PATCH] Add FixedSizeTypeNode and SizePrefixTypeNode (#191) * Add FixedSizeTypeNode and SizePrefixTypeNode * Add changeset --- .changeset/nasty-olives-scream.md | 5 +++ src/nodes/typeNodes/FixedSizeTypeNode.ts | 18 ++++++++++ src/nodes/typeNodes/SizePrefixTypeNode.ts | 17 ++++++++++ src/nodes/typeNodes/TypeNode.ts | 4 +++ src/nodes/typeNodes/index.ts | 2 ++ src/visitors/getDebugStringVisitor.ts | 2 ++ src/visitors/identityVisitor.ts | 23 +++++++++++++ src/visitors/mergeVisitor.ts | 15 ++++++++ .../nodes/typeNodes/FixedSizeTypeNode.test.ts | 31 +++++++++++++++++ .../typeNodes/SizePrefixTypeNode.test.ts | 34 +++++++++++++++++++ 10 files changed, 151 insertions(+) create mode 100644 .changeset/nasty-olives-scream.md create mode 100644 src/nodes/typeNodes/FixedSizeTypeNode.ts create mode 100644 src/nodes/typeNodes/SizePrefixTypeNode.ts create mode 100644 test/visitors/nodes/typeNodes/FixedSizeTypeNode.test.ts create mode 100644 test/visitors/nodes/typeNodes/SizePrefixTypeNode.test.ts diff --git a/.changeset/nasty-olives-scream.md b/.changeset/nasty-olives-scream.md new file mode 100644 index 000000000..c78cfbb56 --- /dev/null +++ b/.changeset/nasty-olives-scream.md @@ -0,0 +1,5 @@ +--- +"@metaplex-foundation/kinobi": minor +--- + +Add FixedSizeTypeNode and SizePrefixTypeNode diff --git a/src/nodes/typeNodes/FixedSizeTypeNode.ts b/src/nodes/typeNodes/FixedSizeTypeNode.ts new file mode 100644 index 000000000..a6e097843 --- /dev/null +++ b/src/nodes/typeNodes/FixedSizeTypeNode.ts @@ -0,0 +1,18 @@ +import { TypeNode } from './TypeNode'; + +export type FixedSizeTypeNode = { + readonly kind: 'fixedSizeTypeNode'; + + // Children. + readonly type: TypeNode; + + // Data. + readonly size: number; +}; + +export function fixedSizeTypeNode( + type: TypeNode, + size: number +): FixedSizeTypeNode { + return { kind: 'fixedSizeTypeNode', type, size }; +} diff --git a/src/nodes/typeNodes/SizePrefixTypeNode.ts b/src/nodes/typeNodes/SizePrefixTypeNode.ts new file mode 100644 index 000000000..bb58729e1 --- /dev/null +++ b/src/nodes/typeNodes/SizePrefixTypeNode.ts @@ -0,0 +1,17 @@ +import { NumberTypeNode } from './NumberTypeNode'; +import { TypeNode } from './TypeNode'; + +export type SizePrefixTypeNode = { + readonly kind: 'sizePrefixTypeNode'; + + // Children. + readonly type: TypeNode; + readonly prefix: NumberTypeNode; +}; + +export function sizePrefixTypeNode( + type: TypeNode, + prefix: NumberTypeNode +): SizePrefixTypeNode { + return { kind: 'sizePrefixTypeNode', type, prefix }; +} diff --git a/src/nodes/typeNodes/TypeNode.ts b/src/nodes/typeNodes/TypeNode.ts index 3e65d93af..dccef3f02 100644 --- a/src/nodes/typeNodes/TypeNode.ts +++ b/src/nodes/typeNodes/TypeNode.ts @@ -14,11 +14,13 @@ import { EnumEmptyVariantTypeNode } from './EnumEmptyVariantTypeNode'; import { EnumStructVariantTypeNode } from './EnumStructVariantTypeNode'; import { EnumTupleVariantTypeNode } from './EnumTupleVariantTypeNode'; import { EnumTypeNode, enumTypeNodeFromIdl } from './EnumTypeNode'; +import { FixedSizeTypeNode } from './FixedSizeTypeNode'; import { MapTypeNode, mapTypeNodeFromIdl } from './MapTypeNode'; import { NumberTypeNode, numberTypeNode } from './NumberTypeNode'; import { OptionTypeNode, optionTypeNodeFromIdl } from './OptionTypeNode'; import { PublicKeyTypeNode, publicKeyTypeNode } from './PublicKeyTypeNode'; import { SetTypeNode, setTypeNodeFromIdl } from './SetTypeNode'; +import { SizePrefixTypeNode } from './SizePrefixTypeNode'; import { SolAmountTypeNode } from './SolAmountTypeNode'; import { StringTypeNode, stringTypeNode } from './StringTypeNode'; import { StructFieldTypeNode } from './StructFieldTypeNode'; @@ -34,11 +36,13 @@ export const STANDALONE_TYPE_NODES = { bytesTypeNode: {} as BytesTypeNode, dateTimeTypeNode: {} as DateTimeTypeNode, enumTypeNode: {} as EnumTypeNode, + fixedSizeTypeNode: {} as FixedSizeTypeNode, mapTypeNode: {} as MapTypeNode, numberTypeNode: {} as NumberTypeNode, optionTypeNode: {} as OptionTypeNode, publicKeyTypeNode: {} as PublicKeyTypeNode, setTypeNode: {} as SetTypeNode, + sizePrefixTypeNode: {} as SizePrefixTypeNode, solAmountTypeNode: {} as SolAmountTypeNode, stringTypeNode: {} as StringTypeNode, structTypeNode: {} as StructTypeNode, diff --git a/src/nodes/typeNodes/index.ts b/src/nodes/typeNodes/index.ts index 18b816340..89aed51dc 100644 --- a/src/nodes/typeNodes/index.ts +++ b/src/nodes/typeNodes/index.ts @@ -8,11 +8,13 @@ export * from './EnumStructVariantTypeNode'; export * from './EnumTupleVariantTypeNode'; export * from './EnumTypeNode'; export * from './EnumVariantTypeNode'; +export * from './FixedSizeTypeNode'; export * from './MapTypeNode'; export * from './NumberTypeNode'; export * from './OptionTypeNode'; export * from './PublicKeyTypeNode'; export * from './SetTypeNode'; +export * from './SizePrefixTypeNode'; export * from './SolAmountTypeNode'; export * from './StringTypeNode'; export * from './StructFieldTypeNode'; diff --git a/src/visitors/getDebugStringVisitor.ts b/src/visitors/getDebugStringVisitor.ts index 23cc584f9..cf52fcc1f 100644 --- a/src/visitors/getDebugStringVisitor.ts +++ b/src/visitors/getDebugStringVisitor.ts @@ -124,6 +124,8 @@ function getNodeDetails(node: Node): string[] { return [node.name, ...(node.offset > 0 ? [`offset:${node.offset}`] : [])]; case 'sizeDiscriminatorNode': return [node.size.toString()]; + case 'fixedSizeTypeNode': + return [node.size.toString()]; default: return 'name' in node ? [node.name] : []; } diff --git a/src/visitors/identityVisitor.ts b/src/visitors/identityVisitor.ts index fbf5a5940..929b925d9 100644 --- a/src/visitors/identityVisitor.ts +++ b/src/visitors/identityVisitor.ts @@ -26,6 +26,7 @@ import { enumTupleVariantTypeNode, enumTypeNode, enumValueNode, + fixedSizeTypeNode, instructionAccountNode, instructionArgumentNode, instructionByteDeltaNode, @@ -45,6 +46,7 @@ import { rootNode, setTypeNode, setValueNode, + sizePrefixTypeNode, solAmountTypeNode, someValueNode, stringTypeNode, @@ -605,5 +607,26 @@ export function identityVisitor( }; } + if (castedNodeKeys.includes('fixedSizeTypeNode')) { + visitor.visitFixedSizeType = function visitFixedSizeType(node) { + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + return fixedSizeTypeNode(type, node.size); + }; + } + + if (castedNodeKeys.includes('sizePrefixTypeNode')) { + visitor.visitSizePrefixType = function visitSizePrefixType(node) { + const prefix = visit(this)(node.prefix); + if (prefix === null) return null; + assertIsNode(prefix, 'numberTypeNode'); + const type = visit(this)(node.type); + if (type === null) return null; + assertIsNode(type, TYPE_NODES); + return sizePrefixTypeNode(type, prefix); + }; + } + return visitor as Visitor; } diff --git a/src/visitors/mergeVisitor.ts b/src/visitors/mergeVisitor.ts index 810e386e8..84c4e31f7 100644 --- a/src/visitors/mergeVisitor.ts +++ b/src/visitors/mergeVisitor.ts @@ -332,5 +332,20 @@ export function mergeVisitor( }; } + if (castedNodeKeys.includes('fixedSizeTypeNode')) { + visitor.visitFixedSizeType = function visitFixedSizeType(node) { + return merge(node, visit(this)(node.type)); + }; + } + + if (castedNodeKeys.includes('sizePrefixTypeNode')) { + visitor.visitSizePrefixType = function visitSizePrefixType(node) { + return merge(node, [ + ...visit(this)(node.prefix), + ...visit(this)(node.type), + ]); + }; + } + return visitor as Visitor; } diff --git a/test/visitors/nodes/typeNodes/FixedSizeTypeNode.test.ts b/test/visitors/nodes/typeNodes/FixedSizeTypeNode.test.ts new file mode 100644 index 000000000..976a9cb4c --- /dev/null +++ b/test/visitors/nodes/typeNodes/FixedSizeTypeNode.test.ts @@ -0,0 +1,31 @@ +import test from 'ava'; +import { + fixedSizeTypeNode, + remainderSizeNode, + stringTypeNode, +} from '../../../../src'; +import { + deleteNodesVisitorMacro, + getDebugStringVisitorMacro, + identityVisitorMacro, + mergeVisitorMacro, +} from '../_setup'; + +const node = fixedSizeTypeNode( + stringTypeNode({ size: remainderSizeNode() }), + 42 +); + +test(mergeVisitorMacro, node, 3); +test(identityVisitorMacro, node); +test(deleteNodesVisitorMacro, node, '[stringTypeNode]', null); +test(deleteNodesVisitorMacro, node, '[fixedSizeTypeNode]', null); +test( + getDebugStringVisitorMacro, + node, + ` +fixedSizeTypeNode [42] +| stringTypeNode [utf8] +| | remainderSizeNode +` +); diff --git a/test/visitors/nodes/typeNodes/SizePrefixTypeNode.test.ts b/test/visitors/nodes/typeNodes/SizePrefixTypeNode.test.ts new file mode 100644 index 000000000..198d6bc41 --- /dev/null +++ b/test/visitors/nodes/typeNodes/SizePrefixTypeNode.test.ts @@ -0,0 +1,34 @@ +import test from 'ava'; +import { + numberTypeNode, + remainderSizeNode, + sizePrefixTypeNode, + stringTypeNode, +} from '../../../../src'; +import { + deleteNodesVisitorMacro, + getDebugStringVisitorMacro, + identityVisitorMacro, + mergeVisitorMacro, +} from '../_setup'; + +const node = sizePrefixTypeNode( + stringTypeNode({ size: remainderSizeNode() }), + numberTypeNode('u32') +); + +test(mergeVisitorMacro, node, 4); +test(identityVisitorMacro, node); +test(deleteNodesVisitorMacro, node, '[sizePrefixTypeNode]', null); +test(deleteNodesVisitorMacro, node, '[stringTypeNode]', null); +test(deleteNodesVisitorMacro, node, '[numberTypeNode]', null); +test( + getDebugStringVisitorMacro, + node, + ` +sizePrefixTypeNode +| numberTypeNode [u32] +| stringTypeNode [utf8] +| | remainderSizeNode +` +);