@kamaalio/codemod-kit 0.0.14 → 0.0.16

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
@@ -44,6 +44,65 @@ Runs a single codemod.
44
44
  - `globItems`: An array of file paths to transform.
45
45
  - `options`: Optional configuration for the run.
46
46
 
47
+ ### `findAndReplace(content, rule, transformer)`
48
+
49
+ A utility function for finding and replacing AST nodes based on a rule.
50
+
51
+ - `content`: An `SgRoot<TypesMap>` object representing the parsed AST.
52
+ - `rule`: A `Rule<TypesMap>` object defining the pattern to search for.
53
+ - `transformer`: A function that takes a matched node and returns an optional string replacement.
54
+
55
+ Returns the transformed content as a string with all matching nodes replaced.
56
+
57
+ ```typescript
58
+ import { findAndReplace } from '@kamaalio/codemod-kit';
59
+ import { parseAsync } from '@ast-grep/napi';
60
+
61
+ const code = `
62
+ function oldFunction() {
63
+ return "hello";
64
+ }
65
+ `;
66
+
67
+ const ast = await parseAsync('javascript', code);
68
+ const result = findAndReplace(
69
+ ast,
70
+ { pattern: 'function oldFunction() { $$$ }' },
71
+ node => 'function newFunction() { return "hello world"; }',
72
+ );
73
+ ```
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
+
47
106
  ### `Codemod`
48
107
 
49
108
  A codemod is defined by the `Codemod` type:
@@ -1,2 +1,2 @@
1
- export { runCodemods, runCodemod, commitEditModifications } from './utils.js';
1
+ export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits } from './utils.js';
2
2
  export type { Codemod, Modifications } from './types.js';
@@ -1,6 +1,8 @@
1
1
  import { type Result } from 'neverthrow';
2
- import { type Edit } from '@ast-grep/napi';
2
+ import { type Rule, type Edit, type SgNode, type SgRoot } from '@ast-grep/napi';
3
+ import type { Kinds, TypesMap } from '@ast-grep/napi/types/staticTypes.js';
3
4
  import type { Codemod, Modifications } from './types.js';
5
+ import type { Optional } from '../utils/type-utils.js';
4
6
  type RunCodemodHooks<C extends Codemod> = {
5
7
  targetFiltering?: (filepath: string, codemod: C) => boolean;
6
8
  preCodemodRun?: (codemod: C) => Promise<void>;
@@ -19,5 +21,7 @@ export declare function runCodemod<C extends Codemod>(codemod: C, transformation
19
21
  hasChanges: boolean;
20
22
  content: string;
21
23
  }, Error>>>;
24
+ export declare function findAndReplaceEdits(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): Array<Edit>;
25
+ export declare function findAndReplace(content: SgRoot<TypesMap>, rule: Rule<TypesMap>, transformer: (node: SgNode<TypesMap, Kinds<TypesMap>>) => Optional<string>): string;
22
26
  export declare function commitEditModifications(edits: Array<Edit>, modifications: Modifications): Promise<Modifications>;
23
27
  export {};
package/dist/index.cjs CHANGED
@@ -35,6 +35,8 @@ __webpack_require__.r(__webpack_exports__);
35
35
  __webpack_require__.d(__webpack_exports__, {
36
36
  commitEditModifications: ()=>commitEditModifications,
37
37
  runCodemod: ()=>runCodemod,
38
+ findAndReplace: ()=>findAndReplace,
39
+ findAndReplaceEdits: ()=>findAndReplaceEdits,
38
40
  runCodemods: ()=>runCodemods
39
41
  });
40
42
  const external_node_path_namespaceObject = require("node:path");
@@ -45,6 +47,7 @@ const external_fast_glob_namespaceObject = require("fast-glob");
45
47
  var external_fast_glob_default = /*#__PURE__*/ __webpack_require__.n(external_fast_glob_namespaceObject);
46
48
  const external_neverthrow_namespaceObject = require("neverthrow");
47
49
  const napi_namespaceObject = require("@ast-grep/napi");
50
+ const kamaal_namespaceObject = require("@kamaalio/kamaal");
48
51
  const JAVASCRIPT_EXTENSIONS = [
49
52
  '.js',
50
53
  '.cjs',
@@ -126,6 +129,21 @@ async function runCodemod(codemod, transformationPath, options) {
126
129
  }
127
130
  }));
128
131
  }
132
+ function findAndReplaceEdits(content, rule, transformer) {
133
+ const nodes = content.root().findAll({
134
+ rule
135
+ });
136
+ return kamaal_namespaceObject.arrays.compactMap(nodes, (node)=>{
137
+ const transformed = transformer(node);
138
+ if (null == transformed) return null;
139
+ return node.replace(transformed);
140
+ });
141
+ }
142
+ function findAndReplace(content, rule, transformer) {
143
+ const root = content.root();
144
+ const edits = findAndReplaceEdits(content, rule, transformer);
145
+ return root.commitEdits(edits);
146
+ }
129
147
  async function commitEditModifications(edits, modifications) {
130
148
  if (0 === edits.length) return modifications;
131
149
  const root = modifications.ast.root();
@@ -160,10 +178,14 @@ function defaultedHooks(hooks) {
160
178
  };
161
179
  }
162
180
  exports.commitEditModifications = __webpack_exports__.commitEditModifications;
181
+ exports.findAndReplace = __webpack_exports__.findAndReplace;
182
+ exports.findAndReplaceEdits = __webpack_exports__.findAndReplaceEdits;
163
183
  exports.runCodemod = __webpack_exports__.runCodemod;
164
184
  exports.runCodemods = __webpack_exports__.runCodemods;
165
185
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
166
186
  "commitEditModifications",
187
+ "findAndReplace",
188
+ "findAndReplaceEdits",
167
189
  "runCodemod",
168
190
  "runCodemods"
169
191
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { runCodemods, runCodemod, commitEditModifications, type Codemod, type Modifications, } from './codemods/index.js';
1
+ export { runCodemods, runCodemod, commitEditModifications, findAndReplace, findAndReplaceEdits, type Codemod, type Modifications, } from './codemods/index.js';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import promises from "node:fs/promises";
3
3
  import fast_glob from "fast-glob";
4
4
  import { err, ok } from "neverthrow";
5
5
  import { Lang, parseAsync } from "@ast-grep/napi";
6
+ import { arrays } from "@kamaalio/kamaal";
6
7
  const JAVASCRIPT_EXTENSIONS = [
7
8
  '.js',
8
9
  '.cjs',
@@ -84,6 +85,21 @@ async function runCodemod(codemod, transformationPath, options) {
84
85
  }
85
86
  }));
86
87
  }
88
+ function findAndReplaceEdits(content, rule, transformer) {
89
+ const nodes = content.root().findAll({
90
+ rule
91
+ });
92
+ return arrays.compactMap(nodes, (node)=>{
93
+ const transformed = transformer(node);
94
+ if (null == transformed) return null;
95
+ return node.replace(transformed);
96
+ });
97
+ }
98
+ function findAndReplace(content, rule, transformer) {
99
+ const root = content.root();
100
+ const edits = findAndReplaceEdits(content, rule, transformer);
101
+ return root.commitEdits(edits);
102
+ }
87
103
  async function commitEditModifications(edits, modifications) {
88
104
  if (0 === edits.length) return modifications;
89
105
  const root = modifications.ast.root();
@@ -117,4 +133,4 @@ function defaultedHooks(hooks) {
117
133
  preCodemodRun
118
134
  };
119
135
  }
120
- export { commitEditModifications, runCodemod, runCodemods };
136
+ export { commitEditModifications, findAndReplace, findAndReplaceEdits, runCodemod, runCodemods };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamaalio/codemod-kit",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "type": "module",
5
5
  "author": "Kamaal Farah",
6
6
  "license": "MIT",
@@ -20,6 +20,7 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "@ast-grep/napi": "^0.38.5",
23
+ "@kamaalio/kamaal": "^0.7.6",
23
24
  "fast-glob": "^3.3.3",
24
25
  "neverthrow": "^8.2.0"
25
26
  },