Skip to content

Commit

Permalink
Add preOffsetTypeNode and postOffsetTypeNode (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva authored Apr 9, 2024
1 parent 6307b3a commit 8eaf605
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/happy-ducks-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@metaplex-foundation/kinobi": minor
---

Add preOffsetTypeNode and postOffsetTypeNode
13 changes: 10 additions & 3 deletions src/nodes/typeNodes/NestedTypeNode.ts
Original file line number Diff line number Diff line change
@@ -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 extends TypeNode> =
| TType
| ((FixedSizeTypeNode | SizePrefixTypeNode) & {
type: NestedTypeNode<TType>;
});
| FixedSizeTypeNode<NestedTypeNode<TType>>
| PostOffsetTypeNode<NestedTypeNode<TType>>
| PreOffsetTypeNode<NestedTypeNode<TType>>
| SizePrefixTypeNode<NestedTypeNode<TType>>;

export function resolveNestedTypeNode<TType extends TypeNode>(
typeNode: NestedTypeNode<TType>
): TType {
switch (typeNode.kind) {
case 'fixedSizeTypeNode':
case 'postOffsetTypeNode':
case 'preOffsetTypeNode':
case 'sizePrefixTypeNode':
return resolveNestedTypeNode<TType>(
typeNode.type as NestedTypeNode<TType>
Expand All @@ -32,6 +37,8 @@ export function transformNestedTypeNode<
): NestedTypeNode<TTo> {
switch (typeNode.kind) {
case 'fixedSizeTypeNode':
case 'postOffsetTypeNode':
case 'preOffsetTypeNode':
case 'sizePrefixTypeNode':
return {
...typeNode,
Expand Down
20 changes: 20 additions & 0 deletions src/nodes/typeNodes/PostOffsetTypeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TypeNode } from './TypeNode';

export interface PostOffsetTypeNode<TType extends TypeNode = TypeNode> {
readonly kind: 'postOffsetTypeNode';

// Children.
readonly type: TType;

// Data.
readonly offset: number;
readonly strategy?: 'relative' | 'absolute' | 'padded' | 'preOffset';
}

export function postOffsetTypeNode<TType extends TypeNode>(
type: TType,
offset: number,
strategy?: PostOffsetTypeNode['strategy']
): PostOffsetTypeNode<TType> {
return { kind: 'postOffsetTypeNode', type, offset, strategy };
}
20 changes: 20 additions & 0 deletions src/nodes/typeNodes/PreOffsetTypeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TypeNode } from './TypeNode';

export interface PreOffsetTypeNode<TType extends TypeNode = TypeNode> {
readonly kind: 'preOffsetTypeNode';

// Children.
readonly type: TType;

// Data.
readonly offset: number;
readonly strategy?: 'relative' | 'absolute' | 'padded';
}

export function preOffsetTypeNode<TType extends TypeNode>(
type: TType,
offset: number,
strategy?: PreOffsetTypeNode['strategy']
): PreOffsetTypeNode<TType> {
return { kind: 'preOffsetTypeNode', type, offset, strategy };
}
6 changes: 6 additions & 0 deletions src/nodes/typeNodes/TypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -37,6 +39,8 @@ export type StandaloneTypeNode =
| MapTypeNode
| NumberTypeNode
| OptionTypeNode
| PostOffsetTypeNode
| PreOffsetTypeNode
| PublicKeyTypeNode
| SetTypeNode
| SizePrefixTypeNode
Expand All @@ -55,6 +59,8 @@ export const STANDALONE_TYPE_NODE_KINDS = [
'mapTypeNode',
'numberTypeNode',
'optionTypeNode',
'postOffsetTypeNode',
'preOffsetTypeNode',
'publicKeyTypeNode',
'setTypeNode',
'sizePrefixTypeNode',
Expand Down
2 changes: 2 additions & 0 deletions src/nodes/typeNodes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
4 changes: 4 additions & 0 deletions src/visitors/getDebugStringVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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] : [];
}
Expand Down
20 changes: 20 additions & 0 deletions src/visitors/identityVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import {
pdaNode,
pdaSeedValueNode,
pdaValueNode,
postOffsetTypeNode,
preOffsetTypeNode,
prefixedCountNode,
programNode,
removeNullAndAssertIsNodeFilter,
Expand Down Expand Up @@ -609,5 +611,23 @@ export function identityVisitor<TNodeKind extends NodeKind = NodeKind>(
};
}

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<Node, TNodeKind>;
}
12 changes: 12 additions & 0 deletions src/visitors/mergeVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,5 +335,17 @@ export function mergeVisitor<TReturn, TNodeKind extends NodeKind = NodeKind>(
};
}

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<TReturn, TNodeKind>;
}
32 changes: 32 additions & 0 deletions test/visitors/nodes/typeNodes/PostOffsetTypeNode.test.ts
Original file line number Diff line number Diff line change
@@ -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]`
);
32 changes: 32 additions & 0 deletions test/visitors/nodes/typeNodes/PreOffsetTypeNode.test.ts
Original file line number Diff line number Diff line change
@@ -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]`
);

0 comments on commit 8eaf605

Please sign in to comment.