@macalinao/codama-rename-visitor 0.1.1 → 0.2.1

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.
Files changed (36) hide show
  1. package/README.md +16 -99
  2. package/dist/index.d.ts +5 -97
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -220
  5. package/dist/index.js.map +1 -1
  6. package/dist/rename-accounts-visitor.d.ts +26 -0
  7. package/dist/rename-accounts-visitor.d.ts.map +1 -0
  8. package/dist/rename-accounts-visitor.js +43 -0
  9. package/dist/rename-accounts-visitor.js.map +1 -0
  10. package/dist/rename-defined-types-visitor.d.ts +27 -0
  11. package/dist/rename-defined-types-visitor.d.ts.map +1 -0
  12. package/dist/rename-defined-types-visitor.js +46 -0
  13. package/dist/rename-defined-types-visitor.js.map +1 -0
  14. package/dist/rename-instructions-visitor.d.ts +26 -0
  15. package/dist/rename-instructions-visitor.d.ts.map +1 -0
  16. package/dist/rename-instructions-visitor.js +43 -0
  17. package/dist/rename-instructions-visitor.js.map +1 -0
  18. package/dist/rename-visitor.d.ts +35 -0
  19. package/dist/rename-visitor.d.ts.map +1 -0
  20. package/dist/rename-visitor.js +75 -0
  21. package/dist/rename-visitor.js.map +1 -0
  22. package/dist/types.d.ts +12 -0
  23. package/dist/types.d.ts.map +1 -0
  24. package/dist/types.js +2 -0
  25. package/dist/types.js.map +1 -0
  26. package/package.json +6 -4
  27. package/src/index.ts +14 -291
  28. package/src/rename-accounts-visitor.ts +50 -0
  29. package/src/rename-defined-types-visitor.test.ts +44 -0
  30. package/src/rename-defined-types-visitor.ts +59 -0
  31. package/src/rename-instructions-visitor.test.ts +83 -0
  32. package/src/rename-instructions-visitor.ts +50 -0
  33. package/src/rename-visitor.test.ts +175 -0
  34. package/src/rename-visitor.ts +94 -0
  35. package/src/types.ts +11 -0
  36. package/src/index.test.ts +0 -409
@@ -0,0 +1,59 @@
1
+ import type { DefinedTypeNode, Node } from "codama";
2
+ import {
3
+ assertIsNode,
4
+ bottomUpTransformerVisitor,
5
+ camelCase,
6
+ rootNodeVisitor,
7
+ visit,
8
+ } from "codama";
9
+
10
+ /**
11
+ * Transform function that renames a defined type node based on a mapping.
12
+ *
13
+ * @param node - The node to transform
14
+ * @param mapping - Object mapping old defined type names to new defined type names
15
+ * @returns The transformed defined type node
16
+ */
17
+ export function renameDefinedTypeTransform(
18
+ node: Node,
19
+ mapping: Record<string, string>,
20
+ ): DefinedTypeNode {
21
+ assertIsNode(node, "definedTypeNode");
22
+ const newName = mapping[node.name];
23
+ if (!newName) {
24
+ return node;
25
+ }
26
+ return {
27
+ ...node,
28
+ name: camelCase(newName),
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Creates a visitor that renames defined types in a Codama IDL.
34
+ *
35
+ * @param mapping - Object mapping old defined type names to new defined type names
36
+ * @returns A root node visitor that renames defined types
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const visitor = renameDefinedTypesVisitor({
41
+ * "counter": "counterAccount",
42
+ * "config": "programConfig"
43
+ * });
44
+ * codama.update(visitor);
45
+ * ```
46
+ */
47
+ export function renameDefinedTypesVisitor(
48
+ mapping: Record<string, string>,
49
+ ): ReturnType<typeof rootNodeVisitor> {
50
+ return rootNodeVisitor((root) => {
51
+ const typeVisitor = bottomUpTransformerVisitor([
52
+ {
53
+ select: "[definedTypeNode]",
54
+ transform: (node) => renameDefinedTypeTransform(node, mapping),
55
+ },
56
+ ]);
57
+ return visit(root, typeVisitor);
58
+ });
59
+ }
@@ -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
+ }