From a9b2aea596a57aed54e5eb86dad35c901bc84e25 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 20:17:58 +0000 Subject: [PATCH 01/12] Add value nodes --- src/nodes/Node.ts | 4 ++- src/nodes/valueNodes/ArrayValueNode.ts | 23 ++++++++++++++++ src/nodes/valueNodes/BooleanValueNode.ts | 24 ++++++++++++++++ src/nodes/valueNodes/NumberValueNode.ts | 22 +++++++++++++++ src/nodes/valueNodes/PublicKeyValueNode.ts | 26 ++++++++++++++++++ src/nodes/valueNodes/StringValueNode.ts | 22 +++++++++++++++ src/nodes/valueNodes/ValueNode.ts | 32 ++++++++++++++++++++++ src/nodes/valueNodes/index.ts | 6 ++++ 8 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/nodes/valueNodes/ArrayValueNode.ts create mode 100644 src/nodes/valueNodes/BooleanValueNode.ts create mode 100644 src/nodes/valueNodes/NumberValueNode.ts create mode 100644 src/nodes/valueNodes/PublicKeyValueNode.ts create mode 100644 src/nodes/valueNodes/StringValueNode.ts create mode 100644 src/nodes/valueNodes/ValueNode.ts create mode 100644 src/nodes/valueNodes/index.ts diff --git a/src/nodes/Node.ts b/src/nodes/Node.ts index b5189aa51..9035f41c5 100644 --- a/src/nodes/Node.ts +++ b/src/nodes/Node.ts @@ -10,6 +10,7 @@ import type { ProgramNode } from './ProgramNode'; import type { RootNode } from './RootNode'; import { REGISTERED_SIZE_NODES } from './sizeNodes'; import { REGISTERED_TYPE_NODES } from './typeNodes'; +import { REGISTERED_VALUE_NODES } from './valueNodes'; const REGISTERED_NODES = { rootNode: {} as RootNode, @@ -24,8 +25,9 @@ const REGISTERED_NODES = { definedTypeNode: {} as DefinedTypeNode, // Groups. - ...REGISTERED_TYPE_NODES, ...REGISTERED_SIZE_NODES, + ...REGISTERED_TYPE_NODES, + ...REGISTERED_VALUE_NODES, }; export const REGISTERED_NODES_KEYS = Object.keys( diff --git a/src/nodes/valueNodes/ArrayValueNode.ts b/src/nodes/valueNodes/ArrayValueNode.ts new file mode 100644 index 000000000..21c8c166d --- /dev/null +++ b/src/nodes/valueNodes/ArrayValueNode.ts @@ -0,0 +1,23 @@ +import { Node } from '../Node'; +import { ValueNode } from '../ValueNode'; + +export type ArrayValueNode = { + readonly kind: 'arrayValueNode'; + readonly items: ValueNode[]; +}; + +export function arrayValueNode(items: ValueNode[]): ArrayValueNode { + return { kind: 'arrayValueNode', items }; +} + +export function isArrayValueNode(node: Node | null): node is ArrayValueNode { + return !!node && node.kind === 'arrayValueNode'; +} + +export function assertArrayValueNode( + node: Node | null +): asserts node is ArrayValueNode { + if (!isArrayValueNode(node)) { + throw new Error(`Expected arrayValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/BooleanValueNode.ts b/src/nodes/valueNodes/BooleanValueNode.ts new file mode 100644 index 000000000..c6d6e2c68 --- /dev/null +++ b/src/nodes/valueNodes/BooleanValueNode.ts @@ -0,0 +1,24 @@ +import { Node } from '../Node'; + +export type BooleanValueNode = { + readonly kind: 'booleanTypeNode'; + readonly boolean: boolean; +}; + +export function booleanTypeNode(boolean: boolean): BooleanValueNode { + return { kind: 'booleanTypeNode', boolean }; +} + +export function isBooleanValueNode( + node: Node | null +): node is BooleanValueNode { + return !!node && node.kind === 'booleanTypeNode'; +} + +export function assertBooleanValueNode( + node: Node | null +): asserts node is BooleanValueNode { + if (!isBooleanValueNode(node)) { + throw new Error(`Expected booleanTypeNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/NumberValueNode.ts b/src/nodes/valueNodes/NumberValueNode.ts new file mode 100644 index 000000000..aee5c4cc0 --- /dev/null +++ b/src/nodes/valueNodes/NumberValueNode.ts @@ -0,0 +1,22 @@ +import { Node } from '../Node'; + +export type NumberValueNode = { + readonly kind: 'numberValueNode'; + readonly number: number; +}; + +export function numberValueNode(number: number): NumberValueNode { + return { kind: 'numberValueNode', number }; +} + +export function isNumberValueNode(node: Node | null): node is NumberValueNode { + return !!node && node.kind === 'numberValueNode'; +} + +export function assertNumberValueNode( + node: Node | null +): asserts node is NumberValueNode { + if (!isNumberValueNode(node)) { + throw new Error(`Expected numberValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/PublicKeyValueNode.ts b/src/nodes/valueNodes/PublicKeyValueNode.ts new file mode 100644 index 000000000..1d7cbc3f0 --- /dev/null +++ b/src/nodes/valueNodes/PublicKeyValueNode.ts @@ -0,0 +1,26 @@ +import { Node } from '../Node'; + +export type PublicKeyValueNode = { + readonly kind: 'publicKeyValueNode'; + readonly publicKey: string; +}; + +export function publicKeyValueNode(publicKey: string): PublicKeyValueNode { + return { kind: 'publicKeyValueNode', publicKey }; +} + +export function isPublicKeyValueNode( + node: Node | null +): node is PublicKeyValueNode { + return !!node && node.kind === 'publicKeyValueNode'; +} + +export function assertPublicKeyValueNode( + node: Node | null +): asserts node is PublicKeyValueNode { + if (!isPublicKeyValueNode(node)) { + throw new Error( + `Expected publicKeyValueNode, got ${node?.kind ?? 'null'}.` + ); + } +} diff --git a/src/nodes/valueNodes/StringValueNode.ts b/src/nodes/valueNodes/StringValueNode.ts new file mode 100644 index 000000000..ff7265509 --- /dev/null +++ b/src/nodes/valueNodes/StringValueNode.ts @@ -0,0 +1,22 @@ +import { Node } from '../Node'; + +export type StringValueNode = { + readonly kind: 'stringValueNode'; + readonly string: string; +}; + +export function stringValueNode(string: string): StringValueNode { + return { kind: 'stringValueNode', string }; +} + +export function isStringValueNode(node: Node | null): node is StringValueNode { + return !!node && node.kind === 'stringValueNode'; +} + +export function assertStringValueNode( + node: Node | null +): asserts node is StringValueNode { + if (!isStringValueNode(node)) { + throw new Error(`Expected stringValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/ValueNode.ts b/src/nodes/valueNodes/ValueNode.ts new file mode 100644 index 000000000..9906c7f25 --- /dev/null +++ b/src/nodes/valueNodes/ValueNode.ts @@ -0,0 +1,32 @@ +import { Node } from '../Node'; +import type { PublicKeyValueNode } from '../ValueNode'; +import type { ArrayValueNode } from './ArrayValueNode'; +import type { BooleanValueNode } from './BooleanValueNode'; +import type { NumberValueNode } from './NumberValueNode'; +import type { StringValueNode } from './StringValueNode'; + +export const REGISTERED_VALUE_NODES = { + arrayValueNode: {} as ArrayValueNode, + booleanValueNode: {} as BooleanValueNode, + numberValueNode: {} as NumberValueNode, + publicKeyValueNode: {} as PublicKeyValueNode, + stringValueNode: {} as StringValueNode, +}; + +export const REGISTERED_VALUE_NODE_KEYS = Object.keys( + REGISTERED_VALUE_NODES +) as (keyof typeof REGISTERED_VALUE_NODES)[]; + +export type RegisteredValueNodes = typeof REGISTERED_VALUE_NODES; + +export type ValueNode = RegisteredValueNodes[keyof RegisteredValueNodes]; + +export function isValueNode(node: Node | null): node is ValueNode { + return !!node && (REGISTERED_VALUE_NODE_KEYS as string[]).includes(node.kind); +} + +export function assertValueNode(node: Node | null): asserts node is ValueNode { + if (!isValueNode(node)) { + throw new Error(`Expected typeNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/index.ts b/src/nodes/valueNodes/index.ts new file mode 100644 index 000000000..185247fab --- /dev/null +++ b/src/nodes/valueNodes/index.ts @@ -0,0 +1,6 @@ +export * from './ArrayValueNode'; +export * from './BooleanValueNode'; +export * from './NumberValueNode'; +export * from './PublicKeyValueNode'; +export * from './StringValueNode'; +export * from './ValueNode'; From b00aa303aac1cf73c9ee626232cf515a149f6ad6 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 20:22:43 +0000 Subject: [PATCH 02/12] Fix typos --- src/nodes/valueNodes/BooleanValueNode.ts | 10 +++++----- src/nodes/valueNodes/ValueNode.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nodes/valueNodes/BooleanValueNode.ts b/src/nodes/valueNodes/BooleanValueNode.ts index c6d6e2c68..965c5e381 100644 --- a/src/nodes/valueNodes/BooleanValueNode.ts +++ b/src/nodes/valueNodes/BooleanValueNode.ts @@ -1,24 +1,24 @@ import { Node } from '../Node'; export type BooleanValueNode = { - readonly kind: 'booleanTypeNode'; + readonly kind: 'booleanValueNode'; readonly boolean: boolean; }; -export function booleanTypeNode(boolean: boolean): BooleanValueNode { - return { kind: 'booleanTypeNode', boolean }; +export function booleanValueNode(boolean: boolean): BooleanValueNode { + return { kind: 'booleanValueNode', boolean }; } export function isBooleanValueNode( node: Node | null ): node is BooleanValueNode { - return !!node && node.kind === 'booleanTypeNode'; + return !!node && node.kind === 'booleanValueNode'; } export function assertBooleanValueNode( node: Node | null ): asserts node is BooleanValueNode { if (!isBooleanValueNode(node)) { - throw new Error(`Expected booleanTypeNode, got ${node?.kind ?? 'null'}.`); + throw new Error(`Expected booleanValueNode, got ${node?.kind ?? 'null'}.`); } } diff --git a/src/nodes/valueNodes/ValueNode.ts b/src/nodes/valueNodes/ValueNode.ts index 9906c7f25..477088c97 100644 --- a/src/nodes/valueNodes/ValueNode.ts +++ b/src/nodes/valueNodes/ValueNode.ts @@ -1,5 +1,5 @@ import { Node } from '../Node'; -import type { PublicKeyValueNode } from '../ValueNode'; +import type { PublicKeyValueNode } from './PublicKeyValueNode'; import type { ArrayValueNode } from './ArrayValueNode'; import type { BooleanValueNode } from './BooleanValueNode'; import type { NumberValueNode } from './NumberValueNode'; From a4a5339dc674430dea29912c77c01b48f19c6439 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 20:38:55 +0000 Subject: [PATCH 03/12] Add other value nodes --- src/nodes/valueNodes/EnumValueNode.ts | 39 +++++++++++++++++++++++++ src/nodes/valueNodes/MapValueNode.ts | 23 +++++++++++++++ src/nodes/valueNodes/NoneValueNode.ts | 21 +++++++++++++ src/nodes/valueNodes/SetValueNode.ts | 23 +++++++++++++++ src/nodes/valueNodes/SomeValueNode.ts | 23 +++++++++++++++ src/nodes/valueNodes/StructValueNode.ts | 31 ++++++++++++++++++++ src/nodes/valueNodes/TupleValueNode.ts | 23 +++++++++++++++ src/nodes/valueNodes/ValueNode.ts | 14 +++++++++ src/nodes/valueNodes/index.ts | 6 ++++ 9 files changed, 203 insertions(+) create mode 100644 src/nodes/valueNodes/EnumValueNode.ts create mode 100644 src/nodes/valueNodes/MapValueNode.ts create mode 100644 src/nodes/valueNodes/NoneValueNode.ts create mode 100644 src/nodes/valueNodes/SetValueNode.ts create mode 100644 src/nodes/valueNodes/SomeValueNode.ts create mode 100644 src/nodes/valueNodes/StructValueNode.ts create mode 100644 src/nodes/valueNodes/TupleValueNode.ts diff --git a/src/nodes/valueNodes/EnumValueNode.ts b/src/nodes/valueNodes/EnumValueNode.ts new file mode 100644 index 000000000..3ac5fae6b --- /dev/null +++ b/src/nodes/valueNodes/EnumValueNode.ts @@ -0,0 +1,39 @@ +import { ImportFrom, MainCaseString, mainCase } from '../../shared'; +import { Node } from '../Node'; +import { StructValueNode } from './StructValueNode'; +import { TupleValueNode } from './TupleValueNode'; + +export type EnumValueNode = { + readonly kind: 'enumValueNode'; + readonly enumType: MainCaseString; + readonly variant: MainCaseString; + readonly value: StructValueNode | TupleValueNode | 'empty' | 'scalar'; + readonly importFrom: ImportFrom | null; +}; + +export function enumValueNode( + enumType: string, + variant: string, + value?: StructValueNode | TupleValueNode | 'empty' | 'scalar', + importFrom?: ImportFrom | null +): EnumValueNode { + return { + kind: 'enumValueNode', + enumType: mainCase(enumType), + variant: mainCase(variant), + value: value ?? 'scalar', + importFrom: importFrom ?? null, + }; +} + +export function isEnumValueNode(node: Node | null): node is EnumValueNode { + return !!node && node.kind === 'enumValueNode'; +} + +export function assertEnumValueNode( + node: Node | null +): asserts node is EnumValueNode { + if (!isEnumValueNode(node)) { + throw new Error(`Expected enumValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/MapValueNode.ts b/src/nodes/valueNodes/MapValueNode.ts new file mode 100644 index 000000000..8dada7de9 --- /dev/null +++ b/src/nodes/valueNodes/MapValueNode.ts @@ -0,0 +1,23 @@ +import { Node } from '../Node'; +import { ValueNode } from './ValueNode'; + +export type MapValueNode = { + readonly kind: 'mapValueNode'; + readonly map: [ValueNode, ValueNode][]; +}; + +export function mapValueNode(map: [ValueNode, ValueNode][]): MapValueNode { + return { kind: 'mapValueNode', map }; +} + +export function isMapValueNode(node: Node | null): node is MapValueNode { + return !!node && node.kind === 'mapValueNode'; +} + +export function assertMapValueNode( + node: Node | null +): asserts node is MapValueNode { + if (!isMapValueNode(node)) { + throw new Error(`Expected mapValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/NoneValueNode.ts b/src/nodes/valueNodes/NoneValueNode.ts new file mode 100644 index 000000000..86e36efa0 --- /dev/null +++ b/src/nodes/valueNodes/NoneValueNode.ts @@ -0,0 +1,21 @@ +import { Node } from '../Node'; + +export type NoneValueNode = { + readonly kind: 'noneValueNode'; +}; + +export function noneValueNode(): NoneValueNode { + return { kind: 'noneValueNode' }; +} + +export function isNoneValueNode(node: Node | null): node is NoneValueNode { + return !!node && node.kind === 'noneValueNode'; +} + +export function assertNoneValueNode( + node: Node | null +): asserts node is NoneValueNode { + if (!isNoneValueNode(node)) { + throw new Error(`Expected noneValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/SetValueNode.ts b/src/nodes/valueNodes/SetValueNode.ts new file mode 100644 index 000000000..326fc3547 --- /dev/null +++ b/src/nodes/valueNodes/SetValueNode.ts @@ -0,0 +1,23 @@ +import { Node } from '../Node'; +import { ValueNode } from './ValueNode'; + +export type SetValueNode = { + readonly kind: 'setValueNode'; + readonly set: ValueNode[]; +}; + +export function setValueNode(set: ValueNode[]): SetValueNode { + return { kind: 'setValueNode', set }; +} + +export function isSetValueNode(node: Node | null): node is SetValueNode { + return !!node && node.kind === 'setValueNode'; +} + +export function assertSetValueNode( + node: Node | null +): asserts node is SetValueNode { + if (!isSetValueNode(node)) { + throw new Error(`Expected setValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/SomeValueNode.ts b/src/nodes/valueNodes/SomeValueNode.ts new file mode 100644 index 000000000..36453daba --- /dev/null +++ b/src/nodes/valueNodes/SomeValueNode.ts @@ -0,0 +1,23 @@ +import { Node } from '../Node'; +import { ValueNode } from './ValueNode'; + +export type SomeValueNode = { + readonly kind: 'someValueNode'; + readonly value: ValueNode; +}; + +export function someValueNode(value: ValueNode): SomeValueNode { + return { kind: 'someValueNode', value }; +} + +export function isSomeValueNode(node: Node | null): node is SomeValueNode { + return !!node && node.kind === 'someValueNode'; +} + +export function assertSomeValueNode( + node: Node | null +): asserts node is SomeValueNode { + if (!isSomeValueNode(node)) { + throw new Error(`Expected someValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/StructValueNode.ts b/src/nodes/valueNodes/StructValueNode.ts new file mode 100644 index 000000000..9545e154f --- /dev/null +++ b/src/nodes/valueNodes/StructValueNode.ts @@ -0,0 +1,31 @@ +import { MainCaseString, mainCase } from '../../shared'; +import { Node } from '../Node'; +import { ValueNode } from './ValueNode'; + +export type StructValueNode = { + readonly kind: 'structValueNode'; + readonly fields: Record; +}; + +export function structValueNode( + fields: Record +): StructValueNode { + return { + kind: 'structValueNode', + fields: Object.fromEntries( + Object.entries(fields).map(([key, value]) => [mainCase(key), value]) + ), + }; +} + +export function isStructValueNode(node: Node | null): node is StructValueNode { + return !!node && node.kind === 'structValueNode'; +} + +export function assertStructValueNode( + node: Node | null +): asserts node is StructValueNode { + if (!isStructValueNode(node)) { + throw new Error(`Expected structValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/TupleValueNode.ts b/src/nodes/valueNodes/TupleValueNode.ts new file mode 100644 index 000000000..6cf01b642 --- /dev/null +++ b/src/nodes/valueNodes/TupleValueNode.ts @@ -0,0 +1,23 @@ +import { Node } from '../Node'; +import { ValueNode } from './ValueNode'; + +export type TupleValueNode = { + readonly kind: 'tupleValueNode'; + readonly items: ValueNode[]; +}; + +export function tupleValueNode(items: ValueNode[]): TupleValueNode { + return { kind: 'tupleValueNode', items }; +} + +export function isTupleValueNode(node: Node | null): node is TupleValueNode { + return !!node && node.kind === 'tupleValueNode'; +} + +export function assertTupleValueNode( + node: Node | null +): asserts node is TupleValueNode { + if (!isTupleValueNode(node)) { + throw new Error(`Expected tupleValueNode, got ${node?.kind ?? 'null'}.`); + } +} diff --git a/src/nodes/valueNodes/ValueNode.ts b/src/nodes/valueNodes/ValueNode.ts index 477088c97..656410ccd 100644 --- a/src/nodes/valueNodes/ValueNode.ts +++ b/src/nodes/valueNodes/ValueNode.ts @@ -4,11 +4,25 @@ import type { ArrayValueNode } from './ArrayValueNode'; import type { BooleanValueNode } from './BooleanValueNode'; import type { NumberValueNode } from './NumberValueNode'; import type { StringValueNode } from './StringValueNode'; +import type { SomeValueNode } from './SomeValueNode'; +import type { NoneValueNode } from './NoneValueNode'; +import type { EnumValueNode } from './EnumValueNode'; +import type { MapValueNode } from './MapValueNode'; +import type { SetValueNode } from './SetValueNode'; +import type { StructValueNode } from './StructValueNode'; +import type { TupleValueNode } from './TupleValueNode'; export const REGISTERED_VALUE_NODES = { arrayValueNode: {} as ArrayValueNode, booleanValueNode: {} as BooleanValueNode, + enumValueNode: {} as EnumValueNode, + mapValueNode: {} as MapValueNode, + noneValueNode: {} as NoneValueNode, numberValueNode: {} as NumberValueNode, + setValueNode: {} as SetValueNode, + someValueNode: {} as SomeValueNode, + structValueNode: {} as StructValueNode, + tupleValueNode: {} as TupleValueNode, publicKeyValueNode: {} as PublicKeyValueNode, stringValueNode: {} as StringValueNode, }; diff --git a/src/nodes/valueNodes/index.ts b/src/nodes/valueNodes/index.ts index 185247fab..201527561 100644 --- a/src/nodes/valueNodes/index.ts +++ b/src/nodes/valueNodes/index.ts @@ -1,6 +1,12 @@ export * from './ArrayValueNode'; export * from './BooleanValueNode'; +export * from './EnumValueNode'; +export * from './MapValueNode'; export * from './NumberValueNode'; export * from './PublicKeyValueNode'; +export * from './SetValueNode'; +export * from './SomeValueNode'; export * from './StringValueNode'; +export * from './StructValueNode'; +export * from './TupleValueNode'; export * from './ValueNode'; From 808a61689f2ac42fc99e6fdfd25088ab301544b0 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 20:55:57 +0000 Subject: [PATCH 04/12] Add value nodes to mergeVisitor --- src/nodes/valueNodes/ArrayValueNode.ts | 2 +- src/nodes/valueNodes/MapValueNode.ts | 6 ++-- src/nodes/valueNodes/SetValueNode.ts | 6 ++-- src/visitors/mergeVisitor.ts | 47 ++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/nodes/valueNodes/ArrayValueNode.ts b/src/nodes/valueNodes/ArrayValueNode.ts index 21c8c166d..2ad83e136 100644 --- a/src/nodes/valueNodes/ArrayValueNode.ts +++ b/src/nodes/valueNodes/ArrayValueNode.ts @@ -1,5 +1,5 @@ import { Node } from '../Node'; -import { ValueNode } from '../ValueNode'; +import { ValueNode } from './ValueNode'; export type ArrayValueNode = { readonly kind: 'arrayValueNode'; diff --git a/src/nodes/valueNodes/MapValueNode.ts b/src/nodes/valueNodes/MapValueNode.ts index 8dada7de9..1627ba638 100644 --- a/src/nodes/valueNodes/MapValueNode.ts +++ b/src/nodes/valueNodes/MapValueNode.ts @@ -3,11 +3,11 @@ import { ValueNode } from './ValueNode'; export type MapValueNode = { readonly kind: 'mapValueNode'; - readonly map: [ValueNode, ValueNode][]; + readonly entries: [ValueNode, ValueNode][]; }; -export function mapValueNode(map: [ValueNode, ValueNode][]): MapValueNode { - return { kind: 'mapValueNode', map }; +export function mapValueNode(entries: [ValueNode, ValueNode][]): MapValueNode { + return { kind: 'mapValueNode', entries }; } export function isMapValueNode(node: Node | null): node is MapValueNode { diff --git a/src/nodes/valueNodes/SetValueNode.ts b/src/nodes/valueNodes/SetValueNode.ts index 326fc3547..4a7294032 100644 --- a/src/nodes/valueNodes/SetValueNode.ts +++ b/src/nodes/valueNodes/SetValueNode.ts @@ -3,11 +3,11 @@ import { ValueNode } from './ValueNode'; export type SetValueNode = { readonly kind: 'setValueNode'; - readonly set: ValueNode[]; + readonly items: ValueNode[]; }; -export function setValueNode(set: ValueNode[]): SetValueNode { - return { kind: 'setValueNode', set }; +export function setValueNode(items: ValueNode[]): SetValueNode { + return { kind: 'setValueNode', items }; } export function isSetValueNode(node: Node | null): node is SetValueNode { diff --git a/src/visitors/mergeVisitor.ts b/src/visitors/mergeVisitor.ts index 9e0eeb60c..9df91c262 100644 --- a/src/visitors/mergeVisitor.ts +++ b/src/visitors/mergeVisitor.ts @@ -214,5 +214,52 @@ export function mergeVisitor< }; } + if (castedNodeKeys.includes('arrayValueNode')) { + visitor.visitArrayValue = function visitArrayValue(node) { + return merge(node, node.items.flatMap(visit(this))); + }; + } + + if (castedNodeKeys.includes('enumValueNode')) { + visitor.visitEnumValue = function visitEnumValue(node) { + return typeof node.value === 'string' + ? leafValue(node) + : merge(node, visit(this)(node.value)); + }; + } + + if (castedNodeKeys.includes('mapValueNode')) { + visitor.visitMapValue = function visitMapValue(node) { + return merge( + node, + node.entries.flatMap(([k, v]) => [...visit(this)(k), ...visit(this)(v)]) + ); + }; + } + + if (castedNodeKeys.includes('setValueNode')) { + visitor.visitSetValue = function visitSetValue(node) { + return merge(node, node.items.flatMap(visit(this))); + }; + } + + if (castedNodeKeys.includes('someValueNode')) { + visitor.visitSomeValue = function visitSomeValue(node) { + return merge(node, visit(this)(node.value)); + }; + } + + if (castedNodeKeys.includes('structValueNode')) { + visitor.visitStructValue = function visitStructValue(node) { + return merge(node, Object.values(node.fields).flatMap(visit(this))); + }; + } + + if (castedNodeKeys.includes('tupleValueNode')) { + visitor.visitTupleValue = function visitTupleValue(node) { + return merge(node, node.items.flatMap(visit(this))); + }; + } + return visitor as Visitor; } From 45b3a0ad513db7b438d185c0ed081cb6d8c4bf98 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:11:40 +0000 Subject: [PATCH 05/12] Add value nodes to identityVisitor --- src/visitors/identityVisitor.ts | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/visitors/identityVisitor.ts b/src/visitors/identityVisitor.ts index 953258c13..f523648e3 100644 --- a/src/visitors/identityVisitor.ts +++ b/src/visitors/identityVisitor.ts @@ -6,6 +6,7 @@ import { accountNode, amountTypeNode, arrayTypeNode, + arrayValueNode, assertAccountDataNode, assertAccountNode, assertDefinedTypeNode, @@ -23,6 +24,7 @@ import { assertStructTypeNode, assertTupleTypeNode, assertTypeNode, + assertValueNode, boolTypeNode, bytesTypeNode, dateTimeTypeNode, @@ -30,21 +32,29 @@ import { enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, + enumValueNode, instructionDataArgsNode, instructionExtraArgsNode, instructionNode, + isStructValueNode, + isTupleValueNode, mapTypeNode, + mapValueNode, optionTypeNode, prefixedSizeNode, programNode, removeNullAndAssertNodeFilter, rootNode, setTypeNode, + setValueNode, solAmountTypeNode, + someValueNode, stringTypeNode, structFieldTypeNode, structTypeNode, + structValueNode, tupleTypeNode, + tupleValueNode, } from '../nodes'; import { AccountSeed } from '../shared'; import { staticVisitor } from './staticVisitor'; @@ -353,5 +363,89 @@ export function identityVisitor< }; } + if (castedNodeKeys.includes('arrayValueNode')) { + visitor.visitArrayValue = function visitArrayValue(node) { + return arrayValueNode( + node.items + .map(visit(this)) + .filter(removeNullAndAssertNodeFilter(assertValueNode)) + ); + }; + } + + if (castedNodeKeys.includes('enumValueNode')) { + visitor.visitEnumValue = function visitEnumValue(node) { + if (typeof node.value === 'string') return { ...node }; + const value = visit(this)(node.value); + if (value === null) return null; + if (!isStructValueNode(value) && !isTupleValueNode(value)) { + throw new Error( + `Expected structValueNode | tupleValueNode, got ${value.kind}.` + ); + } + return enumValueNode(node.enumType, node.variant, value, node.importFrom); + }; + } + + if (castedNodeKeys.includes('mapValueNode')) { + visitor.visitMapValue = function visitMapValue(node) { + return mapValueNode( + node.entries.flatMap(([k, v]) => { + const key = visit(this)(k); + if (key === null) return []; + assertValueNode(key); + const value = visit(this)(v); + if (value === null) return []; + assertValueNode(value); + return [[key, value]]; + }) + ); + }; + } + + if (castedNodeKeys.includes('setValueNode')) { + visitor.visitSetValue = function visitSetValue(node) { + return setValueNode( + node.items + .map(visit(this)) + .filter(removeNullAndAssertNodeFilter(assertValueNode)) + ); + }; + } + + if (castedNodeKeys.includes('someValueNode')) { + visitor.visitSomeValue = function visitSomeValue(node) { + const value = visit(this)(node.value); + if (value === null) return null; + assertValueNode(value); + return someValueNode(value); + }; + } + + if (castedNodeKeys.includes('structValueNode')) { + visitor.visitStructValue = function visitStructValue(node) { + return structValueNode( + Object.fromEntries( + Object.entries(node.fields).flatMap(([k, v]) => { + const value = visit(this)(v); + if (value === null) return []; + assertValueNode(value); + return [[k, value]]; + }) + ) + ); + }; + } + + if (castedNodeKeys.includes('tupleValueNode')) { + visitor.visitTupleValue = function visitTupleValue(node) { + return tupleValueNode( + node.items + .map(visit(this)) + .filter(removeNullAndAssertNodeFilter(assertValueNode)) + ); + }; + } + return visitor as Visitor; } From 8456f313c62ea2aed31d85d558d100d19339c06a Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:18:19 +0000 Subject: [PATCH 06/12] Update node usages --- src/idl/IdlType.ts | 1 - src/nodes/AccountNode.ts | 16 +++- src/nodes/InstructionNode.ts | 4 +- src/nodes/ValueNode.ts | 94 ------------------- src/nodes/index.ts | 2 +- src/nodes/typeNodes/StructFieldTypeNode.ts | 7 +- src/shared/AccountSeed.ts | 7 +- src/shared/AnchorDiscriminator.ts | 8 +- ...reateSubInstructionsFromEnumArgsVisitor.ts | 4 +- 9 files changed, 28 insertions(+), 115 deletions(-) delete mode 100644 src/nodes/ValueNode.ts diff --git a/src/idl/IdlType.ts b/src/idl/IdlType.ts index eac388895..f1d819933 100644 --- a/src/idl/IdlType.ts +++ b/src/idl/IdlType.ts @@ -47,7 +47,6 @@ export type IdlTypeStructField = { name: string; type: IdlType; docs?: string[]; - defaultsValue?: any; }; // Enums. diff --git a/src/nodes/AccountNode.ts b/src/nodes/AccountNode.ts index ba33a7c82..1d58de4f3 100644 --- a/src/nodes/AccountNode.ts +++ b/src/nodes/AccountNode.ts @@ -8,13 +8,17 @@ import { mainCase, } from '../shared'; import { AccountDataNode, accountDataNode } from './AccountDataNode'; -import { bytesTypeNode } from './typeNodes/BytesTypeNode'; import type { Node } from './Node'; +import { remainderSizeNode } from './sizeNodes'; +import { bytesTypeNode } from './typeNodes/BytesTypeNode'; import { stringTypeNode } from './typeNodes/StringTypeNode'; import { assertStructTypeNode } from './typeNodes/StructTypeNode'; import { TypeNode, createTypeNodeFromIdl } from './typeNodes/TypeNode'; -import { vScalar } from './ValueNode'; -import { remainderSizeNode } from './sizeNodes'; +import { + booleanValueNode, + numberValueNode, + stringValueNode, +} from './valueNodes'; export type AccountNode = { readonly kind: 'accountNode'; @@ -60,7 +64,11 @@ export function accountNodeFromIdl(idl: Partial): AccountNode { assertStructTypeNode(struct); const seeds = (idl.seeds ?? []).map((seed): AccountSeed => { if (seed.kind === 'constant') { - const value = vScalar(seed.value); + const value = (() => { + if (typeof seed.value === 'string') return stringValueNode(seed.value); + if (typeof seed.value === 'number') return numberValueNode(seed.value); + return booleanValueNode(seed.value); + })(); let type: TypeNode; if (seed.type === 'string') { type = stringTypeNode({ size: remainderSizeNode() }); diff --git a/src/nodes/InstructionNode.ts b/src/nodes/InstructionNode.ts index db34e65cd..7f1d0de43 100644 --- a/src/nodes/InstructionNode.ts +++ b/src/nodes/InstructionNode.ts @@ -29,7 +29,7 @@ import { structTypeNodeFromIdl, } from './typeNodes/StructTypeNode'; import { createTypeNodeFromIdl } from './typeNodes/TypeNode'; -import { vScalar } from './ValueNode'; +import { numberValueNode } from './valueNodes'; export type InstructionNode = { readonly kind: 'instructionNode'; @@ -102,7 +102,7 @@ export function instructionNodeFromIdl( child: createTypeNodeFromIdl(idl.discriminant.type), defaultsTo: { strategy: 'omitted', - value: vScalar(idl.discriminant.value), + value: numberValueNode(idl.discriminant.value), }, }); dataArgs = structTypeNode([discriminatorField, ...dataArgs.fields]); diff --git a/src/nodes/ValueNode.ts b/src/nodes/ValueNode.ts deleted file mode 100644 index e7d4d9dbc..000000000 --- a/src/nodes/ValueNode.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { ImportFrom, MainCaseString, mainCase } from '../shared'; - -export type ValueNode = - | ScalarValueNode - | PublicKeyValueNode - | ListValueNode - | TupleValueNode - | SetValueNode - | MapValueNode - | OptionValueNode - | StructValueNode - | EnumValueNode; - -export type ScalarValueNode = - | { kind: 'number'; value: number } - | { kind: 'boolean'; value: boolean } - | { kind: 'string'; value: string }; -export const vScalar = (scalar: number | boolean | string): ScalarValueNode => { - if (typeof scalar === 'number') return { kind: 'number', value: scalar }; - if (typeof scalar === 'boolean') return { kind: 'boolean', value: scalar }; - return { kind: 'string', value: scalar }; -}; - -export type PublicKeyValueNode = { kind: 'publicKey'; value: string }; -export const vPublicKey = (value: string): PublicKeyValueNode => ({ - kind: 'publicKey', - value, -}); - -export type ListValueNode = { kind: 'list'; values: ValueNode[] }; -export const vList = (values: ValueNode[]): ListValueNode => ({ - kind: 'list', - values, -}); - -export type TupleValueNode = { kind: 'tuple'; values: ValueNode[] }; -export const vTuple = (values: ValueNode[]): TupleValueNode => ({ - kind: 'tuple', - values, -}); - -export type SetValueNode = { kind: 'set'; values: ValueNode[] }; -export const vSet = (values: ValueNode[]): SetValueNode => ({ - kind: 'set', - values, -}); - -export type MapValueNode = { kind: 'map'; values: [ValueNode, ValueNode][] }; -export const vMap = (values: [ValueNode, ValueNode][]): MapValueNode => ({ - kind: 'map', - values, -}); - -export type OptionValueNode = - | { kind: 'optionNone' } - | { kind: 'optionSome'; value: ValueNode }; -export const vNone = (): OptionValueNode => ({ kind: 'optionNone' }); -export const vSome = (value: ValueNode): OptionValueNode => ({ - kind: 'optionSome', - value, -}); - -export type StructValueNode = { - kind: 'struct'; - values: Record; -}; -export const vStruct = ( - values: Record -): StructValueNode => ({ - kind: 'struct', - values: Object.fromEntries( - Object.entries(values).map(([key, value]) => [mainCase(key), value]) - ), -}); - -export type EnumValueNode = { - kind: 'enum'; - enumType: MainCaseString; - variant: MainCaseString; - value: StructValueNode | TupleValueNode | 'empty' | 'scalar'; - importFrom: ImportFrom | null; -}; -export const vEnum = ( - enumType: string, - variant: string, - value?: StructValueNode | TupleValueNode | 'empty' | 'scalar', - importFrom?: ImportFrom | null -): EnumValueNode => ({ - kind: 'enum', - enumType: mainCase(enumType), - variant: mainCase(variant), - value: value ?? 'scalar', - importFrom: importFrom ?? null, -}); diff --git a/src/nodes/index.ts b/src/nodes/index.ts index c205c899d..51dd31d8e 100644 --- a/src/nodes/index.ts +++ b/src/nodes/index.ts @@ -9,7 +9,7 @@ export * from './InstructionNode'; export * from './Node'; export * from './ProgramNode'; export * from './RootNode'; -export * from './ValueNode'; export * from './sizeNodes'; export * from './typeNodes'; +export * from './valueNodes'; diff --git a/src/nodes/typeNodes/StructFieldTypeNode.ts b/src/nodes/typeNodes/StructFieldTypeNode.ts index 5a5744483..b1724c632 100644 --- a/src/nodes/typeNodes/StructFieldTypeNode.ts +++ b/src/nodes/typeNodes/StructFieldTypeNode.ts @@ -1,8 +1,8 @@ import type { IdlTypeStructField } from '../../idl'; import { InvalidKinobiTreeError, MainCaseString, mainCase } from '../../shared'; import type { Node } from '../Node'; +import { ValueNode } from '../valueNodes'; import { TypeNode, createTypeNodeFromIdl } from './TypeNode'; -import { ValueNode, vScalar } from '../ValueNode'; export type StructFieldTypeNode = { readonly kind: 'structFieldTypeNode'; @@ -44,10 +44,7 @@ export function structFieldTypeNodeFromIdl( name: idl.name ?? '', child: createTypeNodeFromIdl(idl.type), docs: idl.docs ?? [], - defaultsTo: - idl.defaultsValue !== undefined - ? { strategy: 'optional', value: vScalar(idl.defaultsValue) } - : null, + defaultsTo: null, }); } diff --git a/src/shared/AccountSeed.ts b/src/shared/AccountSeed.ts index 1f95aee45..906622bed 100644 --- a/src/shared/AccountSeed.ts +++ b/src/shared/AccountSeed.ts @@ -4,7 +4,7 @@ import { publicKeyTypeNode, remainderSizeNode, stringTypeNode, - vScalar, + stringValueNode, } from '../nodes'; import { MainCaseString, mainCase } from './utils'; @@ -21,7 +21,10 @@ export const constantSeed = ( ): AccountSeed => ({ kind: 'constant', type, value }); export const stringConstantSeed = (value: string): AccountSeed => - constantSeed(stringTypeNode({ size: remainderSizeNode() }), vScalar(value)); + constantSeed( + stringTypeNode({ size: remainderSizeNode() }), + stringValueNode(value) + ); export const variableSeed = ( name: string, diff --git a/src/shared/AnchorDiscriminator.ts b/src/shared/AnchorDiscriminator.ts index 736e33902..8023a9b32 100644 --- a/src/shared/AnchorDiscriminator.ts +++ b/src/shared/AnchorDiscriminator.ts @@ -1,19 +1,19 @@ import { sha256 } from '@noble/hashes/sha256'; -import { ListValueNode, vList, vScalar } from '../nodes/ValueNode'; import { pascalCase, snakeCase } from './utils'; +import { ArrayValueNode, arrayValueNode, numberValueNode } from '../nodes'; -export type AnchorDiscriminator = ListValueNode; +export type AnchorDiscriminator = ArrayValueNode; export const getAnchorInstructionDiscriminator = ( idlName: string ): AnchorDiscriminator => { const hash = sha256(`global:${snakeCase(idlName)}`).slice(0, 8); - return vList([...hash].map((byte) => vScalar(byte))); + return arrayValueNode([...hash].map((byte) => numberValueNode(byte))); }; export const getAnchorAccountDiscriminator = ( idlName: string ): AnchorDiscriminator => { const hash = sha256(`account:${pascalCase(idlName)}`).slice(0, 8); - return vList([...hash].map((byte) => vScalar(byte))); + return arrayValueNode([...hash].map((byte) => numberValueNode(byte))); }; diff --git a/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts b/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts index 72d486b10..ce83090e9 100644 --- a/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts +++ b/src/visitors/createSubInstructionsFromEnumArgsVisitor.ts @@ -12,9 +12,9 @@ import { isEnumTypeNode, isLinkTypeNode, numberTypeNode, + numberValueNode, structFieldTypeNode, structTypeNode, - vScalar, } from '../nodes'; import { logWarn, mainCase } from '../shared'; import { @@ -80,7 +80,7 @@ export function createSubInstructionsFromEnumArgsVisitor( child: numberTypeNode('u8'), defaultsTo: { strategy: 'omitted', - value: vScalar(index), + value: numberValueNode(index), }, }) ); From 2583e8cb4c992506229cbc4611188401589cdc1e Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:35:11 +0000 Subject: [PATCH 07/12] Create renderValueNodeVisitor for js renderer --- src/renderers/js/getRenderMapVisitor.ts | 7 +- src/renderers/js/getTypeManifestVisitor.ts | 8 +- src/renderers/js/renderInstructionDefaults.ts | 11 +- src/renderers/js/renderValueNode.ts | 102 ------------- src/renderers/js/renderValueNodeVisitor.ts | 141 ++++++++++++++++++ 5 files changed, 156 insertions(+), 113 deletions(-) delete mode 100644 src/renderers/js/renderValueNode.ts create mode 100644 src/renderers/js/renderValueNodeVisitor.ts diff --git a/src/renderers/js/getRenderMapVisitor.ts b/src/renderers/js/getRenderMapVisitor.ts index 3f22d76de..bc5dea250 100644 --- a/src/renderers/js/getRenderMapVisitor.ts +++ b/src/renderers/js/getRenderMapVisitor.ts @@ -37,7 +37,7 @@ import { import { JavaScriptContextMap } from './JavaScriptContextMap'; import { JavaScriptImportMap } from './JavaScriptImportMap'; import { renderInstructionDefaults } from './renderInstructionDefaults'; -import { renderValueNode } from './renderValueNode'; +import { renderValueNodeVisitor } from './renderValueNodeVisitor'; const DEFAULT_PRETTIER_OPTIONS: PrettierOptions = { semi: true, @@ -68,6 +68,7 @@ export function getRenderMapVisitor( let byteSizeVisitor = getByteSizeVisitor([]); let program: ProgramNode | null = null; + const valueNodeVisitor = renderValueNodeVisitor(); const typeManifestVisitor = options.typeManifestVisitor ?? getTypeManifestVisitor(); const resolvedInstructionInputVisitor = @@ -281,7 +282,7 @@ export function getRenderMapVisitor( (f) => f.name === discriminator.name ); const discriminatorValue = discriminatorField?.defaultsTo?.value - ? renderValueNode(discriminatorField.defaultsTo.value) + ? visit(discriminatorField.defaultsTo.value, valueNodeVisitor) : undefined; if (discriminatorValue) { imports.mergeWith(discriminatorValue.imports); @@ -331,7 +332,7 @@ export function getRenderMapVisitor( const seedManifest = visit(seed.type, typeManifestVisitor); imports.mergeWith(seedManifest.serializerImports); const seedValue = seed.value; - const valueManifest = renderValueNode(seedValue); + const valueManifest = visit(seedValue, valueNodeVisitor); (seedValue as any).render = valueManifest.render; imports.mergeWith(valueManifest.imports); return { ...seed, typeManifest: seedManifest }; diff --git a/src/renderers/js/getTypeManifestVisitor.ts b/src/renderers/js/getTypeManifestVisitor.ts index 0020a06ed..8ded8de6a 100644 --- a/src/renderers/js/getTypeManifestVisitor.ts +++ b/src/renderers/js/getTypeManifestVisitor.ts @@ -13,7 +13,7 @@ import { import { camelCase, pascalCase, pipe } from '../../shared'; import { Visitor, extendVisitor, staticVisitor, visit } from '../../visitors'; import { JavaScriptImportMap } from './JavaScriptImportMap'; -import { renderValueNode } from './renderValueNode'; +import { renderValueNodeVisitor } from './renderValueNodeVisitor'; export type JavaScriptTypeManifest = { isEnum: boolean; @@ -27,6 +27,7 @@ export type JavaScriptTypeManifest = { export function getTypeManifestVisitor() { let parentName: { strict: string; loose: string } | null = null; + const valueNodeVisitor = renderValueNodeVisitor(); return pipe( staticVisitor( @@ -399,8 +400,9 @@ export function getTypeManifestVisitor() { const defaultsTo = f.defaultsTo as NonNullable< typeof f.defaultsTo >; - const { render: renderedValue, imports } = renderValueNode( - defaultsTo.value + const { render: renderedValue, imports } = visit( + defaultsTo.value, + valueNodeVisitor ); baseManifest.serializerImports.mergeWith(imports); if (defaultsTo.strategy === 'omitted') { diff --git a/src/renderers/js/renderInstructionDefaults.ts b/src/renderers/js/renderInstructionDefaults.ts index f4f67f3f4..49c5562d2 100644 --- a/src/renderers/js/renderInstructionDefaults.ts +++ b/src/renderers/js/renderInstructionDefaults.ts @@ -6,10 +6,10 @@ import { camelCase, pascalCase, } from '../../shared'; -import { ResolvedInstructionInput } from '../../visitors'; +import { ResolvedInstructionInput, visit } from '../../visitors'; import { JavaScriptContextMap } from './JavaScriptContextMap'; import { JavaScriptImportMap } from './JavaScriptImportMap'; -import { renderValueNode } from './renderValueNode'; +import { renderValueNodeVisitor } from './renderValueNodeVisitor'; export function renderInstructionDefaults( input: ResolvedInstructionInput, @@ -20,6 +20,7 @@ export function renderInstructionDefaults( interfaces: JavaScriptContextMap; render: string; } { + const valueNodeVisitor = renderValueNodeVisitor(); const imports = new JavaScriptImportMap(); const interfaces = new JavaScriptContextMap(); @@ -105,7 +106,7 @@ export function renderInstructionDefaults( seedValue.name )})`; } - const valueManifest = renderValueNode(seedValue.value); + const valueManifest = visit(seedValue.value, valueNodeVisitor); imports.mergeWith(valueManifest.imports); return `${seed}: ${valueManifest.render}`; } @@ -152,7 +153,7 @@ export function renderInstructionDefaults( imports.add('shared', 'expectSome'); return render(`expectSome(${argObject}.${camelCase(defaultsTo.name)})`); case 'value': - const valueManifest = renderValueNode(defaultsTo.value); + const valueManifest = visit(defaultsTo.value, valueNodeVisitor); imports.mergeWith(valueManifest.imports); return render(valueManifest.render); case 'resolver': @@ -198,7 +199,7 @@ export function renderInstructionDefaults( ? `resolvedAccounts.${camelCase(defaultsTo.input.name)}.value` : `${argObject}.${camelCase(defaultsTo.input.name)}`; if (defaultsTo.value) { - const comparedValue = renderValueNode(defaultsTo.value); + const comparedValue = visit(defaultsTo.value, valueNodeVisitor); imports.mergeWith(comparedValue.imports); const operator = negatedCondition ? '!==' : '==='; condition = `${comparedInputName} ${operator} ${comparedValue.render}`; diff --git a/src/renderers/js/renderValueNode.ts b/src/renderers/js/renderValueNode.ts deleted file mode 100644 index 8f0763bce..000000000 --- a/src/renderers/js/renderValueNode.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { ValueNode } from 'src/nodes'; -import { camelCase, pascalCase } from '../../shared'; -import { JavaScriptImportMap } from './JavaScriptImportMap'; - -export function renderValueNode(value: ValueNode): { - imports: JavaScriptImportMap; - render: string; -} { - const imports = new JavaScriptImportMap(); - switch (value.kind) { - case 'list': - case 'tuple': - const list = value.values.map((v) => renderValueNode(v)); - return { - imports: imports.mergeWith(...list.map((c) => c.imports)), - render: `[${list.map((c) => c.render).join(', ')}]`, - }; - case 'set': - const set = value.values.map((v) => renderValueNode(v)); - return { - imports: imports.mergeWith(...set.map((c) => c.imports)), - render: `new Set([${set.map((c) => c.render).join(', ')}])`, - }; - case 'map': - const map = value.values.map(([k, v]) => { - const mapKey = renderValueNode(k); - const mapValue = renderValueNode(v); - return { - imports: mapKey.imports.mergeWith(mapValue.imports), - render: `[${mapKey.render}, ${mapValue.render}]`, - }; - }); - return { - imports: imports.mergeWith(...map.map((c) => c.imports)), - render: `new Map([${map.map((c) => c.render).join(', ')}])`, - }; - case 'struct': - const struct = Object.entries(value.values).map(([k, v]) => { - const structValue = renderValueNode(v); - return { - imports: structValue.imports, - render: `${k}: ${structValue.render}`, - }; - }); - return { - imports: imports.mergeWith(...struct.map((c) => c.imports)), - render: `{ ${struct.map((c) => c.render).join(', ')} }`, - }; - case 'enum': - const enumName = pascalCase(value.enumType); - const variantName = pascalCase(value.variant); - const rawImportFrom = value.importFrom ?? 'generated'; - const importFrom = - rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; - - if (value.value === 'scalar') { - return { - imports: imports.add(importFrom, enumName), - render: `${enumName}.${variantName}`, - }; - } - - const enumFn = camelCase(value.enumType); - imports.add(importFrom, enumFn); - - if (value.value === 'empty') { - return { imports, render: `${enumFn}('${variantName}')` }; - } - - const enumValue = renderValueNode(value.value); - const fields = enumValue.render; - imports.mergeWith(enumValue.imports); - - return { - imports, - render: `${enumFn}('${variantName}', ${fields})`, - }; - case 'optionSome': - const child = renderValueNode(value.value); - return { - imports: child.imports.add('umi', 'some'), - render: `some(${child.render})`, - }; - case 'optionNone': - return { - imports: new JavaScriptImportMap().add('umi', 'none'), - render: 'none()', - }; - case 'publicKey': - return { - imports: new JavaScriptImportMap().add('umi', 'publicKey'), - render: `publicKey("${value.value}")`, - }; - case 'string': - case 'number': - case 'boolean': - return { imports, render: JSON.stringify(value.value) }; - default: - const neverDefault: never = value; - throw new Error(`Unexpected value type ${(neverDefault as any).kind}`); - } -} diff --git a/src/renderers/js/renderValueNodeVisitor.ts b/src/renderers/js/renderValueNodeVisitor.ts new file mode 100644 index 000000000..b8e740f76 --- /dev/null +++ b/src/renderers/js/renderValueNodeVisitor.ts @@ -0,0 +1,141 @@ +import { Visitor, visit } from '../../visitors'; +import { RegisteredValueNodes } from '../../nodes'; +import { camelCase, pascalCase } from '../../shared'; +import { JavaScriptImportMap } from './JavaScriptImportMap'; + +export function renderValueNodeVisitor(): Visitor< + { + imports: JavaScriptImportMap; + render: string; + }, + keyof RegisteredValueNodes +> { + return { + visitArrayValue(node) { + const list = node.items.map((v) => visit(v, this)); + return { + imports: new JavaScriptImportMap().mergeWith( + ...list.map((c) => c.imports) + ), + render: `[${list.map((c) => c.render).join(', ')}]`, + }; + }, + visitBooleanValue(node) { + return { + imports: new JavaScriptImportMap(), + render: JSON.stringify(node.boolean), + }; + }, + visitEnumValue(node) { + const imports = new JavaScriptImportMap(); + const enumName = pascalCase(node.enumType); + const variantName = pascalCase(node.variant); + const rawImportFrom = node.importFrom ?? 'generated'; + const importFrom = + rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; + + if (node.value === 'scalar') { + return { + imports: imports.add(importFrom, enumName), + render: `${enumName}.${variantName}`, + }; + } + + const enumFn = camelCase(node.enumType); + imports.add(importFrom, enumFn); + + if (node.value === 'empty') { + return { imports, render: `${enumFn}('${variantName}')` }; + } + + const enumValue = visit(node.value, this); + const fields = enumValue.render; + imports.mergeWith(enumValue.imports); + + return { + imports, + render: `${enumFn}('${variantName}', ${fields})`, + }; + }, + visitMapValue(node) { + const map = node.entries.map(([k, v]) => { + const mapKey = visit(k, this); + const mapValue = visit(v, this); + return { + imports: mapKey.imports.mergeWith(mapValue.imports), + render: `[${mapKey.render}, ${mapValue.render}]`, + }; + }); + return { + imports: new JavaScriptImportMap().mergeWith( + ...map.map((c) => c.imports) + ), + render: `new Map([${map.map((c) => c.render).join(', ')}])`, + }; + }, + visitNoneValue() { + return { + imports: new JavaScriptImportMap().add('umi', 'none'), + render: 'none()', + }; + }, + visitNumberValue(node) { + return { + imports: new JavaScriptImportMap(), + render: JSON.stringify(node.number), + }; + }, + visitPublicKeyValue(node) { + return { + imports: new JavaScriptImportMap().add('umi', 'publicKey'), + render: `publicKey("${node.publicKey}")`, + }; + }, + visitSetValue(node) { + const set = node.items.map((v) => visit(v, this)); + return { + imports: new JavaScriptImportMap().mergeWith( + ...set.map((c) => c.imports) + ), + render: `new Set([${set.map((c) => c.render).join(', ')}])`, + }; + }, + visitSomeValue(node) { + const child = visit(node.value, this); + return { + imports: child.imports.add('umi', 'some'), + render: `some(${child.render})`, + }; + }, + visitStringValue(node) { + return { + imports: new JavaScriptImportMap(), + render: JSON.stringify(node.string), + }; + }, + visitStructValue(node) { + const struct = Object.entries(node.fields).map(([k, v]) => { + const structValue = visit(v, this); + return { + imports: structValue.imports, + render: `${k}: ${structValue.render}`, + }; + }); + return { + imports: new JavaScriptImportMap().mergeWith( + ...struct.map((c) => c.imports) + ), + render: `{ ${struct.map((c) => c.render).join(', ')} }`, + }; + }, + visitTupleValue(node) { + const list = node.items.map((v) => visit(v, this)); + return { + imports: new JavaScriptImportMap().mergeWith( + ...list.map((c) => c.imports) + ), + render: `[${list.map((c) => c.render).join(', ')}]`, + }; + }, + }; +} From af4fbf151f5de8494617764b1e02dc0620f5edea Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:43:28 +0000 Subject: [PATCH 08/12] Create renderValueNodeVisitor for js-experimental renderer --- .../js-experimental/fragments/valueNode.ts | 81 +------------- .../js-experimental/renderValueNodeVisitor.ts | 100 ++++++++++++++++++ 2 files changed, 104 insertions(+), 77 deletions(-) create mode 100644 src/renderers/js-experimental/renderValueNodeVisitor.ts diff --git a/src/renderers/js-experimental/fragments/valueNode.ts b/src/renderers/js-experimental/fragments/valueNode.ts index 1427421c5..02c22e878 100644 --- a/src/renderers/js-experimental/fragments/valueNode.ts +++ b/src/renderers/js-experimental/fragments/valueNode.ts @@ -1,85 +1,12 @@ import { ValueNode } from '../../../nodes'; -import { pascalCase } from '../../../shared'; +import { visit } from '../../../visitors'; import { NameApi } from '../nameTransformers'; -import { Fragment, fragment, mergeFragments } from './common'; +import { renderValueNodeVisitor } from '../renderValueNodeVisitor'; +import { Fragment } from './common'; export function getValueNodeFragment( value: ValueNode, nameApi: NameApi ): Fragment { - switch (value.kind) { - case 'list': - case 'tuple': - return mergeFragments( - value.values.map((v) => getValueNodeFragment(v, nameApi)), - (renders) => `[${renders.join(', ')}]` - ); - case 'set': - return mergeFragments( - value.values.map((v) => getValueNodeFragment(v, nameApi)), - (renders) => `new Set([${renders.join(', ')}])` - ); - case 'map': - const entryFragments = value.values.map(([k, v]) => - mergeFragments( - [getValueNodeFragment(k, nameApi), getValueNodeFragment(v, nameApi)], - (renders) => `[${renders.join(', ')}]` - ) - ); - return mergeFragments( - entryFragments, - (renders) => `new Map([${renders.join(', ')}])` - ); - case 'struct': - const fieldFragments = Object.entries(value.values).map(([k, v]) => - getValueNodeFragment(v, nameApi).mapRender((r) => `${k}: ${r}`) - ); - return mergeFragments( - fieldFragments, - (renders) => `{ ${renders.join(', ')} }` - ); - case 'enum': - const enumName = nameApi.dataType(value.enumType); - const enumFunction = nameApi.dataEnumFunction(value.enumType); - const variantName = pascalCase(value.variant); - const rawImportFrom = value.importFrom ?? 'generated'; - const importFrom = - rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; - - if (value.value === 'scalar') { - return fragment(`${enumName}.${variantName}`).addImports( - importFrom, - enumName - ); - } - - if (value.value === 'empty') { - return fragment(`${enumFunction}('${variantName}')`).addImports( - importFrom, - enumFunction - ); - } - - return getValueNodeFragment(value.value, nameApi) - .mapRender((r) => `${enumFunction}('${variantName}', ${r})`) - .addImports(importFrom, enumFunction); - case 'optionSome': - return getValueNodeFragment(value.value, nameApi) - .mapRender((r) => `some(${r})`) - .addImports('solanaOptions', 'some'); - case 'optionNone': - return fragment('none()').addImports('solanaOptions', 'none'); - case 'publicKey': - return fragment(`address("${value.value}")`).addImports( - 'solanaAddresses', - 'address' - ); - case 'string': - case 'number': - case 'boolean': - return fragment(JSON.stringify(value.value)); - default: - const neverDefault: never = value; - throw new Error(`Unexpected value type ${(neverDefault as any).kind}`); - } + return visit(value, renderValueNodeVisitor(nameApi)); } diff --git a/src/renderers/js-experimental/renderValueNodeVisitor.ts b/src/renderers/js-experimental/renderValueNodeVisitor.ts new file mode 100644 index 000000000..3ea7330cf --- /dev/null +++ b/src/renderers/js-experimental/renderValueNodeVisitor.ts @@ -0,0 +1,100 @@ +import { RegisteredValueNodes } from '../../nodes'; +import { pascalCase } from '../../shared'; +import { Visitor, visit } from '../../visitors'; +import { Fragment, fragment, mergeFragments } from './fragments'; +import { NameApi } from './nameTransformers'; + +export function renderValueNodeVisitor( + nameApi: NameApi +): Visitor { + return { + visitArrayValue(node) { + return mergeFragments( + node.items.map((v) => visit(v, this)), + (renders) => `[${renders.join(', ')}]` + ); + }, + visitBooleanValue(node) { + return fragment(JSON.stringify(node.boolean)); + }, + visitEnumValue(node) { + const enumName = nameApi.dataType(node.enumType); + const enumFunction = nameApi.dataEnumFunction(node.enumType); + const variantName = pascalCase(node.variant); + const rawImportFrom = node.importFrom ?? 'generated'; + const importFrom = + rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; + + if (node.value === 'scalar') { + return fragment(`${enumName}.${variantName}`).addImports( + importFrom, + enumName + ); + } + + if (node.value === 'empty') { + return fragment(`${enumFunction}('${variantName}')`).addImports( + importFrom, + enumFunction + ); + } + + return visit(node.value, this) + .mapRender((r) => `${enumFunction}('${variantName}', ${r})`) + .addImports(importFrom, enumFunction); + }, + visitMapValue(node) { + const entryFragments = node.entries.map(([k, v]) => + mergeFragments( + [visit(k, this), visit(v, this)], + (renders) => `[${renders.join(', ')}]` + ) + ); + return mergeFragments( + entryFragments, + (renders) => `new Map([${renders.join(', ')}])` + ); + }, + visitNoneValue() { + return fragment('none()').addImports('solanaOptions', 'none'); + }, + visitNumberValue(node) { + return fragment(JSON.stringify(node.number)); + }, + visitPublicKeyValue(node) { + return fragment(`address("${node.publicKey}")`).addImports( + 'solanaAddresses', + 'address' + ); + }, + visitSetValue(node) { + return mergeFragments( + node.items.map((v) => visit(v, this)), + (renders) => `new Set([${renders.join(', ')}])` + ); + }, + visitSomeValue(node) { + return visit(node.value, this) + .mapRender((r) => `some(${r})`) + .addImports('solanaOptions', 'some'); + }, + visitStringValue(node) { + return fragment(JSON.stringify(node.string)); + }, + visitStructValue(node) { + const fieldFragments = Object.entries(node.fields).map(([k, v]) => + visit(v, this).mapRender((r) => `${k}: ${r}`) + ); + return mergeFragments( + fieldFragments, + (renders) => `{ ${renders.join(', ')} }` + ); + }, + visitTupleValue(node) { + return mergeFragments( + node.items.map((v) => visit(v, this)), + (renders) => `[${renders.join(', ')}]` + ); + }, + }; +} From 44b9d4407900cf520b5f671e2c6928514f4548e5 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:56:30 +0000 Subject: [PATCH 09/12] Create renderValueNodeVisitor for rust renderer --- src/renderers/rust/getRenderMapVisitor.ts | 2 +- src/renderers/rust/renderValueNode.ts | 105 --------------- src/renderers/rust/renderValueNodeVisitor.ts | 132 +++++++++++++++++++ 3 files changed, 133 insertions(+), 106 deletions(-) delete mode 100644 src/renderers/rust/renderValueNode.ts create mode 100644 src/renderers/rust/renderValueNodeVisitor.ts diff --git a/src/renderers/rust/getRenderMapVisitor.ts b/src/renderers/rust/getRenderMapVisitor.ts index 07d976b85..737a0992b 100644 --- a/src/renderers/rust/getRenderMapVisitor.ts +++ b/src/renderers/rust/getRenderMapVisitor.ts @@ -18,7 +18,7 @@ import { import { extendVisitor, staticVisitor, visit } from '../../visitors'; import { RustImportMap } from './RustImportMap'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; -import { renderValueNode } from './renderValueNode'; +import { renderValueNode } from './renderValueNodeVisitor'; export type GetRustRenderMapOptions = { renderParentInstructions?: boolean; diff --git a/src/renderers/rust/renderValueNode.ts b/src/renderers/rust/renderValueNode.ts deleted file mode 100644 index 8532e6116..000000000 --- a/src/renderers/rust/renderValueNode.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { ValueNode } from '../../nodes'; -import { pascalCase } from '../../shared'; -import { RustImportMap } from './RustImportMap'; - -export function renderValueNode( - value: ValueNode, - useStr: boolean = false -): { - imports: RustImportMap; - render: string; -} { - const imports = new RustImportMap(); - switch (value.kind) { - case 'list': - const list = value.values.map((v) => renderValueNode(v)); - return { - imports: imports.mergeWith(...list.map((c) => c.imports)), - render: `[${list.map((c) => c.render).join(', ')}]`, - }; - case 'tuple': - const tuple = value.values.map((v) => renderValueNode(v)); - return { - imports: imports.mergeWith(...tuple.map((c) => c.imports)), - render: `(${tuple.map((c) => c.render).join(', ')})`, - }; - case 'set': - const set = value.values.map((v) => renderValueNode(v)); - imports.add('std::collection::HashSet'); - return { - imports: imports.mergeWith(...set.map((c) => c.imports)), - render: `HashSet::from([${set.map((c) => c.render).join(', ')}])`, - }; - case 'map': - const map = value.values.map(([k, v]) => { - const mapKey = renderValueNode(k); - const mapValue = renderValueNode(v); - return { - imports: mapKey.imports.mergeWith(mapValue.imports), - render: `[${mapKey.render}, ${mapValue.render}]`, - }; - }); - imports.add('std::collection::HashMap'); - return { - imports: imports.mergeWith(...map.map((c) => c.imports)), - render: `HashMap::from([${map.map((c) => c.render).join(', ')}])`, - }; - case 'struct': - const struct = Object.entries(value.values).map(([k, v]) => { - const structValue = renderValueNode(v); - return { - imports: structValue.imports, - render: `${k}: ${structValue.render}`, - }; - }); - return { - imports: imports.mergeWith(...struct.map((c) => c.imports)), - render: `{ ${struct.map((c) => c.render).join(', ')} }`, - }; - case 'enum': - const enumName = pascalCase(value.enumType); - const variantName = pascalCase(value.variant); - const rawImportFrom = value.importFrom ?? 'generated'; - const importFrom = - rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; - imports.add(`${importFrom}::${enumName}`); - if (value.value === 'scalar' || value.value === 'empty') { - return { imports, render: `${enumName}::${variantName}` }; - } - const enumValue = renderValueNode(value.value); - const fields = enumValue.render; - return { - imports: imports.mergeWith(enumValue.imports), - render: `${enumName}::${variantName} ${fields}`, - }; - case 'optionSome': - const child = renderValueNode(value.value); - return { - ...child, - render: `Some(${child.render})`, - }; - case 'optionNone': - return { - imports: new RustImportMap(), - render: 'None', - }; - case 'publicKey': - return { - imports: new RustImportMap().add('solana_program::pubkey'), - render: `pubkey!("${value.value}")`, - }; - case 'string': - return { - imports, - render: useStr - ? `${JSON.stringify(value.value)}` - : `String::from(${JSON.stringify(value.value)})`, - }; - case 'number': - case 'boolean': - return { imports, render: JSON.stringify(value.value) }; - default: - const neverDefault: never = value; - throw new Error(`Unexpected value type ${(neverDefault as any).kind}`); - } -} diff --git a/src/renderers/rust/renderValueNodeVisitor.ts b/src/renderers/rust/renderValueNodeVisitor.ts new file mode 100644 index 000000000..d56d4259e --- /dev/null +++ b/src/renderers/rust/renderValueNodeVisitor.ts @@ -0,0 +1,132 @@ +import { RustImportMap } from './RustImportMap'; +import { Visitor, visit } from '../../visitors'; +import { RegisteredValueNodes, ValueNode } from '../../nodes'; +import { pascalCase } from '../../shared'; + +export function renderValueNode( + value: ValueNode, + useStr: boolean = false +): { + imports: RustImportMap; + render: string; +} { + return visit(value, renderValueNodeVisitor(useStr)); +} + +export function renderValueNodeVisitor(useStr: boolean = false): Visitor< + { + imports: RustImportMap; + render: string; + }, + keyof RegisteredValueNodes +> { + return { + visitArrayValue(node) { + const list = node.items.map((v) => visit(v, this)); + return { + imports: new RustImportMap().mergeWith(...list.map((c) => c.imports)), + render: `[${list.map((c) => c.render).join(', ')}]`, + }; + }, + visitBooleanValue(node) { + return { + imports: new RustImportMap(), + render: JSON.stringify(node.boolean), + }; + }, + visitEnumValue(node) { + const imports = new RustImportMap(); + const enumName = pascalCase(node.enumType); + const variantName = pascalCase(node.variant); + const rawImportFrom = node.importFrom ?? 'generated'; + const importFrom = + rawImportFrom === 'generated' ? 'generatedTypes' : rawImportFrom; + imports.add(`${importFrom}::${enumName}`); + if (node.value === 'scalar' || node.value === 'empty') { + return { imports, render: `${enumName}::${variantName}` }; + } + const enumValue = visit(node.value, this); + const fields = enumValue.render; + return { + imports: imports.mergeWith(enumValue.imports), + render: `${enumName}::${variantName} ${fields}`, + }; + }, + visitMapValue(node) { + const map = node.entries.map(([k, v]) => { + const mapKey = visit(k, this); + const mapValue = visit(v, this); + return { + imports: mapKey.imports.mergeWith(mapValue.imports), + render: `[${mapKey.render}, ${mapValue.render}]`, + }; + }); + const imports = new RustImportMap().add('std::collection::HashMap'); + return { + imports: imports.mergeWith(...map.map((c) => c.imports)), + render: `HashMap::from([${map.map((c) => c.render).join(', ')}])`, + }; + }, + visitNoneValue() { + return { + imports: new RustImportMap(), + render: 'None', + }; + }, + visitNumberValue(node) { + return { + imports: new RustImportMap(), + render: JSON.stringify(node.number), + }; + }, + visitPublicKeyValue(node) { + return { + imports: new RustImportMap().add('solana_program::pubkey'), + render: `pubkey!("${node.publicKey}")`, + }; + }, + visitSetValue(node) { + const set = node.items.map((v) => visit(v, this)); + const imports = new RustImportMap().add('std::collection::HashSet'); + return { + imports: imports.mergeWith(...set.map((c) => c.imports)), + render: `HashSet::from([${set.map((c) => c.render).join(', ')}])`, + }; + }, + visitSomeValue(node) { + const child = visit(node.value, this); + return { + ...child, + render: `Some(${child.render})`, + }; + }, + visitStringValue(node) { + return { + imports: new RustImportMap(), + render: useStr + ? `${JSON.stringify(node.string)}` + : `String::from(${JSON.stringify(node.string)})`, + }; + }, + visitStructValue(node) { + const struct = Object.entries(node.fields).map(([k, v]) => { + const structValue = visit(v, this); + return { + imports: structValue.imports, + render: `${k}: ${structValue.render}`, + }; + }); + return { + imports: new RustImportMap().mergeWith(...struct.map((c) => c.imports)), + render: `{ ${struct.map((c) => c.render).join(', ')} }`, + }; + }, + visitTupleValue(node) { + const tuple = node.items.map((v) => visit(v, this)); + return { + imports: new RustImportMap().mergeWith(...tuple.map((c) => c.imports)), + render: `(${tuple.map((c) => c.render).join(', ')})`, + }; + }, + }; +} From ffca0d5d224c30075a743809e93a98bdc3f348d8 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:56:46 +0000 Subject: [PATCH 10/12] Update tests --- test/shared/AnchorDiscriminator.test.ts | 28 ++++++++++++------------- test/testFile.cjs | 26 ++++++++++++++++------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/test/shared/AnchorDiscriminator.test.ts b/test/shared/AnchorDiscriminator.test.ts index 3ca0016a7..6e2682f16 100644 --- a/test/shared/AnchorDiscriminator.test.ts +++ b/test/shared/AnchorDiscriminator.test.ts @@ -1,7 +1,9 @@ import test from 'ava'; import { + arrayValueNode, getAnchorAccountDiscriminator, getAnchorInstructionDiscriminator, + numberValueNode, } from '../../src'; test('it can compute the discriminator of an Anchor account', (t) => { @@ -12,13 +14,12 @@ test('it can compute the discriminator of an Anchor account', (t) => { const discriminator = getAnchorAccountDiscriminator(idlName); // Then we get the expected value. - t.like(discriminator, { - kind: 'list', - values: [187, 127, 9, 35, 155, 68, 86, 40].map((byte) => ({ - kind: 'number', - value: byte, - })), - }); + t.deepEqual( + discriminator, + arrayValueNode( + [187, 127, 9, 35, 155, 68, 86, 40].map((byte) => numberValueNode(byte)) + ) + ); }); test('it can compute the discriminator of an Anchor instruction', (t) => { @@ -29,11 +30,10 @@ test('it can compute the discriminator of an Anchor instruction', (t) => { const discriminator = getAnchorInstructionDiscriminator(idlName); // Then we get the expected value. - t.like(discriminator, { - kind: 'list', - values: [223, 50, 224, 227, 151, 8, 115, 106].map((byte) => ({ - kind: 'number', - value: byte, - })), - }); + t.deepEqual( + discriminator, + arrayValueNode( + [223, 50, 224, 227, 151, 8, 115, 106].map((byte) => numberValueNode(byte)) + ) + ); }); diff --git a/test/testFile.cjs b/test/testFile.cjs index c38ff2848..f34c63fa7 100644 --- a/test/testFile.cjs +++ b/test/testFile.cjs @@ -111,7 +111,9 @@ kinobi.update( defaultsTo: k.conditionalDefault('account', 'delegate', { ifTrue: k.pdaDefault('delegateRecord', { seeds: { - role: k.valueDefault(k.vEnum('delegateRole', 'Collection')), + role: k.valueDefault( + k.enumValueNode('delegateRole', 'Collection') + ), }, }), }), @@ -141,7 +143,7 @@ kinobi.update( type: k.arrayTypeNode(k.publicKeyTypeNode(), { size: k.remainderSizeNode(), }), - defaultsTo: k.valueDefault(k.vList([])), + defaultsTo: k.valueDefault(k.arrayValueNode([])), }, }, remainingAccounts: k.remainingAccountsFromArg('proof'), @@ -159,15 +161,23 @@ kinobi.update( args: { tokenStandard: { type: k.linkTypeNode('tokenStandard'), - defaultsTo: k.valueDefault(k.vEnum('tokenStandard', 'NonFungible')), + defaultsTo: k.valueDefault( + k.enumValueNode('tokenStandard', 'NonFungible') + ), }, }, }, }) ); -const tmKey = (name) => ({ field: 'key', value: k.vEnum('TmKey', name) }); -const taKey = (name) => ({ field: 'key', value: k.vEnum('TaKey', name) }); +const tmKey = (name) => ({ + field: 'key', + value: k.enumValueNode('TmKey', name), +}); +const taKey = (name) => ({ + field: 'key', + value: k.enumValueNode('TaKey', name), +}); kinobi.update( k.setAccountDiscriminatorFromFieldVisitor({ 'mplTokenMetadata.Edition': tmKey('EditionV1'), @@ -202,10 +212,12 @@ kinobi.update( kinobi.update( k.setStructDefaultValuesVisitor({ 'mplTokenMetadata.Collection': { - verified: k.vScalar(false), + verified: k.booleanValueNode(false), }, 'mplTokenMetadata.UpdateArgs.V1': { - tokenStandard: k.vSome(k.vEnum('TokenStandard', 'NonFungible')), + tokenStandard: k.someValueNode( + k.enumValueNode('TokenStandard', 'NonFungible') + ), }, }) ); From 2e8618aba6015d026af6710172b21c678f67f340 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:57:54 +0000 Subject: [PATCH 11/12] Remove support for non-standardized "defaultsValue" IDL field attribute --- test/mpl_token_metadata.json | 6 ++-- .../src/generated/types/creator.ts | 31 +++++-------------- .../js/src/generated/types/creator.ts | 28 +++++------------ 3 files changed, 17 insertions(+), 48 deletions(-) diff --git a/test/mpl_token_metadata.json b/test/mpl_token_metadata.json index e43d5ecf8..6caaa3e69 100644 --- a/test/mpl_token_metadata.json +++ b/test/mpl_token_metadata.json @@ -3984,13 +3984,11 @@ }, { "name": "verified", - "type": "bool", - "defaultsValue": false + "type": "bool" }, { "name": "share", - "type": "u8", - "defaultsValue": 42 + "type": "u8" } ] } diff --git a/test/packages/js-experimental/src/generated/types/creator.ts b/test/packages/js-experimental/src/generated/types/creator.ts index a544a780f..ba61c1834 100644 --- a/test/packages/js-experimental/src/generated/types/creator.ts +++ b/test/packages/js-experimental/src/generated/types/creator.ts @@ -11,13 +11,7 @@ import { getAddressDecoder, getAddressEncoder, } from '@solana/addresses'; -import { - Codec, - Decoder, - Encoder, - combineCodec, - mapEncoder, -} from '@solana/codecs-core'; +import { Codec, Decoder, Encoder, combineCodec } from '@solana/codecs-core'; import { getBooleanDecoder, getBooleanEncoder, @@ -28,25 +22,14 @@ import { getU8Decoder, getU8Encoder } from '@solana/codecs-numbers'; export type Creator = { address: Address; verified: boolean; share: number }; -export type CreatorArgs = { - address: Address; - verified?: boolean; - share?: number; -}; +export type CreatorArgs = Creator; export function getCreatorEncoder() { - return mapEncoder( - getStructEncoder<{ address: Address; verified: boolean; share: number }>([ - ['address', getAddressEncoder()], - ['verified', getBooleanEncoder()], - ['share', getU8Encoder()], - ]), - (value) => ({ - ...value, - verified: value.verified ?? false, - share: value.share ?? 42, - }) - ) satisfies Encoder; + return getStructEncoder([ + ['address', getAddressEncoder()], + ['verified', getBooleanEncoder()], + ['share', getU8Encoder()], + ]) satisfies Encoder; } export function getCreatorDecoder() { diff --git a/test/packages/js/src/generated/types/creator.ts b/test/packages/js/src/generated/types/creator.ts index 0f76bfb23..3d335df9a 100644 --- a/test/packages/js/src/generated/types/creator.ts +++ b/test/packages/js/src/generated/types/creator.ts @@ -10,7 +10,6 @@ import { PublicKey } from '@metaplex-foundation/umi'; import { Serializer, bool, - mapSerializer, publicKey as publicKeySerializer, struct, u8, @@ -18,26 +17,15 @@ import { export type Creator = { address: PublicKey; verified: boolean; share: number }; -export type CreatorArgs = { - address: PublicKey; - verified?: boolean; - share?: number; -}; +export type CreatorArgs = Creator; export function getCreatorSerializer(): Serializer { - return mapSerializer( - struct( - [ - ['address', publicKeySerializer()], - ['verified', bool()], - ['share', u8()], - ], - { description: 'Creator' } - ), - (value) => ({ - ...value, - verified: value.verified ?? false, - share: value.share ?? 42, - }) + return struct( + [ + ['address', publicKeySerializer()], + ['verified', bool()], + ['share', u8()], + ], + { description: 'Creator' } ) as Serializer; } From 17fccf1db5206b3f046cced49f27ce9f1b97cd38 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 29 Dec 2023 21:58:34 +0000 Subject: [PATCH 12/12] Add changeset --- .changeset/dull-bees-juggle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/dull-bees-juggle.md diff --git a/.changeset/dull-bees-juggle.md b/.changeset/dull-bees-juggle.md new file mode 100644 index 000000000..4c3ecfe54 --- /dev/null +++ b/.changeset/dull-bees-juggle.md @@ -0,0 +1,5 @@ +--- +'@metaplex-foundation/kinobi': minor +--- + +Create Value nodes