@macalinao/codama-rename-visitor 0.1.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 +121 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +221 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/index.test.ts +409 -0
- package/src/index.ts +291 -0
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @macalinao/codama-rename-visitor
|
|
2
|
+
|
|
3
|
+
A Codama visitor for renaming instructions and events within a Solana program.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @macalinao/codama-rename-visitor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
This visitor allows you to rename instructions and events in your Codama IDL. It's particularly useful when you want to change the naming conventions of your program without modifying the original IDL.
|
|
14
|
+
|
|
15
|
+
### Renaming Instructions
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { renameInstructionsVisitor } from "@macalinao/codama-rename-visitor";
|
|
19
|
+
import { visit } from "codama";
|
|
20
|
+
|
|
21
|
+
// Rename specific instructions
|
|
22
|
+
const visitor = renameInstructionsVisitor({
|
|
23
|
+
oldInstructionName: "newInstructionName",
|
|
24
|
+
transfer: "transferTokens",
|
|
25
|
+
mint: "mintNft"
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const updatedRoot = visit(root, visitor);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Renaming Events
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { renameEventsVisitor } from "@macalinao/codama-rename-visitor";
|
|
35
|
+
import { visit } from "codama";
|
|
36
|
+
|
|
37
|
+
// Rename specific events (as defined types)
|
|
38
|
+
const visitor = renameEventsVisitor({
|
|
39
|
+
oldEventName: "newEventName",
|
|
40
|
+
tokenMinted: "nftMinted",
|
|
41
|
+
transferComplete: "transferFinished"
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const updatedRoot = visit(root, visitor);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Program-Specific Renaming (Recommended)
|
|
48
|
+
|
|
49
|
+
The `renameVisitor` follows the same pattern as Codama's `addPdasVisitor`, where you specify renames for specific programs:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { renameVisitor } from "@macalinao/codama-rename-visitor";
|
|
53
|
+
import { visit } from "codama";
|
|
54
|
+
|
|
55
|
+
// Rename elements in specific programs
|
|
56
|
+
const visitor = renameVisitor({
|
|
57
|
+
quarryMine: {
|
|
58
|
+
instructions: {
|
|
59
|
+
claimRewards: "claimRewardsMine"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
token: {
|
|
63
|
+
instructions: {
|
|
64
|
+
transfer: "transferTokens",
|
|
65
|
+
mint: "mintNft"
|
|
66
|
+
},
|
|
67
|
+
events: {
|
|
68
|
+
tokenMinted: "nftMinted"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const updatedRoot = visit(root, visitor);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Legacy Single-Program Renaming
|
|
77
|
+
|
|
78
|
+
For backward compatibility, you can still use the legacy format for single-program renaming:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { renameVisitor } from "@macalinao/codama-rename-visitor";
|
|
82
|
+
import { visit } from "codama";
|
|
83
|
+
|
|
84
|
+
// Legacy format: rename in the current program
|
|
85
|
+
const visitor = renameVisitor({
|
|
86
|
+
instructions: {
|
|
87
|
+
transfer: "transferTokens",
|
|
88
|
+
mint: "mintNft"
|
|
89
|
+
},
|
|
90
|
+
events: {
|
|
91
|
+
tokenMinted: "nftMinted",
|
|
92
|
+
transferComplete: "transferFinished"
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const updatedRoot = visit(root, visitor);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## API
|
|
100
|
+
|
|
101
|
+
### `renameVisitor(renamesByProgram: Record<string, ProgramRenameOptions>)`
|
|
102
|
+
|
|
103
|
+
Creates a visitor that renames instructions, events, and defined types in specific programs. This is the recommended API.
|
|
104
|
+
|
|
105
|
+
- `renamesByProgram`: Object mapping program names to their rename configurations
|
|
106
|
+
- Each program can specify:
|
|
107
|
+
- `instructions`: Mapping of old instruction names to new names
|
|
108
|
+
- `events`: Mapping of old event names to new names
|
|
109
|
+
- `definedTypes`: Mapping of old defined type names to new names
|
|
110
|
+
|
|
111
|
+
### `renameInstructionsVisitor(mapping: Record<string, string>)`
|
|
112
|
+
|
|
113
|
+
Creates a visitor that renames instructions based on the provided mapping. Applies to all programs.
|
|
114
|
+
|
|
115
|
+
### `renameEventsVisitor(mapping: Record<string, string>)`
|
|
116
|
+
|
|
117
|
+
Creates a visitor that renames events (defined types) based on the provided mapping. Applies to all programs.
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { rootNodeVisitor } from "codama";
|
|
2
|
+
/**
|
|
3
|
+
* Rename mapping for a single program
|
|
4
|
+
*/
|
|
5
|
+
export interface ProgramRenameOptions {
|
|
6
|
+
/** Mapping of old instruction names to new instruction names */
|
|
7
|
+
instructions?: Record<string, string>;
|
|
8
|
+
/** Mapping of old event names (as defined types) to new event names */
|
|
9
|
+
events?: Record<string, string>;
|
|
10
|
+
/** Mapping of old defined type names to new defined type names */
|
|
11
|
+
definedTypes?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Options for the rename visitor (legacy interface)
|
|
15
|
+
*/
|
|
16
|
+
export type RenameVisitorOptions = ProgramRenameOptions;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a visitor that renames instructions in a Codama IDL.
|
|
19
|
+
*
|
|
20
|
+
* @param mapping - Object mapping old instruction names to new instruction names
|
|
21
|
+
* @returns A root node visitor that renames instructions
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const visitor = renameInstructionsVisitor({
|
|
26
|
+
* "transfer": "transferTokens",
|
|
27
|
+
* "mint": "mintNft"
|
|
28
|
+
* });
|
|
29
|
+
* codama.update(visitor);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function renameInstructionsVisitor(mapping: Record<string, string>): ReturnType<typeof rootNodeVisitor>;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a visitor that renames events (as defined types) in a Codama IDL.
|
|
35
|
+
*
|
|
36
|
+
* Events in Anchor IDLs are typically converted to defined types in Codama,
|
|
37
|
+
* so this visitor renames specific defined types that represent events.
|
|
38
|
+
*
|
|
39
|
+
* @param mapping - Object mapping old event names to new event names
|
|
40
|
+
* @param eventSuffix - Optional suffix to identify event types (default: "Event")
|
|
41
|
+
* @returns A root node visitor that renames events
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const visitor = renameEventsVisitor({
|
|
46
|
+
* "tokenMinted": "nftMinted",
|
|
47
|
+
* "transferComplete": "transferFinished"
|
|
48
|
+
* });
|
|
49
|
+
* codama.update(visitor);
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function renameEventsVisitor(mapping: Record<string, string>, eventSuffix?: string): ReturnType<typeof rootNodeVisitor>;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a visitor that renames defined types in a Codama IDL.
|
|
55
|
+
*
|
|
56
|
+
* @param mapping - Object mapping old defined type names to new defined type names
|
|
57
|
+
* @returns A root node visitor that renames defined types
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const visitor = renameDefinedTypesVisitor({
|
|
62
|
+
* "counter": "counterAccount",
|
|
63
|
+
* "config": "programConfig"
|
|
64
|
+
* });
|
|
65
|
+
* codama.update(visitor);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function renameDefinedTypesVisitor(mapping: Record<string, string>): ReturnType<typeof rootNodeVisitor>;
|
|
69
|
+
/**
|
|
70
|
+
* Creates a visitor that renames instructions, events, and defined types in specific programs.
|
|
71
|
+
* This follows the same pattern as addPdasVisitor from Codama.
|
|
72
|
+
*
|
|
73
|
+
* @param renamesByProgram - Object mapping program names to their rename configurations
|
|
74
|
+
* @returns A root node visitor that performs all specified renames
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const visitor = renameVisitor({
|
|
79
|
+
* quarryMine: {
|
|
80
|
+
* instructions: {
|
|
81
|
+
* claimRewards: "claimRewardsMine"
|
|
82
|
+
* }
|
|
83
|
+
* },
|
|
84
|
+
* token: {
|
|
85
|
+
* instructions: {
|
|
86
|
+
* transfer: "transferTokens",
|
|
87
|
+
* mint: "mintNft"
|
|
88
|
+
* },
|
|
89
|
+
* events: {
|
|
90
|
+
* tokenMinted: "nftMinted"
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* });
|
|
94
|
+
* codama.update(visitor);
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare function renameVisitor(renamesByProgram: Record<string, ProgramRenameOptions>): ReturnType<typeof rootNodeVisitor>;
|
|
98
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,eAAe,EAEhB,MAAM,QAAQ,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,UAAU,CAAC,OAAO,eAAe,CAAC,CAoBpC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,SAAU,GACpB,UAAU,CAAC,OAAO,eAAe,CAAC,CA8BpC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,UAAU,CAAC,OAAO,eAAe,CAAC,CAoBpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,aAAa,CAC3B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,GACrD,UAAU,CAAC,OAAO,eAAe,CAAC,CAsGpC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { assertIsNode, bottomUpTransformerVisitor, camelCase, rootNodeVisitor, visit, } from "codama";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a visitor that renames instructions in a Codama IDL.
|
|
4
|
+
*
|
|
5
|
+
* @param mapping - Object mapping old instruction names to new instruction names
|
|
6
|
+
* @returns A root node visitor that renames instructions
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const visitor = renameInstructionsVisitor({
|
|
11
|
+
* "transfer": "transferTokens",
|
|
12
|
+
* "mint": "mintNft"
|
|
13
|
+
* });
|
|
14
|
+
* codama.update(visitor);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function renameInstructionsVisitor(mapping) {
|
|
18
|
+
return rootNodeVisitor((root) => {
|
|
19
|
+
const instructionVisitor = bottomUpTransformerVisitor([
|
|
20
|
+
{
|
|
21
|
+
select: "[instructionNode]",
|
|
22
|
+
transform: (node) => {
|
|
23
|
+
assertIsNode(node, "instructionNode");
|
|
24
|
+
const newName = mapping[node.name];
|
|
25
|
+
if (!newName) {
|
|
26
|
+
return node;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...node,
|
|
30
|
+
name: camelCase(newName),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
return visit(root, instructionVisitor);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Creates a visitor that renames events (as defined types) in a Codama IDL.
|
|
40
|
+
*
|
|
41
|
+
* Events in Anchor IDLs are typically converted to defined types in Codama,
|
|
42
|
+
* so this visitor renames specific defined types that represent events.
|
|
43
|
+
*
|
|
44
|
+
* @param mapping - Object mapping old event names to new event names
|
|
45
|
+
* @param eventSuffix - Optional suffix to identify event types (default: "Event")
|
|
46
|
+
* @returns A root node visitor that renames events
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const visitor = renameEventsVisitor({
|
|
51
|
+
* "tokenMinted": "nftMinted",
|
|
52
|
+
* "transferComplete": "transferFinished"
|
|
53
|
+
* });
|
|
54
|
+
* codama.update(visitor);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function renameEventsVisitor(mapping, eventSuffix = "Event") {
|
|
58
|
+
return rootNodeVisitor((root) => {
|
|
59
|
+
const eventVisitor = bottomUpTransformerVisitor([
|
|
60
|
+
{
|
|
61
|
+
select: "[definedTypeNode]",
|
|
62
|
+
transform: (node) => {
|
|
63
|
+
assertIsNode(node, "definedTypeNode");
|
|
64
|
+
// Check if this is an event type (by suffix or by being in the mapping)
|
|
65
|
+
const isEventBySuffix = node.name.endsWith(eventSuffix);
|
|
66
|
+
const isEventInMapping = mapping[node.name] !== undefined;
|
|
67
|
+
if (!(isEventBySuffix || isEventInMapping)) {
|
|
68
|
+
return node;
|
|
69
|
+
}
|
|
70
|
+
const newName = mapping[node.name];
|
|
71
|
+
if (!newName) {
|
|
72
|
+
return node;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...node,
|
|
76
|
+
name: camelCase(newName),
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
return visit(root, eventVisitor);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a visitor that renames defined types in a Codama IDL.
|
|
86
|
+
*
|
|
87
|
+
* @param mapping - Object mapping old defined type names to new defined type names
|
|
88
|
+
* @returns A root node visitor that renames defined types
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const visitor = renameDefinedTypesVisitor({
|
|
93
|
+
* "counter": "counterAccount",
|
|
94
|
+
* "config": "programConfig"
|
|
95
|
+
* });
|
|
96
|
+
* codama.update(visitor);
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function renameDefinedTypesVisitor(mapping) {
|
|
100
|
+
return rootNodeVisitor((root) => {
|
|
101
|
+
const typeVisitor = bottomUpTransformerVisitor([
|
|
102
|
+
{
|
|
103
|
+
select: "[definedTypeNode]",
|
|
104
|
+
transform: (node) => {
|
|
105
|
+
assertIsNode(node, "definedTypeNode");
|
|
106
|
+
const newName = mapping[node.name];
|
|
107
|
+
if (!newName) {
|
|
108
|
+
return node;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
...node,
|
|
112
|
+
name: camelCase(newName),
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
return visit(root, typeVisitor);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates a visitor that renames instructions, events, and defined types in specific programs.
|
|
122
|
+
* This follows the same pattern as addPdasVisitor from Codama.
|
|
123
|
+
*
|
|
124
|
+
* @param renamesByProgram - Object mapping program names to their rename configurations
|
|
125
|
+
* @returns A root node visitor that performs all specified renames
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const visitor = renameVisitor({
|
|
130
|
+
* quarryMine: {
|
|
131
|
+
* instructions: {
|
|
132
|
+
* claimRewards: "claimRewardsMine"
|
|
133
|
+
* }
|
|
134
|
+
* },
|
|
135
|
+
* token: {
|
|
136
|
+
* instructions: {
|
|
137
|
+
* transfer: "transferTokens",
|
|
138
|
+
* mint: "mintNft"
|
|
139
|
+
* },
|
|
140
|
+
* events: {
|
|
141
|
+
* tokenMinted: "nftMinted"
|
|
142
|
+
* }
|
|
143
|
+
* }
|
|
144
|
+
* });
|
|
145
|
+
* codama.update(visitor);
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function renameVisitor(renamesByProgram) {
|
|
149
|
+
return rootNodeVisitor((root) => {
|
|
150
|
+
// Check if this is the legacy single-program format
|
|
151
|
+
// (has instructions, events, or definedTypes at the top level)
|
|
152
|
+
const isLegacyFormat = "instructions" in renamesByProgram ||
|
|
153
|
+
"events" in renamesByProgram ||
|
|
154
|
+
"definedTypes" in renamesByProgram;
|
|
155
|
+
if (isLegacyFormat) {
|
|
156
|
+
// Legacy support: treat as single program renames
|
|
157
|
+
const options = renamesByProgram;
|
|
158
|
+
let transformedRoot = root;
|
|
159
|
+
// Apply instruction renaming
|
|
160
|
+
if (options.instructions &&
|
|
161
|
+
Object.keys(options.instructions).length > 0) {
|
|
162
|
+
transformedRoot = visit(transformedRoot, renameInstructionsVisitor(options.instructions));
|
|
163
|
+
}
|
|
164
|
+
// Apply event renaming
|
|
165
|
+
if (options.events && Object.keys(options.events).length > 0) {
|
|
166
|
+
transformedRoot = visit(transformedRoot, renameEventsVisitor(options.events));
|
|
167
|
+
}
|
|
168
|
+
// Apply defined type renaming
|
|
169
|
+
if (options.definedTypes &&
|
|
170
|
+
Object.keys(options.definedTypes).length > 0) {
|
|
171
|
+
transformedRoot = visit(transformedRoot, renameDefinedTypesVisitor(options.definedTypes));
|
|
172
|
+
}
|
|
173
|
+
return transformedRoot;
|
|
174
|
+
}
|
|
175
|
+
// New format: program-specific renames
|
|
176
|
+
const transforms = [];
|
|
177
|
+
// Process each program's rename configuration
|
|
178
|
+
Object.entries(renamesByProgram).forEach(([programName, renameOptions]) => {
|
|
179
|
+
// Add instruction renames for this program
|
|
180
|
+
if (renameOptions.instructions) {
|
|
181
|
+
Object.entries(renameOptions.instructions).forEach(([oldName, newName]) => {
|
|
182
|
+
transforms.push({
|
|
183
|
+
select: `[programNode]${programName}.[instructionNode]${oldName}`,
|
|
184
|
+
transform: (node) => {
|
|
185
|
+
assertIsNode(node, "instructionNode");
|
|
186
|
+
return {
|
|
187
|
+
...node,
|
|
188
|
+
name: camelCase(newName),
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// Add event/defined type renames for this program
|
|
195
|
+
if (renameOptions.events || renameOptions.definedTypes) {
|
|
196
|
+
const allTypeRenames = {
|
|
197
|
+
...(renameOptions.events ?? {}),
|
|
198
|
+
...(renameOptions.definedTypes ?? {}),
|
|
199
|
+
};
|
|
200
|
+
Object.entries(allTypeRenames).forEach(([oldName, newName]) => {
|
|
201
|
+
transforms.push({
|
|
202
|
+
select: `[programNode]${programName}.[definedTypeNode]${oldName}`,
|
|
203
|
+
transform: (node) => {
|
|
204
|
+
assertIsNode(node, "definedTypeNode");
|
|
205
|
+
return {
|
|
206
|
+
...node,
|
|
207
|
+
name: camelCase(newName),
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
if (transforms.length === 0) {
|
|
215
|
+
return root;
|
|
216
|
+
}
|
|
217
|
+
const visitor = bottomUpTransformerVisitor(transforms);
|
|
218
|
+
return visit(root, visitor);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DefinedTypeNode, InstructionNode, Node, RootNode } from \"codama\";\nimport {\n assertIsNode,\n bottomUpTransformerVisitor,\n camelCase,\n rootNodeVisitor,\n visit,\n} from \"codama\";\n\n/**\n * Rename mapping for a single program\n */\nexport interface ProgramRenameOptions {\n /** Mapping of old instruction names to new instruction names */\n instructions?: Record<string, string>;\n /** Mapping of old event names (as defined types) to new event names */\n events?: Record<string, string>;\n /** Mapping of old defined type names to new defined type names */\n definedTypes?: Record<string, string>;\n}\n\n/**\n * Options for the rename visitor (legacy interface)\n */\nexport type RenameVisitorOptions = ProgramRenameOptions;\n\n/**\n * Creates a visitor that renames instructions in a Codama IDL.\n *\n * @param mapping - Object mapping old instruction names to new instruction names\n * @returns A root node visitor that renames instructions\n *\n * @example\n * ```typescript\n * const visitor = renameInstructionsVisitor({\n * \"transfer\": \"transferTokens\",\n * \"mint\": \"mintNft\"\n * });\n * codama.update(visitor);\n * ```\n */\nexport function renameInstructionsVisitor(\n mapping: Record<string, string>,\n): ReturnType<typeof rootNodeVisitor> {\n return rootNodeVisitor((root) => {\n const instructionVisitor = bottomUpTransformerVisitor([\n {\n select: \"[instructionNode]\",\n transform: (node) => {\n assertIsNode(node, \"instructionNode\");\n const newName = mapping[node.name];\n if (!newName) {\n return node;\n }\n return {\n ...node,\n name: camelCase(newName),\n } as InstructionNode;\n },\n },\n ]);\n return visit(root, instructionVisitor);\n });\n}\n\n/**\n * Creates a visitor that renames events (as defined types) in a Codama IDL.\n *\n * Events in Anchor IDLs are typically converted to defined types in Codama,\n * so this visitor renames specific defined types that represent events.\n *\n * @param mapping - Object mapping old event names to new event names\n * @param eventSuffix - Optional suffix to identify event types (default: \"Event\")\n * @returns A root node visitor that renames events\n *\n * @example\n * ```typescript\n * const visitor = renameEventsVisitor({\n * \"tokenMinted\": \"nftMinted\",\n * \"transferComplete\": \"transferFinished\"\n * });\n * codama.update(visitor);\n * ```\n */\nexport function renameEventsVisitor(\n mapping: Record<string, string>,\n eventSuffix = \"Event\",\n): ReturnType<typeof rootNodeVisitor> {\n return rootNodeVisitor((root) => {\n const eventVisitor = bottomUpTransformerVisitor([\n {\n select: \"[definedTypeNode]\",\n transform: (node) => {\n assertIsNode(node, \"definedTypeNode\");\n\n // Check if this is an event type (by suffix or by being in the mapping)\n const isEventBySuffix = node.name.endsWith(eventSuffix);\n const isEventInMapping = mapping[node.name] !== undefined;\n\n if (!(isEventBySuffix || isEventInMapping)) {\n return node;\n }\n\n const newName = mapping[node.name];\n if (!newName) {\n return node;\n }\n\n return {\n ...node,\n name: camelCase(newName),\n } as DefinedTypeNode;\n },\n },\n ]);\n return visit(root, eventVisitor);\n });\n}\n\n/**\n * Creates a visitor that renames defined types in a Codama IDL.\n *\n * @param mapping - Object mapping old defined type names to new defined type names\n * @returns A root node visitor that renames defined types\n *\n * @example\n * ```typescript\n * const visitor = renameDefinedTypesVisitor({\n * \"counter\": \"counterAccount\",\n * \"config\": \"programConfig\"\n * });\n * codama.update(visitor);\n * ```\n */\nexport function renameDefinedTypesVisitor(\n mapping: Record<string, string>,\n): ReturnType<typeof rootNodeVisitor> {\n return rootNodeVisitor((root) => {\n const typeVisitor = bottomUpTransformerVisitor([\n {\n select: \"[definedTypeNode]\",\n transform: (node) => {\n assertIsNode(node, \"definedTypeNode\");\n const newName = mapping[node.name];\n if (!newName) {\n return node;\n }\n return {\n ...node,\n name: camelCase(newName),\n } as DefinedTypeNode;\n },\n },\n ]);\n return visit(root, typeVisitor);\n });\n}\n\n/**\n * Creates a visitor that renames instructions, events, and defined types in specific programs.\n * This follows the same pattern as addPdasVisitor from Codama.\n *\n * @param renamesByProgram - Object mapping program names to their rename configurations\n * @returns A root node visitor that performs all specified renames\n *\n * @example\n * ```typescript\n * const visitor = renameVisitor({\n * quarryMine: {\n * instructions: {\n * claimRewards: \"claimRewardsMine\"\n * }\n * },\n * token: {\n * instructions: {\n * transfer: \"transferTokens\",\n * mint: \"mintNft\"\n * },\n * events: {\n * tokenMinted: \"nftMinted\"\n * }\n * }\n * });\n * codama.update(visitor);\n * ```\n */\nexport function renameVisitor(\n renamesByProgram: Record<string, ProgramRenameOptions>,\n): ReturnType<typeof rootNodeVisitor> {\n return rootNodeVisitor((root) => {\n // Check if this is the legacy single-program format\n // (has instructions, events, or definedTypes at the top level)\n const isLegacyFormat =\n \"instructions\" in renamesByProgram ||\n \"events\" in renamesByProgram ||\n \"definedTypes\" in renamesByProgram;\n\n if (isLegacyFormat) {\n // Legacy support: treat as single program renames\n const options = renamesByProgram as unknown as RenameVisitorOptions;\n let transformedRoot = root;\n\n // Apply instruction renaming\n if (\n options.instructions &&\n Object.keys(options.instructions).length > 0\n ) {\n transformedRoot = visit(\n transformedRoot,\n renameInstructionsVisitor(options.instructions),\n ) as RootNode;\n }\n\n // Apply event renaming\n if (options.events && Object.keys(options.events).length > 0) {\n transformedRoot = visit(\n transformedRoot,\n renameEventsVisitor(options.events),\n ) as RootNode;\n }\n\n // Apply defined type renaming\n if (\n options.definedTypes &&\n Object.keys(options.definedTypes).length > 0\n ) {\n transformedRoot = visit(\n transformedRoot,\n renameDefinedTypesVisitor(options.definedTypes),\n ) as RootNode;\n }\n\n return transformedRoot;\n }\n\n // New format: program-specific renames\n const transforms: {\n select: string;\n transform: (node: Node) => Node | null;\n }[] = [];\n\n // Process each program's rename configuration\n Object.entries(renamesByProgram).forEach(([programName, renameOptions]) => {\n // Add instruction renames for this program\n if (renameOptions.instructions) {\n Object.entries(renameOptions.instructions).forEach(\n ([oldName, newName]) => {\n transforms.push({\n select: `[programNode]${programName}.[instructionNode]${oldName}`,\n transform: (node) => {\n assertIsNode(node, \"instructionNode\");\n return {\n ...node,\n name: camelCase(newName),\n } as InstructionNode;\n },\n });\n },\n );\n }\n\n // Add event/defined type renames for this program\n if (renameOptions.events || renameOptions.definedTypes) {\n const allTypeRenames = {\n ...(renameOptions.events ?? {}),\n ...(renameOptions.definedTypes ?? {}),\n };\n\n Object.entries(allTypeRenames).forEach(([oldName, newName]) => {\n transforms.push({\n select: `[programNode]${programName}.[definedTypeNode]${oldName}`,\n transform: (node) => {\n assertIsNode(node, \"definedTypeNode\");\n return {\n ...node,\n name: camelCase(newName),\n } as DefinedTypeNode;\n },\n });\n });\n }\n });\n\n if (transforms.length === 0) {\n return root;\n }\n\n const visitor = bottomUpTransformerVisitor(transforms);\n return visit(root, visitor);\n });\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@macalinao/codama-rename-visitor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Codama visitor for renaming instructions and events within a program",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"author": "Ian Macalinao <me@ianm.com>",
|
|
8
|
+
"homepage": "https://github.com/macalinao/coda",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"codama",
|
|
12
|
+
"solana",
|
|
13
|
+
"anchor",
|
|
14
|
+
"idl",
|
|
15
|
+
"rename",
|
|
16
|
+
"visitor",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist/",
|
|
29
|
+
"src/"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/macalinao/coda.git",
|
|
37
|
+
"directory": "packages/codama-rename-visitor"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"clean": "rm -fr dist/",
|
|
42
|
+
"lint": "eslint . --cache",
|
|
43
|
+
"test": "bun test"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"codama": "*"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@macalinao/eslint-config": "^5",
|
|
50
|
+
"@macalinao/tsconfig": "^3.2.3",
|
|
51
|
+
"eslint": "^9.33.0",
|
|
52
|
+
"typescript": "^5.9.2"
|
|
53
|
+
},
|
|
54
|
+
"lint-staged": {
|
|
55
|
+
"*.{js,jsx,ts,tsx,cjs,mjs,cts,mts}": [
|
|
56
|
+
"biome check --write --no-errors-on-unmatched",
|
|
57
|
+
"eslint --fix --cache"
|
|
58
|
+
],
|
|
59
|
+
"*.{json,jsonc,html}": "biome format --write --no-errors-on-unmatched"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,409 @@
|
|
|
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
|
+
instructionAccountNode,
|
|
8
|
+
instructionNode,
|
|
9
|
+
numberTypeNode,
|
|
10
|
+
programNode,
|
|
11
|
+
publicKeyTypeNode,
|
|
12
|
+
rootNode,
|
|
13
|
+
visit,
|
|
14
|
+
} from "codama";
|
|
15
|
+
import {
|
|
16
|
+
renameDefinedTypesVisitor,
|
|
17
|
+
renameEventsVisitor,
|
|
18
|
+
renameInstructionsVisitor,
|
|
19
|
+
renameVisitor,
|
|
20
|
+
} from "./index.js";
|
|
21
|
+
|
|
22
|
+
describe("renameInstructionsVisitor", () => {
|
|
23
|
+
it("should rename instructions based on the mapping", () => {
|
|
24
|
+
const program: ProgramNode = programNode({
|
|
25
|
+
name: camelCase("testProgram"),
|
|
26
|
+
publicKey: "11111111111111111111111111111111",
|
|
27
|
+
instructions: [
|
|
28
|
+
instructionNode({
|
|
29
|
+
name: camelCase("transfer"),
|
|
30
|
+
accounts: [
|
|
31
|
+
instructionAccountNode({
|
|
32
|
+
name: camelCase("source"),
|
|
33
|
+
isWritable: true,
|
|
34
|
+
isSigner: false,
|
|
35
|
+
}),
|
|
36
|
+
instructionAccountNode({
|
|
37
|
+
name: camelCase("destination"),
|
|
38
|
+
isWritable: true,
|
|
39
|
+
isSigner: false,
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
}),
|
|
43
|
+
instructionNode({
|
|
44
|
+
name: camelCase("mint"),
|
|
45
|
+
accounts: [
|
|
46
|
+
instructionAccountNode({
|
|
47
|
+
name: camelCase("mint"),
|
|
48
|
+
isWritable: true,
|
|
49
|
+
isSigner: false,
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const root = rootNode(program);
|
|
57
|
+
const visitor = renameInstructionsVisitor({
|
|
58
|
+
transfer: "transferTokens",
|
|
59
|
+
mint: "mintNft",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
63
|
+
const instructions = updatedRoot.program.instructions;
|
|
64
|
+
|
|
65
|
+
expect(instructions[0].name.toString()).toBe("transferTokens");
|
|
66
|
+
expect(instructions[1].name.toString()).toBe("mintNft");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should leave unmapped instructions unchanged", () => {
|
|
70
|
+
const program: ProgramNode = programNode({
|
|
71
|
+
name: camelCase("testProgram"),
|
|
72
|
+
publicKey: "11111111111111111111111111111111",
|
|
73
|
+
instructions: [
|
|
74
|
+
instructionNode({
|
|
75
|
+
name: camelCase("burn"),
|
|
76
|
+
accounts: [],
|
|
77
|
+
}),
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const root = rootNode(program);
|
|
82
|
+
const visitor = renameInstructionsVisitor({
|
|
83
|
+
transfer: "transferTokens",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
87
|
+
const instructions = updatedRoot.program.instructions;
|
|
88
|
+
|
|
89
|
+
expect(instructions[0].name.toString()).toBe("burn");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("renameDefinedTypesVisitor", () => {
|
|
94
|
+
it("should rename defined types based on the mapping", () => {
|
|
95
|
+
const program: ProgramNode = programNode({
|
|
96
|
+
name: camelCase("testProgram"),
|
|
97
|
+
publicKey: "11111111111111111111111111111111",
|
|
98
|
+
definedTypes: [
|
|
99
|
+
definedTypeNode({
|
|
100
|
+
name: camelCase("counter"),
|
|
101
|
+
type: numberTypeNode("u64"),
|
|
102
|
+
}),
|
|
103
|
+
definedTypeNode({
|
|
104
|
+
name: camelCase("config"),
|
|
105
|
+
type: publicKeyTypeNode(),
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const root = rootNode(program);
|
|
111
|
+
const visitor = renameDefinedTypesVisitor({
|
|
112
|
+
counter: "counterAccount",
|
|
113
|
+
config: "programConfig",
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
117
|
+
const types = updatedRoot.program.definedTypes;
|
|
118
|
+
|
|
119
|
+
expect(types[0].name.toString()).toBe("counterAccount");
|
|
120
|
+
expect(types[1].name.toString()).toBe("programConfig");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe("renameEventsVisitor", () => {
|
|
125
|
+
it("should rename events (as defined types with Event suffix)", () => {
|
|
126
|
+
const program: ProgramNode = programNode({
|
|
127
|
+
name: camelCase("testProgram"),
|
|
128
|
+
publicKey: "11111111111111111111111111111111",
|
|
129
|
+
definedTypes: [
|
|
130
|
+
definedTypeNode({
|
|
131
|
+
name: camelCase("tokenMintedEvent"),
|
|
132
|
+
type: numberTypeNode("u64"),
|
|
133
|
+
}),
|
|
134
|
+
definedTypeNode({
|
|
135
|
+
name: camelCase("transferCompleteEvent"),
|
|
136
|
+
type: publicKeyTypeNode(),
|
|
137
|
+
}),
|
|
138
|
+
definedTypeNode({
|
|
139
|
+
name: camelCase("regularType"),
|
|
140
|
+
type: numberTypeNode("u32"),
|
|
141
|
+
}),
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const root = rootNode(program);
|
|
146
|
+
const visitor = renameEventsVisitor({
|
|
147
|
+
tokenMintedEvent: "nftMintedEvent",
|
|
148
|
+
transferCompleteEvent: "transferFinishedEvent",
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
152
|
+
const types = updatedRoot.program.definedTypes;
|
|
153
|
+
|
|
154
|
+
expect(types[0].name.toString()).toBe("nftMintedEvent");
|
|
155
|
+
expect(types[1].name.toString()).toBe("transferFinishedEvent");
|
|
156
|
+
expect(types[2].name.toString()).toBe("regularType"); // Should remain unchanged
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should rename events without suffix if explicitly in mapping", () => {
|
|
160
|
+
const program: ProgramNode = programNode({
|
|
161
|
+
name: camelCase("testProgram"),
|
|
162
|
+
publicKey: "11111111111111111111111111111111",
|
|
163
|
+
definedTypes: [
|
|
164
|
+
definedTypeNode({
|
|
165
|
+
name: camelCase("tokenMinted"),
|
|
166
|
+
type: numberTypeNode("u64"),
|
|
167
|
+
}),
|
|
168
|
+
],
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const root = rootNode(program);
|
|
172
|
+
const visitor = renameEventsVisitor({
|
|
173
|
+
tokenMinted: "nftMinted",
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
177
|
+
const types = updatedRoot.program.definedTypes;
|
|
178
|
+
|
|
179
|
+
expect(types[0].name.toString()).toBe("nftMinted");
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe("renameVisitor (legacy format)", () => {
|
|
184
|
+
it("should rename both instructions and events", () => {
|
|
185
|
+
const program: ProgramNode = programNode({
|
|
186
|
+
name: camelCase("testProgram"),
|
|
187
|
+
publicKey: "11111111111111111111111111111111",
|
|
188
|
+
instructions: [
|
|
189
|
+
instructionNode({
|
|
190
|
+
name: camelCase("transfer"),
|
|
191
|
+
accounts: [],
|
|
192
|
+
}),
|
|
193
|
+
],
|
|
194
|
+
definedTypes: [
|
|
195
|
+
definedTypeNode({
|
|
196
|
+
name: camelCase("tokenMintedEvent"),
|
|
197
|
+
type: numberTypeNode("u64"),
|
|
198
|
+
}),
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const root = rootNode(program);
|
|
203
|
+
const visitor = renameVisitor({
|
|
204
|
+
instructions: {
|
|
205
|
+
transfer: "transferTokens",
|
|
206
|
+
},
|
|
207
|
+
events: {
|
|
208
|
+
tokenMintedEvent: "nftMintedEvent",
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
213
|
+
const instructions = updatedRoot.program.instructions;
|
|
214
|
+
const types = updatedRoot.program.definedTypes;
|
|
215
|
+
|
|
216
|
+
expect(instructions[0].name.toString()).toBe("transferTokens");
|
|
217
|
+
expect(types[0].name.toString()).toBe("nftMintedEvent");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("should handle empty options gracefully", () => {
|
|
221
|
+
const program: ProgramNode = programNode({
|
|
222
|
+
name: camelCase("testProgram"),
|
|
223
|
+
publicKey: "11111111111111111111111111111111",
|
|
224
|
+
instructions: [
|
|
225
|
+
instructionNode({
|
|
226
|
+
name: camelCase("transfer"),
|
|
227
|
+
accounts: [],
|
|
228
|
+
}),
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const root = rootNode(program);
|
|
233
|
+
const visitor = renameVisitor({});
|
|
234
|
+
|
|
235
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
236
|
+
const instructions = updatedRoot.program.instructions;
|
|
237
|
+
|
|
238
|
+
expect(instructions[0].name.toString()).toBe("transfer");
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("renameVisitor (program-specific format)", () => {
|
|
243
|
+
it("should rename instructions in specific programs", () => {
|
|
244
|
+
const quarryMineProgram: ProgramNode = programNode({
|
|
245
|
+
name: camelCase("quarryMine"),
|
|
246
|
+
publicKey: "11111111111111111111111111111111",
|
|
247
|
+
instructions: [
|
|
248
|
+
instructionNode({
|
|
249
|
+
name: camelCase("claimRewards"),
|
|
250
|
+
accounts: [],
|
|
251
|
+
}),
|
|
252
|
+
instructionNode({
|
|
253
|
+
name: camelCase("stake"),
|
|
254
|
+
accounts: [],
|
|
255
|
+
}),
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const tokenProgram: ProgramNode = programNode({
|
|
260
|
+
name: camelCase("token"),
|
|
261
|
+
publicKey: "22222222222222222222222222222222",
|
|
262
|
+
instructions: [
|
|
263
|
+
instructionNode({
|
|
264
|
+
name: camelCase("transfer"),
|
|
265
|
+
accounts: [],
|
|
266
|
+
}),
|
|
267
|
+
instructionNode({
|
|
268
|
+
name: camelCase("mint"),
|
|
269
|
+
accounts: [],
|
|
270
|
+
}),
|
|
271
|
+
],
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Create a root with multiple programs
|
|
275
|
+
const root = rootNode(quarryMineProgram, [tokenProgram]);
|
|
276
|
+
|
|
277
|
+
const visitor = renameVisitor({
|
|
278
|
+
quarryMine: {
|
|
279
|
+
instructions: {
|
|
280
|
+
claimRewards: "claimRewardsMine",
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
token: {
|
|
284
|
+
instructions: {
|
|
285
|
+
transfer: "transferTokens",
|
|
286
|
+
mint: "mintNft",
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
292
|
+
const quarryInstructions = updatedRoot.program.instructions;
|
|
293
|
+
const tokenInstructions =
|
|
294
|
+
updatedRoot.additionalPrograms?.[0]?.instructions ?? [];
|
|
295
|
+
|
|
296
|
+
expect(quarryInstructions[0].name.toString()).toBe("claimRewardsMine");
|
|
297
|
+
expect(quarryInstructions[1].name.toString()).toBe("stake"); // Unchanged
|
|
298
|
+
expect(tokenInstructions[0].name.toString()).toBe("transferTokens");
|
|
299
|
+
expect(tokenInstructions[1].name.toString()).toBe("mintNft");
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should rename events and defined types in specific programs", () => {
|
|
303
|
+
const program: ProgramNode = programNode({
|
|
304
|
+
name: camelCase("myProgram"),
|
|
305
|
+
publicKey: "11111111111111111111111111111111",
|
|
306
|
+
definedTypes: [
|
|
307
|
+
definedTypeNode({
|
|
308
|
+
name: camelCase("tokenMintedEvent"),
|
|
309
|
+
type: numberTypeNode("u64"),
|
|
310
|
+
}),
|
|
311
|
+
definedTypeNode({
|
|
312
|
+
name: camelCase("counter"),
|
|
313
|
+
type: numberTypeNode("u64"),
|
|
314
|
+
}),
|
|
315
|
+
],
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const root = rootNode(program);
|
|
319
|
+
|
|
320
|
+
const visitor = renameVisitor({
|
|
321
|
+
myProgram: {
|
|
322
|
+
events: {
|
|
323
|
+
tokenMintedEvent: "nftMintedEvent",
|
|
324
|
+
},
|
|
325
|
+
definedTypes: {
|
|
326
|
+
counter: "counterAccount",
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
332
|
+
const types = updatedRoot.program.definedTypes;
|
|
333
|
+
|
|
334
|
+
expect(types[0].name.toString()).toBe("nftMintedEvent");
|
|
335
|
+
expect(types[1].name.toString()).toBe("counterAccount");
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("should work with Quarry-style program names (camelCase)", () => {
|
|
339
|
+
const quarryMergeMineProgram: ProgramNode = programNode({
|
|
340
|
+
name: camelCase("quarryMergeMine"),
|
|
341
|
+
publicKey: "QMMD16kjauP5knBwxNUJRZ1Z5o3deBuFrqVjBVmmqto",
|
|
342
|
+
instructions: [
|
|
343
|
+
instructionNode({
|
|
344
|
+
name: camelCase("claimRewards"),
|
|
345
|
+
accounts: [],
|
|
346
|
+
}),
|
|
347
|
+
instructionNode({
|
|
348
|
+
name: camelCase("stake"),
|
|
349
|
+
accounts: [],
|
|
350
|
+
}),
|
|
351
|
+
],
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const root = rootNode(quarryMergeMineProgram);
|
|
355
|
+
|
|
356
|
+
const visitor = renameVisitor({
|
|
357
|
+
quarryMergeMine: {
|
|
358
|
+
instructions: {
|
|
359
|
+
claimRewards: "claimRewardsMergeMine",
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
365
|
+
const instructions = updatedRoot.program.instructions;
|
|
366
|
+
|
|
367
|
+
expect(instructions[0].name.toString()).toBe("claimRewardsMergeMine");
|
|
368
|
+
expect(instructions[1].name.toString()).toBe("stake"); // Unchanged
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("should handle mixed program configurations", () => {
|
|
372
|
+
const program: ProgramNode = programNode({
|
|
373
|
+
name: camelCase("testProgram"),
|
|
374
|
+
publicKey: "11111111111111111111111111111111",
|
|
375
|
+
instructions: [
|
|
376
|
+
instructionNode({
|
|
377
|
+
name: camelCase("transfer"),
|
|
378
|
+
accounts: [],
|
|
379
|
+
}),
|
|
380
|
+
],
|
|
381
|
+
definedTypes: [
|
|
382
|
+
definedTypeNode({
|
|
383
|
+
name: camelCase("transferEvent"),
|
|
384
|
+
type: numberTypeNode("u64"),
|
|
385
|
+
}),
|
|
386
|
+
],
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const root = rootNode(program);
|
|
390
|
+
|
|
391
|
+
const visitor = renameVisitor({
|
|
392
|
+
testProgram: {
|
|
393
|
+
instructions: {
|
|
394
|
+
transfer: "sendTokens",
|
|
395
|
+
},
|
|
396
|
+
events: {
|
|
397
|
+
transferEvent: "tokenSentEvent",
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const updatedRoot = visit(root, visitor) as RootNode;
|
|
403
|
+
const instructions = updatedRoot.program.instructions;
|
|
404
|
+
const types = updatedRoot.program.definedTypes;
|
|
405
|
+
|
|
406
|
+
expect(instructions[0].name.toString()).toBe("sendTokens");
|
|
407
|
+
expect(types[0].name.toString()).toBe("tokenSentEvent");
|
|
408
|
+
});
|
|
409
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type { DefinedTypeNode, InstructionNode, Node, RootNode } from "codama";
|
|
2
|
+
import {
|
|
3
|
+
assertIsNode,
|
|
4
|
+
bottomUpTransformerVisitor,
|
|
5
|
+
camelCase,
|
|
6
|
+
rootNodeVisitor,
|
|
7
|
+
visit,
|
|
8
|
+
} from "codama";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Rename mapping for a single program
|
|
12
|
+
*/
|
|
13
|
+
export interface ProgramRenameOptions {
|
|
14
|
+
/** Mapping of old instruction names to new instruction names */
|
|
15
|
+
instructions?: Record<string, string>;
|
|
16
|
+
/** Mapping of old event names (as defined types) to new event names */
|
|
17
|
+
events?: Record<string, string>;
|
|
18
|
+
/** Mapping of old defined type names to new defined type names */
|
|
19
|
+
definedTypes?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Options for the rename visitor (legacy interface)
|
|
24
|
+
*/
|
|
25
|
+
export type RenameVisitorOptions = ProgramRenameOptions;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates a visitor that renames instructions in a Codama IDL.
|
|
29
|
+
*
|
|
30
|
+
* @param mapping - Object mapping old instruction names to new instruction names
|
|
31
|
+
* @returns A root node visitor that renames instructions
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const visitor = renameInstructionsVisitor({
|
|
36
|
+
* "transfer": "transferTokens",
|
|
37
|
+
* "mint": "mintNft"
|
|
38
|
+
* });
|
|
39
|
+
* codama.update(visitor);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function renameInstructionsVisitor(
|
|
43
|
+
mapping: Record<string, string>,
|
|
44
|
+
): ReturnType<typeof rootNodeVisitor> {
|
|
45
|
+
return rootNodeVisitor((root) => {
|
|
46
|
+
const instructionVisitor = bottomUpTransformerVisitor([
|
|
47
|
+
{
|
|
48
|
+
select: "[instructionNode]",
|
|
49
|
+
transform: (node) => {
|
|
50
|
+
assertIsNode(node, "instructionNode");
|
|
51
|
+
const newName = mapping[node.name];
|
|
52
|
+
if (!newName) {
|
|
53
|
+
return node;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
...node,
|
|
57
|
+
name: camelCase(newName),
|
|
58
|
+
} as InstructionNode;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
return visit(root, instructionVisitor);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Creates a visitor that renames events (as defined types) in a Codama IDL.
|
|
68
|
+
*
|
|
69
|
+
* Events in Anchor IDLs are typically converted to defined types in Codama,
|
|
70
|
+
* so this visitor renames specific defined types that represent events.
|
|
71
|
+
*
|
|
72
|
+
* @param mapping - Object mapping old event names to new event names
|
|
73
|
+
* @param eventSuffix - Optional suffix to identify event types (default: "Event")
|
|
74
|
+
* @returns A root node visitor that renames events
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const visitor = renameEventsVisitor({
|
|
79
|
+
* "tokenMinted": "nftMinted",
|
|
80
|
+
* "transferComplete": "transferFinished"
|
|
81
|
+
* });
|
|
82
|
+
* codama.update(visitor);
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function renameEventsVisitor(
|
|
86
|
+
mapping: Record<string, string>,
|
|
87
|
+
eventSuffix = "Event",
|
|
88
|
+
): ReturnType<typeof rootNodeVisitor> {
|
|
89
|
+
return rootNodeVisitor((root) => {
|
|
90
|
+
const eventVisitor = bottomUpTransformerVisitor([
|
|
91
|
+
{
|
|
92
|
+
select: "[definedTypeNode]",
|
|
93
|
+
transform: (node) => {
|
|
94
|
+
assertIsNode(node, "definedTypeNode");
|
|
95
|
+
|
|
96
|
+
// Check if this is an event type (by suffix or by being in the mapping)
|
|
97
|
+
const isEventBySuffix = node.name.endsWith(eventSuffix);
|
|
98
|
+
const isEventInMapping = mapping[node.name] !== undefined;
|
|
99
|
+
|
|
100
|
+
if (!(isEventBySuffix || isEventInMapping)) {
|
|
101
|
+
return node;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const newName = mapping[node.name];
|
|
105
|
+
if (!newName) {
|
|
106
|
+
return node;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
...node,
|
|
111
|
+
name: camelCase(newName),
|
|
112
|
+
} as DefinedTypeNode;
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
return visit(root, eventVisitor);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Creates a visitor that renames defined types in a Codama IDL.
|
|
122
|
+
*
|
|
123
|
+
* @param mapping - Object mapping old defined type names to new defined type names
|
|
124
|
+
* @returns A root node visitor that renames defined types
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const visitor = renameDefinedTypesVisitor({
|
|
129
|
+
* "counter": "counterAccount",
|
|
130
|
+
* "config": "programConfig"
|
|
131
|
+
* });
|
|
132
|
+
* codama.update(visitor);
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function renameDefinedTypesVisitor(
|
|
136
|
+
mapping: Record<string, string>,
|
|
137
|
+
): ReturnType<typeof rootNodeVisitor> {
|
|
138
|
+
return rootNodeVisitor((root) => {
|
|
139
|
+
const typeVisitor = bottomUpTransformerVisitor([
|
|
140
|
+
{
|
|
141
|
+
select: "[definedTypeNode]",
|
|
142
|
+
transform: (node) => {
|
|
143
|
+
assertIsNode(node, "definedTypeNode");
|
|
144
|
+
const newName = mapping[node.name];
|
|
145
|
+
if (!newName) {
|
|
146
|
+
return node;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
...node,
|
|
150
|
+
name: camelCase(newName),
|
|
151
|
+
} as DefinedTypeNode;
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
]);
|
|
155
|
+
return visit(root, typeVisitor);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Creates a visitor that renames instructions, events, and defined types in specific programs.
|
|
161
|
+
* This follows the same pattern as addPdasVisitor from Codama.
|
|
162
|
+
*
|
|
163
|
+
* @param renamesByProgram - Object mapping program names to their rename configurations
|
|
164
|
+
* @returns A root node visitor that performs all specified renames
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const visitor = renameVisitor({
|
|
169
|
+
* quarryMine: {
|
|
170
|
+
* instructions: {
|
|
171
|
+
* claimRewards: "claimRewardsMine"
|
|
172
|
+
* }
|
|
173
|
+
* },
|
|
174
|
+
* token: {
|
|
175
|
+
* instructions: {
|
|
176
|
+
* transfer: "transferTokens",
|
|
177
|
+
* mint: "mintNft"
|
|
178
|
+
* },
|
|
179
|
+
* events: {
|
|
180
|
+
* tokenMinted: "nftMinted"
|
|
181
|
+
* }
|
|
182
|
+
* }
|
|
183
|
+
* });
|
|
184
|
+
* codama.update(visitor);
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export function renameVisitor(
|
|
188
|
+
renamesByProgram: Record<string, ProgramRenameOptions>,
|
|
189
|
+
): ReturnType<typeof rootNodeVisitor> {
|
|
190
|
+
return rootNodeVisitor((root) => {
|
|
191
|
+
// Check if this is the legacy single-program format
|
|
192
|
+
// (has instructions, events, or definedTypes at the top level)
|
|
193
|
+
const isLegacyFormat =
|
|
194
|
+
"instructions" in renamesByProgram ||
|
|
195
|
+
"events" in renamesByProgram ||
|
|
196
|
+
"definedTypes" in renamesByProgram;
|
|
197
|
+
|
|
198
|
+
if (isLegacyFormat) {
|
|
199
|
+
// Legacy support: treat as single program renames
|
|
200
|
+
const options = renamesByProgram as unknown as RenameVisitorOptions;
|
|
201
|
+
let transformedRoot = root;
|
|
202
|
+
|
|
203
|
+
// Apply instruction renaming
|
|
204
|
+
if (
|
|
205
|
+
options.instructions &&
|
|
206
|
+
Object.keys(options.instructions).length > 0
|
|
207
|
+
) {
|
|
208
|
+
transformedRoot = visit(
|
|
209
|
+
transformedRoot,
|
|
210
|
+
renameInstructionsVisitor(options.instructions),
|
|
211
|
+
) as RootNode;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Apply event renaming
|
|
215
|
+
if (options.events && Object.keys(options.events).length > 0) {
|
|
216
|
+
transformedRoot = visit(
|
|
217
|
+
transformedRoot,
|
|
218
|
+
renameEventsVisitor(options.events),
|
|
219
|
+
) as RootNode;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Apply defined type renaming
|
|
223
|
+
if (
|
|
224
|
+
options.definedTypes &&
|
|
225
|
+
Object.keys(options.definedTypes).length > 0
|
|
226
|
+
) {
|
|
227
|
+
transformedRoot = visit(
|
|
228
|
+
transformedRoot,
|
|
229
|
+
renameDefinedTypesVisitor(options.definedTypes),
|
|
230
|
+
) as RootNode;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return transformedRoot;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// New format: program-specific renames
|
|
237
|
+
const transforms: {
|
|
238
|
+
select: string;
|
|
239
|
+
transform: (node: Node) => Node | null;
|
|
240
|
+
}[] = [];
|
|
241
|
+
|
|
242
|
+
// Process each program's rename configuration
|
|
243
|
+
Object.entries(renamesByProgram).forEach(([programName, renameOptions]) => {
|
|
244
|
+
// Add instruction renames for this program
|
|
245
|
+
if (renameOptions.instructions) {
|
|
246
|
+
Object.entries(renameOptions.instructions).forEach(
|
|
247
|
+
([oldName, newName]) => {
|
|
248
|
+
transforms.push({
|
|
249
|
+
select: `[programNode]${programName}.[instructionNode]${oldName}`,
|
|
250
|
+
transform: (node) => {
|
|
251
|
+
assertIsNode(node, "instructionNode");
|
|
252
|
+
return {
|
|
253
|
+
...node,
|
|
254
|
+
name: camelCase(newName),
|
|
255
|
+
} as InstructionNode;
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Add event/defined type renames for this program
|
|
263
|
+
if (renameOptions.events || renameOptions.definedTypes) {
|
|
264
|
+
const allTypeRenames = {
|
|
265
|
+
...(renameOptions.events ?? {}),
|
|
266
|
+
...(renameOptions.definedTypes ?? {}),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
Object.entries(allTypeRenames).forEach(([oldName, newName]) => {
|
|
270
|
+
transforms.push({
|
|
271
|
+
select: `[programNode]${programName}.[definedTypeNode]${oldName}`,
|
|
272
|
+
transform: (node) => {
|
|
273
|
+
assertIsNode(node, "definedTypeNode");
|
|
274
|
+
return {
|
|
275
|
+
...node,
|
|
276
|
+
name: camelCase(newName),
|
|
277
|
+
} as DefinedTypeNode;
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (transforms.length === 0) {
|
|
285
|
+
return root;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const visitor = bottomUpTransformerVisitor(transforms);
|
|
289
|
+
return visit(root, visitor);
|
|
290
|
+
});
|
|
291
|
+
}
|