@macalinao/codama-rename-visitor 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/index.d.ts +5 -97
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -220
- package/dist/index.js.map +1 -1
- package/dist/rename-accounts-visitor.d.ts +26 -0
- package/dist/rename-accounts-visitor.d.ts.map +1 -0
- package/dist/rename-accounts-visitor.js +43 -0
- package/dist/rename-accounts-visitor.js.map +1 -0
- package/dist/rename-defined-types-visitor.d.ts +27 -0
- package/dist/rename-defined-types-visitor.d.ts.map +1 -0
- package/dist/rename-defined-types-visitor.js +46 -0
- package/dist/rename-defined-types-visitor.js.map +1 -0
- package/dist/rename-instructions-visitor.d.ts +26 -0
- package/dist/rename-instructions-visitor.d.ts.map +1 -0
- package/dist/rename-instructions-visitor.js +43 -0
- package/dist/rename-instructions-visitor.js.map +1 -0
- package/dist/rename-visitor.d.ts +35 -0
- package/dist/rename-visitor.d.ts.map +1 -0
- package/dist/rename-visitor.js +75 -0
- package/dist/rename-visitor.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +6 -4
- package/src/index.ts +14 -291
- package/src/rename-accounts-visitor.ts +50 -0
- package/src/rename-defined-types-visitor.test.ts +44 -0
- package/src/rename-defined-types-visitor.ts +59 -0
- package/src/rename-instructions-visitor.test.ts +83 -0
- package/src/rename-instructions-visitor.ts +50 -0
- package/src/rename-visitor.test.ts +175 -0
- package/src/rename-visitor.ts +94 -0
- package/src/types.ts +11 -0
- package/src/index.test.ts +0 -409
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/// <reference types="bun-types" />
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import type { ProgramNode, RootNode } from "codama";
|
|
4
|
+
import {
|
|
5
|
+
camelCase,
|
|
6
|
+
instructionAccountNode,
|
|
7
|
+
instructionNode,
|
|
8
|
+
programNode,
|
|
9
|
+
rootNode,
|
|
10
|
+
visit,
|
|
11
|
+
} from "codama";
|
|
12
|
+
import { renameInstructionsVisitor } from "./rename-instructions-visitor.js";
|
|
13
|
+
|
|
14
|
+
describe("renameInstructionsVisitor", () => {
|
|
15
|
+
it("should rename instructions based on the mapping", () => {
|
|
16
|
+
const program: ProgramNode = programNode({
|
|
17
|
+
name: camelCase("testProgram"),
|
|
18
|
+
publicKey: "11111111111111111111111111111111",
|
|
19
|
+
instructions: [
|
|
20
|
+
instructionNode({
|
|
21
|
+
name: camelCase("transfer"),
|
|
22
|
+
accounts: [
|
|
23
|
+
instructionAccountNode({
|
|
24
|
+
name: camelCase("source"),
|
|
25
|
+
isWritable: true,
|
|
26
|
+
isSigner: false,
|
|
27
|
+
}),
|
|
28
|
+
instructionAccountNode({
|
|
29
|
+
name: camelCase("destination"),
|
|
30
|
+
isWritable: true,
|
|
31
|
+
isSigner: false,
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
}),
|
|
35
|
+
instructionNode({
|
|
36
|
+
name: camelCase("mint"),
|
|
37
|
+
accounts: [
|
|
38
|
+
instructionAccountNode({
|
|
39
|
+
name: camelCase("mint"),
|
|
40
|
+
isWritable: true,
|
|
41
|
+
isSigner: false,
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
}),
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const root = rootNode(program);
|
|
49
|
+
const visitor = renameInstructionsVisitor({
|
|
50
|
+
transfer: "transferTokens",
|
|
51
|
+
mint: "mintNft",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
55
|
+
const instructions = updatedRoot.program.instructions;
|
|
56
|
+
|
|
57
|
+
expect(instructions[0].name.toString()).toBe("transferTokens");
|
|
58
|
+
expect(instructions[1].name.toString()).toBe("mintNft");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should leave unmapped instructions unchanged", () => {
|
|
62
|
+
const program: ProgramNode = programNode({
|
|
63
|
+
name: camelCase("testProgram"),
|
|
64
|
+
publicKey: "11111111111111111111111111111111",
|
|
65
|
+
instructions: [
|
|
66
|
+
instructionNode({
|
|
67
|
+
name: camelCase("burn"),
|
|
68
|
+
accounts: [],
|
|
69
|
+
}),
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const root = rootNode(program);
|
|
74
|
+
const visitor = renameInstructionsVisitor({
|
|
75
|
+
transfer: "transferTokens",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
79
|
+
const instructions = updatedRoot.program.instructions;
|
|
80
|
+
|
|
81
|
+
expect(instructions[0].name.toString()).toBe("burn");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { InstructionNode, Node, NodeKind, Visitor } from "codama";
|
|
2
|
+
import { assertIsNode, bottomUpTransformerVisitor, camelCase } from "codama";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Transform function that renames an instruction node based on a mapping.
|
|
6
|
+
*
|
|
7
|
+
* @param node - The node to transform
|
|
8
|
+
* @param mapping - Object mapping old instruction names to new instruction names
|
|
9
|
+
* @returns The transformed instruction node
|
|
10
|
+
*/
|
|
11
|
+
export function renameInstructionTransform(
|
|
12
|
+
node: Node,
|
|
13
|
+
mapping: Record<string, string>,
|
|
14
|
+
): InstructionNode {
|
|
15
|
+
assertIsNode(node, "instructionNode");
|
|
16
|
+
const newName = mapping[node.name];
|
|
17
|
+
if (!newName) {
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
...node,
|
|
22
|
+
name: camelCase(newName),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a visitor that renames instructions in a Codama IDL.
|
|
28
|
+
*
|
|
29
|
+
* @param mapping - Object mapping old instruction names to new instruction names
|
|
30
|
+
* @returns A root node visitor that renames instructions
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const visitor = renameInstructionsVisitor({
|
|
35
|
+
* "transfer": "transferTokens",
|
|
36
|
+
* "mint": "mintNft"
|
|
37
|
+
* });
|
|
38
|
+
* codama.update(visitor);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function renameInstructionsVisitor<
|
|
42
|
+
TNodeKind extends NodeKind = NodeKind,
|
|
43
|
+
>(mapping: Record<string, string>): Visitor<Node | null, TNodeKind> {
|
|
44
|
+
return bottomUpTransformerVisitor([
|
|
45
|
+
{
|
|
46
|
+
select: "[instructionNode]",
|
|
47
|
+
transform: (node) => renameInstructionTransform(node, mapping),
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/// <reference types="bun-types" />
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import type { ProgramNode, RootNode } from "codama";
|
|
4
|
+
import {
|
|
5
|
+
camelCase,
|
|
6
|
+
definedTypeNode,
|
|
7
|
+
instructionNode,
|
|
8
|
+
numberTypeNode,
|
|
9
|
+
programNode,
|
|
10
|
+
rootNode,
|
|
11
|
+
visit,
|
|
12
|
+
} from "codama";
|
|
13
|
+
import { renameVisitor } from "./rename-visitor.js";
|
|
14
|
+
|
|
15
|
+
describe("renameVisitor (program-specific format)", () => {
|
|
16
|
+
it("should rename instructions in specific programs", () => {
|
|
17
|
+
const quarryMineProgram: ProgramNode = programNode({
|
|
18
|
+
name: camelCase("quarryMine"),
|
|
19
|
+
publicKey: "11111111111111111111111111111111",
|
|
20
|
+
instructions: [
|
|
21
|
+
instructionNode({
|
|
22
|
+
name: camelCase("claimRewards"),
|
|
23
|
+
accounts: [],
|
|
24
|
+
}),
|
|
25
|
+
instructionNode({
|
|
26
|
+
name: camelCase("stake"),
|
|
27
|
+
accounts: [],
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const tokenProgram: ProgramNode = programNode({
|
|
33
|
+
name: camelCase("token"),
|
|
34
|
+
publicKey: "22222222222222222222222222222222",
|
|
35
|
+
instructions: [
|
|
36
|
+
instructionNode({
|
|
37
|
+
name: camelCase("transfer"),
|
|
38
|
+
accounts: [],
|
|
39
|
+
}),
|
|
40
|
+
instructionNode({
|
|
41
|
+
name: camelCase("mint"),
|
|
42
|
+
accounts: [],
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Create a root with multiple programs
|
|
48
|
+
const root = rootNode(quarryMineProgram, [tokenProgram]);
|
|
49
|
+
|
|
50
|
+
const visitor = renameVisitor({
|
|
51
|
+
quarryMine: {
|
|
52
|
+
instructions: {
|
|
53
|
+
claimRewards: "claimRewardsMine",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
token: {
|
|
57
|
+
instructions: {
|
|
58
|
+
transfer: "transferTokens",
|
|
59
|
+
mint: "mintNft",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
65
|
+
const quarryInstructions = updatedRoot.program.instructions;
|
|
66
|
+
const tokenInstructions =
|
|
67
|
+
updatedRoot.additionalPrograms?.[0]?.instructions ?? [];
|
|
68
|
+
|
|
69
|
+
expect(quarryInstructions[0].name.toString()).toBe("claimRewardsMine");
|
|
70
|
+
expect(quarryInstructions[1].name.toString()).toBe("stake"); // Unchanged
|
|
71
|
+
expect(tokenInstructions[0].name.toString()).toBe("transferTokens");
|
|
72
|
+
expect(tokenInstructions[1].name.toString()).toBe("mintNft");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should rename defined types in specific programs", () => {
|
|
76
|
+
const program: ProgramNode = programNode({
|
|
77
|
+
name: camelCase("myProgram"),
|
|
78
|
+
publicKey: "11111111111111111111111111111111",
|
|
79
|
+
definedTypes: [
|
|
80
|
+
definedTypeNode({
|
|
81
|
+
name: camelCase("tokenMintedEvent"),
|
|
82
|
+
type: numberTypeNode("u64"),
|
|
83
|
+
}),
|
|
84
|
+
definedTypeNode({
|
|
85
|
+
name: camelCase("counter"),
|
|
86
|
+
type: numberTypeNode("u64"),
|
|
87
|
+
}),
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const root = rootNode(program);
|
|
92
|
+
|
|
93
|
+
const visitor = renameVisitor({
|
|
94
|
+
myProgram: {
|
|
95
|
+
definedTypes: {
|
|
96
|
+
counter: "counterAccount",
|
|
97
|
+
tokenMintedEvent: "nftMintedEvent",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
103
|
+
const types = updatedRoot.program.definedTypes;
|
|
104
|
+
|
|
105
|
+
expect(types[0].name.toString()).toBe("nftMintedEvent");
|
|
106
|
+
expect(types[1].name.toString()).toBe("counterAccount");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should work with Quarry-style program names (camelCase)", () => {
|
|
110
|
+
const quarryMergeMineProgram: ProgramNode = programNode({
|
|
111
|
+
name: camelCase("quarryMergeMine"),
|
|
112
|
+
publicKey: "QMMD16kjauP5knBwxNUJRZ1Z5o3deBuFrqVjBVmmqto",
|
|
113
|
+
instructions: [
|
|
114
|
+
instructionNode({
|
|
115
|
+
name: camelCase("claimRewards"),
|
|
116
|
+
accounts: [],
|
|
117
|
+
}),
|
|
118
|
+
instructionNode({
|
|
119
|
+
name: camelCase("stake"),
|
|
120
|
+
accounts: [],
|
|
121
|
+
}),
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const root = rootNode(quarryMergeMineProgram);
|
|
126
|
+
|
|
127
|
+
const visitor = renameVisitor({
|
|
128
|
+
quarryMergeMine: {
|
|
129
|
+
instructions: {
|
|
130
|
+
claimRewards: "claimRewardsMergeMine",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
136
|
+
const instructions = updatedRoot.program.instructions;
|
|
137
|
+
|
|
138
|
+
expect(instructions[0].name.toString()).toBe("claimRewardsMergeMine");
|
|
139
|
+
expect(instructions[1].name.toString()).toBe("stake"); // Unchanged
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should handle mixed program configurations", () => {
|
|
143
|
+
const program: ProgramNode = programNode({
|
|
144
|
+
name: camelCase("testProgram"),
|
|
145
|
+
publicKey: "11111111111111111111111111111111",
|
|
146
|
+
instructions: [
|
|
147
|
+
instructionNode({
|
|
148
|
+
name: camelCase("transfer"),
|
|
149
|
+
accounts: [],
|
|
150
|
+
}),
|
|
151
|
+
],
|
|
152
|
+
definedTypes: [
|
|
153
|
+
definedTypeNode({
|
|
154
|
+
name: camelCase("transferEvent"),
|
|
155
|
+
type: numberTypeNode("u64"),
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const root = rootNode(program);
|
|
161
|
+
|
|
162
|
+
const visitor = renameVisitor({
|
|
163
|
+
testProgram: {
|
|
164
|
+
instructions: {
|
|
165
|
+
transfer: "sendTokens",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
171
|
+
const instructions = updatedRoot.program.instructions;
|
|
172
|
+
|
|
173
|
+
expect(instructions[0].name.toString()).toBe("sendTokens");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { Node } from "codama";
|
|
2
|
+
import { bottomUpTransformerVisitor, rootNodeVisitor, visit } from "codama";
|
|
3
|
+
import { renameAccountTransform } from "./rename-accounts-visitor.js";
|
|
4
|
+
import { renameDefinedTypeTransform } from "./rename-defined-types-visitor.js";
|
|
5
|
+
import { renameInstructionTransform } from "./rename-instructions-visitor.js";
|
|
6
|
+
import type { ProgramRenameOptions } from "./types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a visitor that renames accounts, instructions, and defined types in specific programs.
|
|
10
|
+
* This follows the same pattern as addPdasVisitor from Codama.
|
|
11
|
+
*
|
|
12
|
+
* @param renamesByProgram - Object mapping program names to their rename configurations
|
|
13
|
+
* @returns A root node visitor that performs all specified renames
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const visitor = renameVisitor({
|
|
18
|
+
* quarryMine: {
|
|
19
|
+
* instructions: {
|
|
20
|
+
* claimRewards: "claimRewardsMine"
|
|
21
|
+
* },
|
|
22
|
+
* accounts: {
|
|
23
|
+
* miner: "minerAccount"
|
|
24
|
+
* }
|
|
25
|
+
* },
|
|
26
|
+
* token: {
|
|
27
|
+
* instructions: {
|
|
28
|
+
* transfer: "transferTokens",
|
|
29
|
+
* mint: "mintNft"
|
|
30
|
+
* },
|
|
31
|
+
* definedTypes: {
|
|
32
|
+
* tokenData: "tokenMetadata"
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* });
|
|
36
|
+
* codama.update(visitor);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function renameVisitor(
|
|
40
|
+
renamesByProgram: Record<string, ProgramRenameOptions>,
|
|
41
|
+
): ReturnType<typeof rootNodeVisitor> {
|
|
42
|
+
return rootNodeVisitor((root) => {
|
|
43
|
+
const transforms: {
|
|
44
|
+
select: string;
|
|
45
|
+
transform: (node: Node) => Node | null;
|
|
46
|
+
}[] = [];
|
|
47
|
+
|
|
48
|
+
// Process each program's rename configuration
|
|
49
|
+
Object.entries(renamesByProgram).forEach(([programName, renameOptions]) => {
|
|
50
|
+
// Add instruction renames for this program
|
|
51
|
+
if (renameOptions.instructions) {
|
|
52
|
+
Object.entries(renameOptions.instructions).forEach(
|
|
53
|
+
([oldName, newName]) => {
|
|
54
|
+
transforms.push({
|
|
55
|
+
select: `[programNode]${programName}.[instructionNode]${oldName}`,
|
|
56
|
+
transform: (node) =>
|
|
57
|
+
renameInstructionTransform(node, { [oldName]: newName }),
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (renameOptions.accounts) {
|
|
64
|
+
Object.entries(renameOptions.accounts).forEach(([oldName, newName]) => {
|
|
65
|
+
transforms.push({
|
|
66
|
+
select: `[programNode]${programName}.[accountNode]${oldName}`,
|
|
67
|
+
transform: (node) =>
|
|
68
|
+
renameAccountTransform(node, { [oldName]: newName }),
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Add defined type renames for this program
|
|
74
|
+
if (renameOptions.definedTypes) {
|
|
75
|
+
Object.entries(renameOptions.definedTypes ?? {}).forEach(
|
|
76
|
+
([oldName, newName]) => {
|
|
77
|
+
transforms.push({
|
|
78
|
+
select: `[programNode]${programName}.[definedTypeNode]${oldName}`,
|
|
79
|
+
transform: (node) =>
|
|
80
|
+
renameDefinedTypeTransform(node, { [oldName]: newName }),
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (transforms.length === 0) {
|
|
88
|
+
return root;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const visitor = bottomUpTransformerVisitor(transforms);
|
|
92
|
+
return visit(root, visitor);
|
|
93
|
+
});
|
|
94
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rename mapping for a single program
|
|
3
|
+
*/
|
|
4
|
+
export interface ProgramRenameOptions {
|
|
5
|
+
/** Mapping of old account names to new account names */
|
|
6
|
+
accounts?: Record<string, string>;
|
|
7
|
+
/** Mapping of old instruction names to new instruction names */
|
|
8
|
+
instructions?: Record<string, string>;
|
|
9
|
+
/** Mapping of old defined type names to new defined type names */
|
|
10
|
+
definedTypes?: Record<string, string>;
|
|
11
|
+
}
|