Skip to content

Commit 452424e

Browse files
committed
Fix LinkNode paths for getTypeManifestVisitor
1 parent 5bdd745 commit 452424e

File tree

6 files changed

+110
-4
lines changed

6 files changed

+110
-4
lines changed

.changeset/dirty-onions-arrive.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@codama/renderers-js-umi': minor
3+
'@codama/renderers-js': minor
4+
---
5+
6+
Fix LinkNode paths for JavaScript `getTypeManifestVisitors`

packages/renderers-js-umi/src/getRenderMapVisitor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}): Visitor<
9696
linkables,
9797
nonScalarEnums,
9898
parentName,
99+
stack,
99100
});
100101
const typeManifestVisitor = getTypeManifestVisitor();
101102
const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();

packages/renderers-js-umi/src/getTypeManifestVisitor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@ export function getTypeManifestVisitor(input: {
6464
linkables: LinkableDictionary;
6565
nonScalarEnums: CamelCaseString[];
6666
parentName?: { loose: string; strict: string };
67+
stack?: NodeStack;
6768
}) {
6869
const { linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input;
6970
let parentName = input.parentName ?? null;
7071
let parentSize: NumberTypeNode | number | null = null;
71-
const stack = new NodeStack();
72+
const stack = input.stack ?? new NodeStack();
7273

7374
return pipe(
7475
staticVisitor(
@@ -428,7 +429,6 @@ export function getTypeManifestVisitor(input: {
428429
const variantName = pascalCase(node.variant);
429430
const importFrom = getImportFrom(node.enum);
430431

431-
// FIXME(loris): No program node can ever be in this stack.
432432
const enumNode = linkables.get([...stack.getPath(), node.enum])?.type;
433433
const isScalar =
434434
enumNode && isNode(enumNode, 'enumTypeNode')

packages/renderers-js/src/getRenderMapVisitor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
114114
nameApi,
115115
nonScalarEnums,
116116
parentName,
117+
stack,
117118
});
118119
const typeManifestVisitor = getTypeManifestVisitor();
119120
const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();

packages/renderers-js/src/getTypeManifestVisitor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ export function getTypeManifestVisitor(input: {
4141
nameApi: NameApi;
4242
nonScalarEnums: CamelCaseString[];
4343
parentName?: { loose: string; strict: string };
44+
stack?: NodeStack;
4445
}) {
4546
const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input;
46-
const stack = new NodeStack();
47+
const stack = input.stack ?? new NodeStack();
4748
let parentName = input.parentName ?? null;
4849

4950
return pipe(
@@ -355,7 +356,6 @@ export function getTypeManifestVisitor(input: {
355356
const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name);
356357
const importFrom = getImportFrom(node.enum);
357358

358-
// FIXME(loris): No program node can ever be in this stack.
359359
const enumNode = linkables.get([...stack.getPath(), node.enum])?.type;
360360
const isScalar =
361361
enumNode && isNode(enumNode, 'enumTypeNode')

packages/renderers-js/test/links/definedType.test.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import {
22
definedTypeLinkNode,
33
definedTypeNode,
4+
enumEmptyVariantTypeNode,
5+
enumTupleVariantTypeNode,
6+
enumTypeNode,
7+
enumValueNode,
48
fixedSizeTypeNode,
9+
numberTypeNode,
510
programNode,
611
stringTypeNode,
712
structFieldTypeNode,
813
structTypeNode,
14+
tupleTypeNode,
915
} from '@codama/nodes';
1016
import { visit } from '@codama/visitors-core';
1117
import { test } from 'vitest';
@@ -91,3 +97,95 @@ test('it can override the import of a linked type', async () => {
9197
'../../hooked': ['Symbol', 'SymbolArgs', 'getSymbolEncoder', 'getSymbolDecoder'],
9298
});
9399
});
100+
101+
test('it knows if an enum value is a scalar enum using link nodes', async () => {
102+
// Given a program with a scalar enum linked in a default value.
103+
const node = programNode({
104+
definedTypes: [
105+
definedTypeNode({
106+
name: 'person',
107+
type: structTypeNode([
108+
structFieldTypeNode({
109+
defaultValue: enumValueNode('direction', 'up'),
110+
name: 'movement',
111+
type: definedTypeLinkNode('direction'),
112+
}),
113+
]),
114+
}),
115+
definedTypeNode({
116+
name: 'direction',
117+
type: enumTypeNode([
118+
enumEmptyVariantTypeNode('up'),
119+
enumEmptyVariantTypeNode('right'),
120+
enumEmptyVariantTypeNode('down'),
121+
enumEmptyVariantTypeNode('left'),
122+
]),
123+
}),
124+
],
125+
name: 'myProgram',
126+
publicKey: '1111',
127+
});
128+
129+
// When we render it.
130+
const renderMap = visit(node, getRenderMapVisitor());
131+
132+
// Then we expect the direction enum to be exported as a scalar enum.
133+
await renderMapContains(renderMap, 'types/person.ts', [
134+
'movement: value.movement ?? Direction.Up',
135+
'export type Person = { movement: Direction }',
136+
'export type PersonArgs = { movement?: DirectionArgs }',
137+
'getDirectionEncoder()',
138+
'getDirectionDecoder()',
139+
]);
140+
141+
// And we expect the following imports.
142+
await renderMapContainsImports(renderMap, 'types/person.ts', {
143+
'.': ['Direction', 'DirectionArgs', 'getDirectionEncoder', 'getDirectionDecoder'],
144+
});
145+
});
146+
147+
test('it knows if an enum value is a data enum using link nodes', async () => {
148+
// Given a program with a data enum linked in a default value.
149+
const node = programNode({
150+
definedTypes: [
151+
definedTypeNode({
152+
name: 'person',
153+
type: structTypeNode([
154+
structFieldTypeNode({
155+
defaultValue: enumValueNode('action', 'stop'),
156+
name: 'nextAction',
157+
type: definedTypeLinkNode('action'),
158+
}),
159+
]),
160+
}),
161+
definedTypeNode({
162+
name: 'action',
163+
type: enumTypeNode([
164+
enumEmptyVariantTypeNode('stop'),
165+
enumEmptyVariantTypeNode('turnRight'),
166+
enumEmptyVariantTypeNode('turnLeft'),
167+
enumTupleVariantTypeNode('moveForward', tupleTypeNode([numberTypeNode('u8')])),
168+
]),
169+
}),
170+
],
171+
name: 'myProgram',
172+
publicKey: '1111',
173+
});
174+
175+
// When we render it.
176+
const renderMap = visit(node, getRenderMapVisitor());
177+
178+
// Then we expect the action enum to be exported as a data enum.
179+
await renderMapContains(renderMap, 'types/person.ts', [
180+
"nextAction: value.nextAction ?? action('Stop')",
181+
'export type Person = { nextAction: Action }',
182+
'export type PersonArgs = { nextAction?: ActionArgs }',
183+
'getActionEncoder()',
184+
'getActionDecoder()',
185+
]);
186+
187+
// And we expect the following imports.
188+
await renderMapContainsImports(renderMap, 'types/person.ts', {
189+
'.': ['Action', 'ActionArgs', 'getActionEncoder', 'getActionDecoder'],
190+
});
191+
});

0 commit comments

Comments
 (0)