@kamaalio/codemod-kit 0.0.15 → 0.0.17
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 +97 -0
- package/dist/codemods/index.d.ts +1 -1
- package/dist/codemods/utils.d.ts +13 -0
- package/dist/index.cjs +36 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,6 +72,103 @@ const result = findAndReplace(
|
|
|
72
72
|
);
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
### `findAndReplaceEdits(content, rule, transformer)`
|
|
76
|
+
|
|
77
|
+
A utility function for finding AST nodes and generating edit operations without committing them.
|
|
78
|
+
|
|
79
|
+
- `content`: An `SgRoot<TypesMap>` object representing the parsed AST.
|
|
80
|
+
- `rule`: A `Rule<TypesMap>` object defining the pattern to search for.
|
|
81
|
+
- `transformer`: A function that takes a matched node and returns an optional string replacement.
|
|
82
|
+
|
|
83
|
+
Returns an array of `Edit` objects that can be committed later using `commitEdits()`.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { findAndReplaceEdits } from '@kamaalio/codemod-kit';
|
|
87
|
+
import { parseAsync } from '@ast-grep/napi';
|
|
88
|
+
|
|
89
|
+
const code = `
|
|
90
|
+
function oldFunction() {
|
|
91
|
+
return "hello";
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const ast = await parseAsync('javascript', code);
|
|
96
|
+
const edits = findAndReplaceEdits(
|
|
97
|
+
ast,
|
|
98
|
+
{ pattern: 'function oldFunction() { $$$ }' },
|
|
99
|
+
node => 'function newFunction() { return "hello world"; }',
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Commit the edits later
|
|
103
|
+
const result = ast.root().commitEdits(edits);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `findAndReplaceConfig(content, lang, config)`
|
|
107
|
+
|
|
108
|
+
A utility function for applying multiple find-and-replace operations sequentially on AST content.
|
|
109
|
+
|
|
110
|
+
- `content`: An `SgRoot<TypesMap>` object representing the parsed AST.
|
|
111
|
+
- `lang`: A `NapiLang` value specifying the language for re-parsing after each transformation.
|
|
112
|
+
- `config`: An array of objects containing `rule` and `transformer` pairs to apply sequentially.
|
|
113
|
+
|
|
114
|
+
Returns the final transformed content as a string after applying all transformations.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { findAndReplaceConfig } from '@kamaalio/codemod-kit';
|
|
118
|
+
import { parseAsync } from '@ast-grep/napi';
|
|
119
|
+
|
|
120
|
+
const code = `
|
|
121
|
+
function oldFunction() {
|
|
122
|
+
return "hello";
|
|
123
|
+
}
|
|
124
|
+
const value = 42;
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const ast = await parseAsync('javascript', code);
|
|
128
|
+
const result = await findAndReplaceConfig(ast, 'javascript', [
|
|
129
|
+
{
|
|
130
|
+
rule: { pattern: 'function oldFunction() { $$$ }' },
|
|
131
|
+
transformer: node => 'function newFunction() { return "hello world"; }',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
rule: { pattern: 'const value = $VAL' },
|
|
135
|
+
transformer: node => 'const value = 100',
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `findAndReplaceConfigEdits(content, lang, config)`
|
|
141
|
+
|
|
142
|
+
A utility function for applying multiple find-and-replace operations sequentially and returning the edit history.
|
|
143
|
+
|
|
144
|
+
- `content`: An `SgRoot<TypesMap>` object representing the parsed AST.
|
|
145
|
+
- `lang`: A `NapiLang` value specifying the language for re-parsing after each transformation.
|
|
146
|
+
- `config`: An array of objects containing `rule` and `transformer` pairs to apply sequentially.
|
|
147
|
+
|
|
148
|
+
Returns an array of objects containing the AST content and edits for each transformation step.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { findAndReplaceConfigEdits } from '@kamaalio/codemod-kit';
|
|
152
|
+
import { parseAsync } from '@ast-grep/napi';
|
|
153
|
+
|
|
154
|
+
const code = `
|
|
155
|
+
function oldFunction() {
|
|
156
|
+
return "hello";
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
const ast = await parseAsync('javascript', code);
|
|
161
|
+
const editsHistory = await findAndReplaceConfigEdits(ast, 'javascript', [
|
|
162
|
+
{
|
|
163
|
+
rule: { pattern: 'function oldFunction() { $$$ }' },
|
|
164
|
+
transformer: node => 'function newFunction() { return "hello world"; }',
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
// Each element contains { content: SgRoot, edits: Edit[] }
|
|
169
|
+
// Useful for tracking transformation history or debugging
|
|
170
|
+
```
|
|
171
|
+
|
|
75
172
|
### `Codemod`
|
|
76
173
|
|
|
77
174
|
A codemod is defined by the `Codemod` type:
|
package/dist/codemods/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { runCodemods, runCodemod, commitEditModifications, findAndReplace } from './utils.js';
|
|
1
|
+
export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits, findAndReplaceConfig, findAndReplaceConfigEdits, } from './utils.js';
|
|
2
2
|
export type { Codemod, Modifications } from './types.js';
|
package/dist/codemods/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Result } from 'neverthrow';
|
|
2
2
|
import { type Rule, type Edit, type SgNode, type SgRoot } from '@ast-grep/napi';
|
|
3
3
|
import type { Kinds, TypesMap } from '@ast-grep/napi/types/staticTypes.js';
|
|
4
|
+
import type { NapiLang } from '@ast-grep/napi/types/lang.js';
|
|
4
5
|
import type { Codemod, Modifications } from './types.js';
|
|
5
6
|
import type { Optional } from '../utils/type-utils.js';
|
|
6
7
|
type RunCodemodHooks<C extends Codemod> = {
|
|
@@ -21,6 +22,18 @@ export declare function runCodemod<C extends Codemod>(codemod: C, transformation
|
|
|
21
22
|
hasChanges: boolean;
|
|
22
23
|
content: string;
|
|
23
24
|
}, Error>>>;
|
|
25
|
+
export declare function findAndReplaceConfigEdits(content: SgRoot<TypesMap>, lang: NapiLang, config: Array<{
|
|
26
|
+
rule: Rule<TypesMap>;
|
|
27
|
+
transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>;
|
|
28
|
+
}>): Promise<Array<{
|
|
29
|
+
content: SgRoot<TypesMap>;
|
|
30
|
+
edits: Array<Edit>;
|
|
31
|
+
}>>;
|
|
32
|
+
export declare function findAndReplaceConfig(content: SgRoot<TypesMap>, lang: NapiLang, config: Array<{
|
|
33
|
+
rule: Rule<TypesMap>;
|
|
34
|
+
transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>;
|
|
35
|
+
}>): Promise<string>;
|
|
36
|
+
export declare function findAndReplaceEdits(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): Array<Edit>;
|
|
24
37
|
export declare function findAndReplace(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): string;
|
|
25
38
|
export declare function commitEditModifications(edits: Array<Edit>, modifications: Modifications): Promise<Modifications>;
|
|
26
39
|
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -34,9 +34,12 @@ var __webpack_exports__ = {};
|
|
|
34
34
|
__webpack_require__.r(__webpack_exports__);
|
|
35
35
|
__webpack_require__.d(__webpack_exports__, {
|
|
36
36
|
commitEditModifications: ()=>commitEditModifications,
|
|
37
|
+
findAndReplaceConfigEdits: ()=>findAndReplaceConfigEdits,
|
|
37
38
|
runCodemod: ()=>runCodemod,
|
|
38
39
|
findAndReplace: ()=>findAndReplace,
|
|
39
|
-
|
|
40
|
+
findAndReplaceEdits: ()=>findAndReplaceEdits,
|
|
41
|
+
runCodemods: ()=>runCodemods,
|
|
42
|
+
findAndReplaceConfig: ()=>findAndReplaceConfig
|
|
40
43
|
});
|
|
41
44
|
const external_node_path_namespaceObject = require("node:path");
|
|
42
45
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
@@ -128,15 +131,37 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
128
131
|
}
|
|
129
132
|
}));
|
|
130
133
|
}
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
+
async function findAndReplaceConfigEdits(content, lang, config) {
|
|
135
|
+
let currentContent = content;
|
|
136
|
+
const editsAndContent = [];
|
|
137
|
+
for (const { rule, transformer } of config){
|
|
138
|
+
const edits = findAndReplaceEdits(currentContent, rule, transformer);
|
|
139
|
+
const updatedContent = currentContent.root().commitEdits(edits);
|
|
140
|
+
editsAndContent.push({
|
|
141
|
+
content: currentContent,
|
|
142
|
+
edits
|
|
143
|
+
});
|
|
144
|
+
currentContent = await (0, napi_namespaceObject.parseAsync)(lang, updatedContent);
|
|
145
|
+
}
|
|
146
|
+
return editsAndContent;
|
|
147
|
+
}
|
|
148
|
+
async function findAndReplaceConfig(content, lang, config) {
|
|
149
|
+
const edits = await findAndReplaceConfigEdits(content, lang, config);
|
|
150
|
+
return edits.at(-1)?.content.root().text() ?? content.root().text();
|
|
151
|
+
}
|
|
152
|
+
function findAndReplaceEdits(content, rule, transformer) {
|
|
153
|
+
const nodes = content.root().findAll({
|
|
134
154
|
rule
|
|
135
|
-
})
|
|
155
|
+
});
|
|
156
|
+
return kamaal_namespaceObject.arrays.compactMap(nodes, (node)=>{
|
|
136
157
|
const transformed = transformer(node);
|
|
137
158
|
if (null == transformed) return null;
|
|
138
159
|
return node.replace(transformed);
|
|
139
160
|
});
|
|
161
|
+
}
|
|
162
|
+
function findAndReplace(content, rule, transformer) {
|
|
163
|
+
const root = content.root();
|
|
164
|
+
const edits = findAndReplaceEdits(content, rule, transformer);
|
|
140
165
|
return root.commitEdits(edits);
|
|
141
166
|
}
|
|
142
167
|
async function commitEditModifications(edits, modifications) {
|
|
@@ -174,11 +199,17 @@ function defaultedHooks(hooks) {
|
|
|
174
199
|
}
|
|
175
200
|
exports.commitEditModifications = __webpack_exports__.commitEditModifications;
|
|
176
201
|
exports.findAndReplace = __webpack_exports__.findAndReplace;
|
|
202
|
+
exports.findAndReplaceConfig = __webpack_exports__.findAndReplaceConfig;
|
|
203
|
+
exports.findAndReplaceConfigEdits = __webpack_exports__.findAndReplaceConfigEdits;
|
|
204
|
+
exports.findAndReplaceEdits = __webpack_exports__.findAndReplaceEdits;
|
|
177
205
|
exports.runCodemod = __webpack_exports__.runCodemod;
|
|
178
206
|
exports.runCodemods = __webpack_exports__.runCodemods;
|
|
179
207
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
180
208
|
"commitEditModifications",
|
|
181
209
|
"findAndReplace",
|
|
210
|
+
"findAndReplaceConfig",
|
|
211
|
+
"findAndReplaceConfigEdits",
|
|
212
|
+
"findAndReplaceEdits",
|
|
182
213
|
"runCodemod",
|
|
183
214
|
"runCodemods"
|
|
184
215
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { runCodemods, runCodemod, commitEditModifications, findAndReplace, type Codemod, type Modifications, } from './codemods/index.js';
|
|
1
|
+
export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits, findAndReplaceConfig, findAndReplaceConfigEdits, type Codemod, type Modifications, } from './codemods/index.js';
|
package/dist/index.js
CHANGED
|
@@ -85,15 +85,37 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
85
85
|
}
|
|
86
86
|
}));
|
|
87
87
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
const
|
|
88
|
+
async function findAndReplaceConfigEdits(content, lang, config) {
|
|
89
|
+
let currentContent = content;
|
|
90
|
+
const editsAndContent = [];
|
|
91
|
+
for (const { rule, transformer } of config){
|
|
92
|
+
const edits = findAndReplaceEdits(currentContent, rule, transformer);
|
|
93
|
+
const updatedContent = currentContent.root().commitEdits(edits);
|
|
94
|
+
editsAndContent.push({
|
|
95
|
+
content: currentContent,
|
|
96
|
+
edits
|
|
97
|
+
});
|
|
98
|
+
currentContent = await parseAsync(lang, updatedContent);
|
|
99
|
+
}
|
|
100
|
+
return editsAndContent;
|
|
101
|
+
}
|
|
102
|
+
async function findAndReplaceConfig(content, lang, config) {
|
|
103
|
+
const edits = await findAndReplaceConfigEdits(content, lang, config);
|
|
104
|
+
return edits.at(-1)?.content.root().text() ?? content.root().text();
|
|
105
|
+
}
|
|
106
|
+
function findAndReplaceEdits(content, rule, transformer) {
|
|
107
|
+
const nodes = content.root().findAll({
|
|
91
108
|
rule
|
|
92
|
-
})
|
|
109
|
+
});
|
|
110
|
+
return arrays.compactMap(nodes, (node)=>{
|
|
93
111
|
const transformed = transformer(node);
|
|
94
112
|
if (null == transformed) return null;
|
|
95
113
|
return node.replace(transformed);
|
|
96
114
|
});
|
|
115
|
+
}
|
|
116
|
+
function findAndReplace(content, rule, transformer) {
|
|
117
|
+
const root = content.root();
|
|
118
|
+
const edits = findAndReplaceEdits(content, rule, transformer);
|
|
97
119
|
return root.commitEdits(edits);
|
|
98
120
|
}
|
|
99
121
|
async function commitEditModifications(edits, modifications) {
|
|
@@ -129,4 +151,4 @@ function defaultedHooks(hooks) {
|
|
|
129
151
|
preCodemodRun
|
|
130
152
|
};
|
|
131
153
|
}
|
|
132
|
-
export { commitEditModifications, findAndReplace, runCodemod, runCodemods };
|
|
154
|
+
export { commitEditModifications, findAndReplace, findAndReplaceConfig, findAndReplaceConfigEdits, findAndReplaceEdits, runCodemod, runCodemods };
|