Skip to content

Commit

Permalink
Add ZeroableOptionTypeNode (#206)
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva authored Apr 11, 2024
1 parent 748d8ea commit 0463a43
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/empty-knives-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@metaplex-foundation/kinobi": minor
---

Add ZeroableOptionTypeNode
5 changes: 4 additions & 1 deletion src/nodes/typeNodes/TypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { StringTypeNode, stringTypeNode } from './StringTypeNode';
import { StructFieldTypeNode } from './StructFieldTypeNode';
import { StructTypeNode, structTypeNodeFromIdl } from './StructTypeNode';
import { TupleTypeNode, tupleTypeNodeFromIdl } from './TupleTypeNode';
import { ZeroableOptionTypeNode } from './ZeroableOptionTypeNode';

// Standalone Type Node Registration.
export type StandaloneTypeNode =
Expand All @@ -53,7 +54,8 @@ export type StandaloneTypeNode =
| SolAmountTypeNode
| StringTypeNode
| StructTypeNode
| TupleTypeNode;
| TupleTypeNode
| ZeroableOptionTypeNode;
export const STANDALONE_TYPE_NODE_KINDS = [
'amountTypeNode',
'arrayTypeNode',
Expand All @@ -77,6 +79,7 @@ export const STANDALONE_TYPE_NODE_KINDS = [
'stringTypeNode',
'structTypeNode',
'tupleTypeNode',
'zeroableOptionTypeNode',
] satisfies readonly StandaloneTypeNode['kind'][];
null as unknown as StandaloneTypeNode['kind'] satisfies (typeof STANDALONE_TYPE_NODE_KINDS)[number];

Expand Down
25 changes: 25 additions & 0 deletions src/nodes/typeNodes/ZeroableOptionTypeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ConstantValueNode } from '../valueNodes';
import { TypeNode } from './TypeNode';

export interface ZeroableOptionTypeNode<
TItem extends TypeNode = TypeNode,
TZeroValue extends ConstantValueNode | undefined =
| ConstantValueNode
| undefined,
> {
readonly kind: 'zeroableOptionTypeNode';

// Children.
readonly item: TItem;
readonly zeroValue?: TZeroValue;
}

export function zeroableOptionTypeNode<
TItem extends TypeNode,
TZeroValue extends ConstantValueNode | undefined,
>(
item: TItem,
zeroValue?: TZeroValue
): ZeroableOptionTypeNode<TItem, TZeroValue> {
return { kind: 'zeroableOptionTypeNode', item, zeroValue };
}
1 change: 1 addition & 0 deletions src/nodes/typeNodes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export * from './StructFieldTypeNode';
export * from './StructTypeNode';
export * from './TupleTypeNode';
export * from './TypeNode';
export * from './ZeroableOptionTypeNode';
14 changes: 14 additions & 0 deletions src/visitors/identityVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
tupleTypeNode,
tupleValueNode,
variablePdaSeedNode,
zeroableOptionTypeNode,
} from '../nodes';
import { staticVisitor } from './staticVisitor';
import { Visitor, visit as baseVisit } from './visitor';
Expand Down Expand Up @@ -324,6 +325,19 @@ export function identityVisitor<TNodeKind extends NodeKind = NodeKind>(
};
}

if (castedNodeKeys.includes('zeroableOptionTypeNode')) {
visitor.visitZeroableOptionType = function visitZeroableOptionType(node) {
const item = visit(this)(node.item);
if (item === null) return null;
assertIsNode(item, TYPE_NODES);
const zeroValue = node.zeroValue
? visit(this)(node.zeroValue) ?? undefined
: undefined;
if (zeroValue) assertIsNode(zeroValue, 'constantValueNode');
return zeroableOptionTypeNode(item, zeroValue);
};
}

if (castedNodeKeys.includes('booleanTypeNode')) {
visitor.visitBooleanType = function visitBooleanType(node) {
const size = visit(this)(node.size);
Expand Down
9 changes: 9 additions & 0 deletions src/visitors/mergeVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ export function mergeVisitor<TReturn, TNodeKind extends NodeKind = NodeKind>(
};
}

if (castedNodeKeys.includes('zeroableOptionTypeNode')) {
visitor.visitZeroableOptionType = function visitZeroableOptionType(node) {
return merge(node, [
...visit(this)(node.item),
...(node.zeroValue ? visit(this)(node.zeroValue) : []),
]);
};
}

if (castedNodeKeys.includes('booleanTypeNode')) {
visitor.visitBooleanType = function visitBooleanType(node) {
return merge(node, visit(this)(node.size));
Expand Down
48 changes: 48 additions & 0 deletions test/visitors/nodes/typeNodes/ZeroableOptionTypeNode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import test from 'ava';
import {
constantValueNodeFromBytes,
publicKeyTypeNode,
zeroableOptionTypeNode,
} from '../../../../src';
import {
deleteNodesVisitorMacro,
getDebugStringVisitorMacro,
identityVisitorMacro,
mergeVisitorMacro,
} from '../_setup';

const node = zeroableOptionTypeNode(
publicKeyTypeNode(),
constantValueNodeFromBytes('base16', 'ff'.repeat(32))
);

test(mergeVisitorMacro, node, 5);
test(identityVisitorMacro, node);
test(deleteNodesVisitorMacro, node, '[zeroableOptionTypeNode]', null);
test(deleteNodesVisitorMacro, node, '[publicKeyTypeNode]', null);
test(
deleteNodesVisitorMacro,
node,
'[constantValueNode]',
zeroableOptionTypeNode(publicKeyTypeNode())
);
test(
getDebugStringVisitorMacro,
node,
`
zeroableOptionTypeNode
| publicKeyTypeNode
| constantValueNode
| | bytesTypeNode
| | bytesValueNode [base16.ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff]`
);

// No zero value.
test(
'getDebugStringVisitor: different strategy',
getDebugStringVisitorMacro,
zeroableOptionTypeNode(publicKeyTypeNode()),
`
zeroableOptionTypeNode
| publicKeyTypeNode`
);

0 comments on commit 0463a43

Please sign in to comment.