Skip to content

Commit 51c17f2

Browse files
committed
Fix LinkNode paths for getByteSizeVisitor
1 parent f8e1b19 commit 51c17f2

File tree

5 files changed

+58
-19
lines changed

5 files changed

+58
-19
lines changed

.changeset/soft-beds-jam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@codama/visitors-core': minor
3+
---
4+
5+
Fix LinkNode paths for `getByteSizeVisitor`

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export type GetRenderMapOptions = {
6363
export function getRenderMapVisitor(options: GetRenderMapOptions = {}): Visitor<RenderMap> {
6464
const linkables = new LinkableDictionary();
6565
const stack = new NodeStack();
66-
const byteSizeVisitor = getByteSizeVisitor(linkables, stack);
6766
let program: ProgramNode | null = null;
6867

6968
const renderParentInstructions = options.renderParentInstructions ?? false;
@@ -100,6 +99,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}): Visitor<
10099
});
101100
const typeManifestVisitor = getTypeManifestVisitor();
102101
const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();
102+
const byteSizeVisitor = getByteSizeVisitor(linkables, stack);
103103

104104
function getInstructionAccountType(account: ResolvedInstructionAccount): string {
105105
if (account.isPda && account.isSigner === false) return 'Pda';

packages/visitors-core/src/getByteSizeVisitor.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { isNode, isScalarEnum, REGISTERED_TYPE_NODE_KINDS, RegisteredTypeNode }
33
import { extendVisitor } from './extendVisitor';
44
import { LinkableDictionary } from './LinkableDictionary';
55
import { mergeVisitor } from './mergeVisitor';
6+
import { getLastNodeFromPath } from './NodePath';
67
import { NodeStack } from './NodeStack';
78
import { pipe } from './pipe';
89
import { recordNodeStackVisitor } from './recordNodeStackVisitor';
@@ -69,19 +70,20 @@ export function getByteSizeVisitor(
6970
visitDefinedTypeLink(node, { self }) {
7071
// Fetch the linked type and return null if not found.
7172
// The validator visitor will throw a proper error later on.
72-
// FIXME: Keep track of our own internal stack within this visitor (starting from a provided NodePath).
73-
const linkedDefinedType = linkables.get([...stack.getPath(), node]);
74-
if (!linkedDefinedType) {
75-
return null;
76-
}
73+
const linkedDefinedPath = linkables.getPath(stack.getPath(node.kind));
74+
if (!linkedDefinedPath) return null;
75+
const linkedDefinedType = getLastNodeFromPath(linkedDefinedPath);
7776

7877
// This prevents infinite recursion by using assuming
7978
// cyclic types don't have a fixed size.
8079
if (definedTypeStack.includes(linkedDefinedType.name)) {
8180
return null;
8281
}
8382

84-
return visit(linkedDefinedType, self);
83+
stack.pushPath(linkedDefinedPath);
84+
const result = visit(linkedDefinedType, self);
85+
stack.popPath();
86+
return result;
8587
},
8688

8789
visitEnumEmptyVariantType() {

packages/visitors-core/test/getByteSizeVisitor.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import {
2+
definedTypeLinkNode,
3+
definedTypeNode,
24
enumEmptyVariantTypeNode,
35
enumStructVariantTypeNode,
46
enumTupleVariantTypeNode,
@@ -7,15 +9,18 @@ import {
79
Node,
810
NumberFormat,
911
numberTypeNode,
12+
programLinkNode,
13+
programNode,
1014
publicKeyTypeNode,
15+
rootNode,
1116
stringTypeNode,
1217
structFieldTypeNode,
1318
structTypeNode,
1419
tupleTypeNode,
1520
} from '@codama/nodes';
1621
import { expect, test } from 'vitest';
1722

18-
import { getByteSizeVisitor, LinkableDictionary, NodeStack, visit, Visitor } from '../src';
23+
import { getByteSizeVisitor, getRecordLinkablesVisitor, LinkableDictionary, NodeStack, visit, Visitor } from '../src';
1924

2025
const expectSize = (node: Node, expectedSize: number | null) => {
2126
expect(visit(node, getByteSizeVisitor(new LinkableDictionary(), new NodeStack()) as Visitor<number | null>)).toBe(
@@ -104,3 +109,38 @@ test('it gets the size of variable data enums', () => {
104109
null,
105110
);
106111
});
112+
113+
test('it follows linked nodes using the correct paths', () => {
114+
// Given two link nodes designed so that the path would
115+
// fail if we did not save and restored linked paths.
116+
const programA = programNode({
117+
definedTypes: [
118+
definedTypeNode({
119+
name: 'typeA',
120+
type: definedTypeLinkNode('typeB1', programLinkNode('programB')),
121+
}),
122+
],
123+
name: 'programA',
124+
publicKey: '1111',
125+
});
126+
const programB = programNode({
127+
definedTypes: [
128+
definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }),
129+
definedTypeNode({ name: 'typeB2', type: numberTypeNode('u64') }),
130+
],
131+
name: 'programB',
132+
publicKey: '2222',
133+
});
134+
const root = rootNode(programA, [programB]);
135+
136+
// And given a recorded linkables dictionary.
137+
const linkables = new LinkableDictionary();
138+
visit(root, getRecordLinkablesVisitor(linkables));
139+
140+
// When we visit the first defined type.
141+
const visitor = getByteSizeVisitor(linkables, new NodeStack([root, programA]));
142+
const result = visit(programA.definedTypes[0], visitor);
143+
144+
// Then we expect the final linkable to be resolved.
145+
expect(result).toBe(8);
146+
});

packages/visitors/src/setFixedAccountSizesVisitor.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,22 @@ import {
44
getLastNodeFromPath,
55
isNodePath,
66
LinkableDictionary,
7-
NodeStack,
87
pipe,
98
recordLinkablesOnFirstVisitVisitor,
10-
recordNodeStackVisitor,
119
topDownTransformerVisitor,
1210
visit,
1311
} from '@codama/visitors-core';
1412

1513
export function setFixedAccountSizesVisitor() {
1614
const linkables = new LinkableDictionary();
17-
const stack = new NodeStack();
18-
const byteSizeVisitor = getByteSizeVisitor(linkables, stack);
1915

2016
const visitor = topDownTransformerVisitor(
2117
[
2218
{
2319
select: path => isNodePath(path, 'accountNode') && getLastNodeFromPath(path).size === undefined,
24-
transform: node => {
20+
transform: (node, stack) => {
2521
assertIsNode(node, 'accountNode');
26-
const size = visit(node.data, byteSizeVisitor);
22+
const size = visit(node.data, getByteSizeVisitor(linkables, stack));
2723
if (size === null) return node;
2824
return accountNode({ ...node, size }) as typeof node;
2925
},
@@ -32,9 +28,5 @@ export function setFixedAccountSizesVisitor() {
3228
['rootNode', 'programNode', 'accountNode'],
3329
);
3430

35-
return pipe(
36-
visitor,
37-
v => recordNodeStackVisitor(v, stack),
38-
v => recordLinkablesOnFirstVisitVisitor(v, linkables),
39-
);
31+
return pipe(visitor, v => recordLinkablesOnFirstVisitVisitor(v, linkables));
4032
}

0 commit comments

Comments
 (0)