@kamaalio/codemod-kit 0.0.16 → 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 CHANGED
@@ -103,6 +103,72 @@ const edits = findAndReplaceEdits(
103
103
  const result = ast.root().commitEdits(edits);
104
104
  ```
105
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
+
106
172
  ### `Codemod`
107
173
 
108
174
  A codemod is defined by the `Codemod` type:
@@ -1,2 +1,2 @@
1
- export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits } from './utils.js';
1
+ export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits, findAndReplaceConfig, findAndReplaceConfigEdits, } from './utils.js';
2
2
  export type { Codemod, Modifications } from './types.js';
@@ -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,17 @@ 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>;
24
36
  export declare function findAndReplaceEdits(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): Array<Edit>;
25
37
  export declare function findAndReplace(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): string;
26
38
  export declare function commitEditModifications(edits: Array<Edit>, modifications: Modifications): Promise<Modifications>;
package/dist/index.cjs CHANGED
@@ -34,10 +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,
40
- runCodemods: ()=>runCodemods
41
+ runCodemods: ()=>runCodemods,
42
+ findAndReplaceConfig: ()=>findAndReplaceConfig
41
43
  });
42
44
  const external_node_path_namespaceObject = require("node:path");
43
45
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
@@ -129,6 +131,24 @@ async function runCodemod(codemod, transformationPath, options) {
129
131
  }
130
132
  }));
131
133
  }
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
+ }
132
152
  function findAndReplaceEdits(content, rule, transformer) {
133
153
  const nodes = content.root().findAll({
134
154
  rule
@@ -179,12 +199,16 @@ function defaultedHooks(hooks) {
179
199
  }
180
200
  exports.commitEditModifications = __webpack_exports__.commitEditModifications;
181
201
  exports.findAndReplace = __webpack_exports__.findAndReplace;
202
+ exports.findAndReplaceConfig = __webpack_exports__.findAndReplaceConfig;
203
+ exports.findAndReplaceConfigEdits = __webpack_exports__.findAndReplaceConfigEdits;
182
204
  exports.findAndReplaceEdits = __webpack_exports__.findAndReplaceEdits;
183
205
  exports.runCodemod = __webpack_exports__.runCodemod;
184
206
  exports.runCodemods = __webpack_exports__.runCodemods;
185
207
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
186
208
  "commitEditModifications",
187
209
  "findAndReplace",
210
+ "findAndReplaceConfig",
211
+ "findAndReplaceConfigEdits",
188
212
  "findAndReplaceEdits",
189
213
  "runCodemod",
190
214
  "runCodemods"
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits, 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,6 +85,24 @@ async function runCodemod(codemod, transformationPath, options) {
85
85
  }
86
86
  }));
87
87
  }
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
+ }
88
106
  function findAndReplaceEdits(content, rule, transformer) {
89
107
  const nodes = content.root().findAll({
90
108
  rule
@@ -133,4 +151,4 @@ function defaultedHooks(hooks) {
133
151
  preCodemodRun
134
152
  };
135
153
  }
136
- export { commitEditModifications, findAndReplace, findAndReplaceEdits, runCodemod, runCodemods };
154
+ export { commitEditModifications, findAndReplace, findAndReplaceConfig, findAndReplaceConfigEdits, findAndReplaceEdits, runCodemod, runCodemods };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamaalio/codemod-kit",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "author": "Kamaal Farah",
6
6
  "license": "MIT",