@next/codemod 16.0.0-canary.13 → 16.0.0-canary.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next/codemod",
3
- "version": "16.0.0-canary.13",
3
+ "version": "16.0.0-canary.14",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -118,6 +118,7 @@ function replaceFlatCompatInConfig(configPath) {
118
118
  // Look for FlatCompat extends usage and identify which configs are being used
119
119
  root.find(j.CallExpression).forEach((astPath) => {
120
120
  const node = astPath.value;
121
+ // Detect compat.extends() calls and identify which configs are being used
121
122
  if (node.callee.type === 'MemberExpression' &&
122
123
  node.callee.object.type === 'Identifier' &&
123
124
  node.callee.object.name === 'compat' &&
@@ -139,6 +140,41 @@ function replaceFlatCompatInConfig(configPath) {
139
140
  }
140
141
  });
141
142
  }
143
+ // Detect compat.config({ extends: [...] }) calls and identify which configs are being used
144
+ if (node.callee.type === 'MemberExpression' &&
145
+ node.callee.object.type === 'Identifier' &&
146
+ node.callee.object.name === 'compat' &&
147
+ node.callee.property.type === 'Identifier' &&
148
+ node.callee.property.name === 'config') {
149
+ // Look for extends property in the object argument
150
+ node.arguments.forEach((arg) => {
151
+ if (arg.type === 'ObjectExpression') {
152
+ arg.properties?.forEach((prop) => {
153
+ if (prop.type === 'ObjectProperty' &&
154
+ prop.key.type === 'Identifier' &&
155
+ prop.key.name === 'extends' &&
156
+ prop.value.type === 'ArrayExpression') {
157
+ // Process the extends array
158
+ prop.value.elements?.forEach((element) => {
159
+ if (element.type === 'Literal' ||
160
+ element.type === 'StringLiteral') {
161
+ if (element.value === 'next/core-web-vitals') {
162
+ needsNextVitals = true;
163
+ }
164
+ else if (element.value === 'next/typescript') {
165
+ needsNextTs = true;
166
+ }
167
+ else if (typeof element.value === 'string') {
168
+ // Preserve other configs (non-Next.js or other Next.js variants)
169
+ otherConfigs.push(element.value);
170
+ }
171
+ }
172
+ });
173
+ }
174
+ });
175
+ }
176
+ });
177
+ }
142
178
  });
143
179
  if (!needsNextVitals && !needsNextTs && otherConfigs.length === 0) {
144
180
  console.warn(exports.prefixes.warn, ' No ESLint configs found in FlatCompat usage');
@@ -217,6 +253,7 @@ function replaceFlatCompatInConfig(configPath) {
217
253
  // Replace FlatCompat extends with spread imports
218
254
  root.find(j.SpreadElement).forEach((astPath) => {
219
255
  const node = astPath.value;
256
+ // Replace spread of compat.extends(...) calls with direct imports
220
257
  if (node.argument.type === 'CallExpression' &&
221
258
  node.argument.callee.type === 'MemberExpression' &&
222
259
  node.argument.callee.object.type === 'Identifier' &&
@@ -250,6 +287,70 @@ function replaceFlatCompatInConfig(configPath) {
250
287
  }
251
288
  }
252
289
  }
290
+ // Replace spread of compat.config({ extends: [...] }) calls with direct imports
291
+ if (node.argument.type === 'CallExpression' &&
292
+ node.argument.callee.type === 'MemberExpression' &&
293
+ node.argument.callee.object.type === 'Identifier' &&
294
+ node.argument.callee.object.name === 'compat' &&
295
+ node.argument.callee.property.type === 'Identifier' &&
296
+ node.argument.callee.property.name === 'config') {
297
+ const replacements = [];
298
+ const preservedConfigs = [];
299
+ // Process each argument to compat.config
300
+ node.argument.arguments.forEach((arg) => {
301
+ if (arg.type === 'ObjectExpression') {
302
+ const updatedProperties = [];
303
+ arg.properties?.forEach((prop) => {
304
+ if (prop.type === 'ObjectProperty' &&
305
+ prop.key.type === 'Identifier' &&
306
+ prop.key.name === 'extends' &&
307
+ prop.value.type === 'ArrayExpression') {
308
+ const nonNextConfigs = [];
309
+ // Process extends array
310
+ prop.value.elements?.forEach((element) => {
311
+ if (element.type === 'Literal' ||
312
+ element.type === 'StringLiteral') {
313
+ if (element.value === 'next/core-web-vitals') {
314
+ replacements.push(j.spreadElement(j.identifier('nextCoreWebVitals')));
315
+ }
316
+ else if (element.value === 'next/typescript') {
317
+ replacements.push(j.spreadElement(j.identifier('nextTypescript')));
318
+ }
319
+ else if (typeof element.value === 'string') {
320
+ // Keep non-Next.js configs
321
+ nonNextConfigs.push(element);
322
+ }
323
+ }
324
+ });
325
+ // If there are non-Next.js configs, preserve the extends property with them
326
+ if (nonNextConfigs.length > 0) {
327
+ updatedProperties.push(j.property('init', j.identifier('extends'), j.arrayExpression(nonNextConfigs)));
328
+ }
329
+ }
330
+ else {
331
+ // Preserve other properties (not extends)
332
+ updatedProperties.push(prop);
333
+ }
334
+ });
335
+ // If we still have properties to preserve, keep the compat.config call
336
+ if (updatedProperties.length > 0) {
337
+ preservedConfigs.push(j.spreadElement(j.callExpression(j.memberExpression(j.identifier('compat'), j.identifier('config')), [j.objectExpression(updatedProperties)])));
338
+ }
339
+ }
340
+ });
341
+ // Add all replacements
342
+ const allReplacements = [...replacements, ...preservedConfigs];
343
+ if (allReplacements.length > 0) {
344
+ // Replace the current spread element with multiple spread elements
345
+ const parent = astPath.parent;
346
+ if (parent.value.type === 'ArrayExpression') {
347
+ const index = parent.value.elements.indexOf(node);
348
+ if (index !== -1) {
349
+ parent.value.elements.splice(index, 1, ...allReplacements);
350
+ }
351
+ }
352
+ }
353
+ }
253
354
  });
254
355
  // Also handle the case where extends is used as a property value (not spread)
255
356
  root.find(j.ObjectExpression).forEach((astPath) => {