@@ -123,112 +123,3 @@ import { getNodeJsUsage } from '@nodejs/codemod-utils';
123
123
// Finds scripts like: "start": "node server.js", "build": "node.exe build.js"
124
124
const nodeUsages = getNodeJsUsage (packageJsonAst );
125
125
```
126
-
127
- ## Practical Examples
128
-
129
- ### Complete Codemod Workflow
130
-
131
- Here's how these utilities work together in a typical Node.js deprecation codemod:
132
-
133
- ``` typescript
134
- import astGrep from ' @ast-grep/napi' ;
135
- import {
136
- getNodeImportStatements ,
137
- getNodeRequireCalls ,
138
- resolveBindingPath ,
139
- removeBinding ,
140
- removeLines
141
- } from ' @nodejs/codemod-utils' ;
142
-
143
- export default function workflow({ file , options }) {
144
- // 1. Parse the source code
145
- const ast = astGrep .parse (astGrep .Lang .JavaScript , file .source );
146
-
147
- // 2. Find all util imports/requires
148
- const importStatements = getNodeImportStatements (ast , ' util' );
149
- const requireCalls = getNodeRequireCalls (ast , ' util' );
150
- const allUtilNodes = [... importStatements , ... requireCalls ];
151
-
152
- // 3. Find and transform deprecated API usage
153
- const edits = [];
154
- const linesToRemove = [];
155
-
156
- for (const node of allUtilNodes ) {
157
- // Resolve how the deprecated API is accessed locally
158
- const localPath = resolveBindingPath (node , ' $.types.isNativeError' );
159
-
160
- if (localPath ) {
161
- // Find all usages of the deprecated API
162
- const usages = ast .root ().findAll ({
163
- rule: {
164
- kind: ' call_expression' ,
165
- has: {
166
- field: ' function' ,
167
- kind: ' member_expression' ,
168
- regex: localPath .replace (' .' , ' \\ .' )
169
- }
170
- }
171
- });
172
-
173
- // Transform each usage
174
- for (const usage of usages ) {
175
- edits .push ({
176
- startIndex: usage .range ().start .index ,
177
- endIndex: usage .range ().end .index ,
178
- newText: usage .text ().replace (localPath , ' util.types.isError' )
179
- });
180
- }
181
-
182
- // Remove the binding if it's no longer needed
183
- const bindingRemoval = removeBinding (node , ' types' );
184
- if (bindingRemoval ?.edit ) {
185
- edits .push (bindingRemoval .edit );
186
- } else if (bindingRemoval ?.lineToRemove ) {
187
- linesToRemove .push (bindingRemoval .lineToRemove );
188
- }
189
- }
190
- }
191
-
192
- // 4. Apply all transformations
193
- let transformedSource = file .source ;
194
-
195
- // Apply edits
196
- for (const edit of edits .reverse ()) { // reverse to maintain indices
197
- transformedSource = transformedSource .slice (0 , edit .startIndex ) +
198
- edit .newText +
199
- transformedSource .slice (edit .endIndex );
200
- }
201
-
202
- // Remove entire lines
203
- if (linesToRemove .length > 0 ) {
204
- transformedSource = removeLines (transformedSource , linesToRemove );
205
- }
206
-
207
- return {
208
- ... file ,
209
- source: transformedSource
210
- };
211
- }
212
- ```
213
-
214
- ### Handling Different Import Patterns
215
-
216
- The utilities automatically handle various import/require patterns:
217
-
218
- ``` typescript
219
- // ES Modules
220
- import util from ' util' ; // → util.types.isNativeError
221
- import { types } from ' util' ; // → types.isNativeError
222
- import { types as t } from ' util' ; // → t.isNativeError
223
-
224
- // CommonJS
225
- const util = require (' util' ); // → util.types.isNativeError
226
- const { types } = require (' util' ); // → types.isNativeError
227
- const { types : t } = require (' util' ); // → t.isNativeError
228
-
229
- // Mixed with node: protocol
230
- import { types } from ' node:util' ; // → types.isNativeError
231
- const util = require (' node:util' ); // → util.types.isNativeError
232
- ```
233
-
234
- This unified approach ensures your codemods work correctly regardless of how developers import Node.js modules in their projects.
0 commit comments