@next/codemod 16.0.0-canary.9 → 16.0.1-canary.0
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/bin/upgrade.js
CHANGED
|
@@ -164,7 +164,8 @@ async function runUpgrade(revision, options) {
|
|
|
164
164
|
const targetReactVersion = shouldStayOnReact18
|
|
165
165
|
? '18.3.1'
|
|
166
166
|
: await loadHighestNPMVersionMatching(`react@${targetNextPackageJson.peerDependencies['react']}`);
|
|
167
|
-
if ((0, semver_1.compare)(targetNextVersion, '15.0.0-canary') >= 0
|
|
167
|
+
if ((0, semver_1.compare)(targetNextVersion, '15.0.0-canary') >= 0 &&
|
|
168
|
+
(0, semver_1.compare)(targetNextVersion, '16.0.0-canary') < 0) {
|
|
168
169
|
await suggestTurbopack(appPackageJson, targetNextVersion);
|
|
169
170
|
}
|
|
170
171
|
const codemods = await suggestCodemods(installedNextVersion, targetNextVersion);
|
package/lib/utils.js
CHANGED
|
@@ -122,5 +122,15 @@ exports.TRANSFORMER_INQUIRER_CHOICES = [
|
|
|
122
122
|
value: 'middleware-to-proxy',
|
|
123
123
|
version: '15.6.0-canary.54',
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
title: 'Remove `unstable_` prefix from stabilized API',
|
|
127
|
+
value: 'remove-unstable-prefix',
|
|
128
|
+
version: '16.0.0-canary.10',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
title: 'Remove `experimental_ppr` Route Segment Config from App Router pages and layouts',
|
|
132
|
+
value: 'remove-experimental-ppr',
|
|
133
|
+
version: '16.0.0-canary.11',
|
|
134
|
+
},
|
|
125
135
|
];
|
|
126
136
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -45,6 +45,9 @@ function transformer(file) {
|
|
|
45
45
|
if (isMiddlewareFile) {
|
|
46
46
|
const middlewareChanges = transformMiddlewareFunction(root, j);
|
|
47
47
|
hasChanges = hasChanges || middlewareChanges.hasChanges;
|
|
48
|
+
// Remove runtime segment config
|
|
49
|
+
const runtimeChanges = removeRuntimeConfig(root, j);
|
|
50
|
+
hasChanges = hasChanges || runtimeChanges;
|
|
48
51
|
}
|
|
49
52
|
if (isNextConfig) {
|
|
50
53
|
const { hasConfigChanges } = transformNextConfig(root, j);
|
|
@@ -602,4 +605,123 @@ function extractObjectsFromCallExpression(callExpr, configObjects, exportedNames
|
|
|
602
605
|
});
|
|
603
606
|
}
|
|
604
607
|
}
|
|
608
|
+
function removeRuntimeConfig(root, j) {
|
|
609
|
+
let hasChanges = false;
|
|
610
|
+
// Remove export const runtime = 'string'
|
|
611
|
+
const directRuntimeExports = root.find(j.ExportNamedDeclaration, {
|
|
612
|
+
declaration: {
|
|
613
|
+
type: 'VariableDeclaration',
|
|
614
|
+
declarations: [
|
|
615
|
+
{
|
|
616
|
+
id: { name: 'runtime' },
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
},
|
|
620
|
+
});
|
|
621
|
+
if (directRuntimeExports.size() > 0) {
|
|
622
|
+
directRuntimeExports.remove();
|
|
623
|
+
hasChanges = true;
|
|
624
|
+
}
|
|
625
|
+
// Remove const runtime = 'string' declarations
|
|
626
|
+
const runtimeVariableDeclarations = root
|
|
627
|
+
.find(j.VariableDeclaration)
|
|
628
|
+
.filter((path) => path.node.declarations.some((decl) => {
|
|
629
|
+
if (j.VariableDeclarator.check(decl) && j.Identifier.check(decl.id)) {
|
|
630
|
+
return decl.id.name === 'runtime';
|
|
631
|
+
}
|
|
632
|
+
return false;
|
|
633
|
+
}));
|
|
634
|
+
if (runtimeVariableDeclarations.size() > 0) {
|
|
635
|
+
runtimeVariableDeclarations.forEach((path) => {
|
|
636
|
+
const originalDeclarations = path.node.declarations;
|
|
637
|
+
const filteredDeclarations = originalDeclarations.filter((decl) => {
|
|
638
|
+
if (j.VariableDeclarator.check(decl) && j.Identifier.check(decl.id)) {
|
|
639
|
+
return decl.id.name !== 'runtime';
|
|
640
|
+
}
|
|
641
|
+
return true;
|
|
642
|
+
});
|
|
643
|
+
// If we filtered out some declarations, update the node
|
|
644
|
+
if (filteredDeclarations.length !== originalDeclarations.length) {
|
|
645
|
+
// Remove the entire declaration only if no declarators left
|
|
646
|
+
if (filteredDeclarations.length === 0) {
|
|
647
|
+
j(path).remove();
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
path.node.declarations = filteredDeclarations;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
hasChanges = true;
|
|
655
|
+
}
|
|
656
|
+
// Handle export { runtime } and export { runtime, other }
|
|
657
|
+
const namedExports = root
|
|
658
|
+
.find(j.ExportNamedDeclaration)
|
|
659
|
+
.filter((path) => path.node.specifiers && path.node.specifiers.length > 0);
|
|
660
|
+
namedExports.forEach((path) => {
|
|
661
|
+
const specifiers = path.node.specifiers;
|
|
662
|
+
if (!specifiers)
|
|
663
|
+
return;
|
|
664
|
+
const filteredSpecifiers = specifiers.filter((spec) => {
|
|
665
|
+
if (j.ExportSpecifier.check(spec) && j.Identifier.check(spec.local)) {
|
|
666
|
+
return spec.local.name !== 'runtime';
|
|
667
|
+
}
|
|
668
|
+
return true;
|
|
669
|
+
});
|
|
670
|
+
// If we removed any specifiers
|
|
671
|
+
if (filteredSpecifiers.length !== specifiers.length) {
|
|
672
|
+
hasChanges = true;
|
|
673
|
+
// If no specifiers left, remove the entire export statement
|
|
674
|
+
if (filteredSpecifiers.length === 0) {
|
|
675
|
+
j(path).remove();
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
// Update the specifiers array
|
|
679
|
+
path.node.specifiers = filteredSpecifiers;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
// Handle runtime property in config objects
|
|
684
|
+
const configExports = root.find(j.ExportNamedDeclaration, {
|
|
685
|
+
declaration: {
|
|
686
|
+
type: 'VariableDeclaration',
|
|
687
|
+
declarations: [
|
|
688
|
+
{
|
|
689
|
+
id: { name: 'config' },
|
|
690
|
+
},
|
|
691
|
+
],
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
configExports.forEach((path) => {
|
|
695
|
+
const declaration = path.node.declaration;
|
|
696
|
+
if (j.VariableDeclaration.check(declaration)) {
|
|
697
|
+
declaration.declarations.forEach((decl) => {
|
|
698
|
+
if (j.VariableDeclarator.check(decl) &&
|
|
699
|
+
j.Identifier.check(decl.id) &&
|
|
700
|
+
decl.id.name === 'config' &&
|
|
701
|
+
j.ObjectExpression.check(decl.init)) {
|
|
702
|
+
const objExpr = decl.init;
|
|
703
|
+
const initialLength = objExpr.properties.length;
|
|
704
|
+
// Filter out runtime property
|
|
705
|
+
objExpr.properties = objExpr.properties.filter((prop) => {
|
|
706
|
+
if (isStaticProperty(prop) &&
|
|
707
|
+
prop.key &&
|
|
708
|
+
prop.key.type === 'Identifier') {
|
|
709
|
+
return prop.key.name !== 'runtime';
|
|
710
|
+
}
|
|
711
|
+
return true;
|
|
712
|
+
});
|
|
713
|
+
// If we removed any properties
|
|
714
|
+
if (objExpr.properties.length !== initialLength) {
|
|
715
|
+
hasChanges = true;
|
|
716
|
+
// If no properties left, remove the entire config export
|
|
717
|
+
if (objExpr.properties.length === 0) {
|
|
718
|
+
j(path).remove();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
return hasChanges;
|
|
726
|
+
}
|
|
605
727
|
//# sourceMappingURL=middleware-to-proxy.js.map
|
|
@@ -8,6 +8,7 @@ exports.default = transformer;
|
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const node_child_process_1 = require("node:child_process");
|
|
11
|
+
const semver_1 = __importDefault(require("semver"));
|
|
11
12
|
const handle_package_1 = require("../lib/handle-package");
|
|
12
13
|
const parser_1 = require("../lib/parser");
|
|
13
14
|
const picocolors_1 = require("picocolors");
|
|
@@ -118,6 +119,7 @@ function replaceFlatCompatInConfig(configPath) {
|
|
|
118
119
|
// Look for FlatCompat extends usage and identify which configs are being used
|
|
119
120
|
root.find(j.CallExpression).forEach((astPath) => {
|
|
120
121
|
const node = astPath.value;
|
|
122
|
+
// Detect compat.extends() calls and identify which configs are being used
|
|
121
123
|
if (node.callee.type === 'MemberExpression' &&
|
|
122
124
|
node.callee.object.type === 'Identifier' &&
|
|
123
125
|
node.callee.object.name === 'compat' &&
|
|
@@ -139,6 +141,41 @@ function replaceFlatCompatInConfig(configPath) {
|
|
|
139
141
|
}
|
|
140
142
|
});
|
|
141
143
|
}
|
|
144
|
+
// Detect compat.config({ extends: [...] }) calls and identify which configs are being used
|
|
145
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
146
|
+
node.callee.object.type === 'Identifier' &&
|
|
147
|
+
node.callee.object.name === 'compat' &&
|
|
148
|
+
node.callee.property.type === 'Identifier' &&
|
|
149
|
+
node.callee.property.name === 'config') {
|
|
150
|
+
// Look for extends property in the object argument
|
|
151
|
+
node.arguments.forEach((arg) => {
|
|
152
|
+
if (arg.type === 'ObjectExpression') {
|
|
153
|
+
arg.properties?.forEach((prop) => {
|
|
154
|
+
if (prop.type === 'ObjectProperty' &&
|
|
155
|
+
prop.key.type === 'Identifier' &&
|
|
156
|
+
prop.key.name === 'extends' &&
|
|
157
|
+
prop.value.type === 'ArrayExpression') {
|
|
158
|
+
// Process the extends array
|
|
159
|
+
prop.value.elements?.forEach((element) => {
|
|
160
|
+
if (element.type === 'Literal' ||
|
|
161
|
+
element.type === 'StringLiteral') {
|
|
162
|
+
if (element.value === 'next/core-web-vitals') {
|
|
163
|
+
needsNextVitals = true;
|
|
164
|
+
}
|
|
165
|
+
else if (element.value === 'next/typescript') {
|
|
166
|
+
needsNextTs = true;
|
|
167
|
+
}
|
|
168
|
+
else if (typeof element.value === 'string') {
|
|
169
|
+
// Preserve other configs (non-Next.js or other Next.js variants)
|
|
170
|
+
otherConfigs.push(element.value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
142
179
|
});
|
|
143
180
|
if (!needsNextVitals && !needsNextTs && otherConfigs.length === 0) {
|
|
144
181
|
console.warn(exports.prefixes.warn, ' No ESLint configs found in FlatCompat usage');
|
|
@@ -217,6 +254,7 @@ function replaceFlatCompatInConfig(configPath) {
|
|
|
217
254
|
// Replace FlatCompat extends with spread imports
|
|
218
255
|
root.find(j.SpreadElement).forEach((astPath) => {
|
|
219
256
|
const node = astPath.value;
|
|
257
|
+
// Replace spread of compat.extends(...) calls with direct imports
|
|
220
258
|
if (node.argument.type === 'CallExpression' &&
|
|
221
259
|
node.argument.callee.type === 'MemberExpression' &&
|
|
222
260
|
node.argument.callee.object.type === 'Identifier' &&
|
|
@@ -250,6 +288,70 @@ function replaceFlatCompatInConfig(configPath) {
|
|
|
250
288
|
}
|
|
251
289
|
}
|
|
252
290
|
}
|
|
291
|
+
// Replace spread of compat.config({ extends: [...] }) calls with direct imports
|
|
292
|
+
if (node.argument.type === 'CallExpression' &&
|
|
293
|
+
node.argument.callee.type === 'MemberExpression' &&
|
|
294
|
+
node.argument.callee.object.type === 'Identifier' &&
|
|
295
|
+
node.argument.callee.object.name === 'compat' &&
|
|
296
|
+
node.argument.callee.property.type === 'Identifier' &&
|
|
297
|
+
node.argument.callee.property.name === 'config') {
|
|
298
|
+
const replacements = [];
|
|
299
|
+
const preservedConfigs = [];
|
|
300
|
+
// Process each argument to compat.config
|
|
301
|
+
node.argument.arguments.forEach((arg) => {
|
|
302
|
+
if (arg.type === 'ObjectExpression') {
|
|
303
|
+
const updatedProperties = [];
|
|
304
|
+
arg.properties?.forEach((prop) => {
|
|
305
|
+
if (prop.type === 'ObjectProperty' &&
|
|
306
|
+
prop.key.type === 'Identifier' &&
|
|
307
|
+
prop.key.name === 'extends' &&
|
|
308
|
+
prop.value.type === 'ArrayExpression') {
|
|
309
|
+
const nonNextConfigs = [];
|
|
310
|
+
// Process extends array
|
|
311
|
+
prop.value.elements?.forEach((element) => {
|
|
312
|
+
if (element.type === 'Literal' ||
|
|
313
|
+
element.type === 'StringLiteral') {
|
|
314
|
+
if (element.value === 'next/core-web-vitals') {
|
|
315
|
+
replacements.push(j.spreadElement(j.identifier('nextCoreWebVitals')));
|
|
316
|
+
}
|
|
317
|
+
else if (element.value === 'next/typescript') {
|
|
318
|
+
replacements.push(j.spreadElement(j.identifier('nextTypescript')));
|
|
319
|
+
}
|
|
320
|
+
else if (typeof element.value === 'string') {
|
|
321
|
+
// Keep non-Next.js configs
|
|
322
|
+
nonNextConfigs.push(element);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
// If there are non-Next.js configs, preserve the extends property with them
|
|
327
|
+
if (nonNextConfigs.length > 0) {
|
|
328
|
+
updatedProperties.push(j.property('init', j.identifier('extends'), j.arrayExpression(nonNextConfigs)));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
// Preserve other properties (not extends)
|
|
333
|
+
updatedProperties.push(prop);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
// If we still have properties to preserve, keep the compat.config call
|
|
337
|
+
if (updatedProperties.length > 0) {
|
|
338
|
+
preservedConfigs.push(j.spreadElement(j.callExpression(j.memberExpression(j.identifier('compat'), j.identifier('config')), [j.objectExpression(updatedProperties)])));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
// Add all replacements
|
|
343
|
+
const allReplacements = [...replacements, ...preservedConfigs];
|
|
344
|
+
if (allReplacements.length > 0) {
|
|
345
|
+
// Replace the current spread element with multiple spread elements
|
|
346
|
+
const parent = astPath.parent;
|
|
347
|
+
if (parent.value.type === 'ArrayExpression') {
|
|
348
|
+
const index = parent.value.elements.indexOf(node);
|
|
349
|
+
if (index !== -1) {
|
|
350
|
+
parent.value.elements.splice(index, 1, ...allReplacements);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
253
355
|
});
|
|
254
356
|
// Also handle the case where extends is used as a property value (not spread)
|
|
255
357
|
root.find(j.ObjectExpression).forEach((astPath) => {
|
|
@@ -658,6 +760,19 @@ function updatePackageJsonScripts(packageJsonContent) {
|
|
|
658
760
|
nextVersion || 'latest';
|
|
659
761
|
needsUpdate = true;
|
|
660
762
|
}
|
|
763
|
+
// Bump eslint to v9 for full Flat config support
|
|
764
|
+
if (packageJson.dependencies?.['eslint'] &&
|
|
765
|
+
semver_1.default.lt(semver_1.default.minVersion(packageJson.dependencies['eslint'])?.version ??
|
|
766
|
+
'0.0.0', '9.0.0')) {
|
|
767
|
+
packageJson.dependencies['eslint'] = '^9';
|
|
768
|
+
needsUpdate = true;
|
|
769
|
+
}
|
|
770
|
+
if (packageJson.devDependencies?.['eslint'] &&
|
|
771
|
+
semver_1.default.lt(semver_1.default.minVersion(packageJson.devDependencies['eslint'])?.version ??
|
|
772
|
+
'0.0.0', '9.0.0')) {
|
|
773
|
+
packageJson.devDependencies['eslint'] = '^9';
|
|
774
|
+
needsUpdate = true;
|
|
775
|
+
}
|
|
661
776
|
// Remove @eslint/eslintrc if it exists since we no longer use FlatCompat
|
|
662
777
|
if (packageJson.devDependencies?.['@eslint/eslintrc']) {
|
|
663
778
|
delete packageJson.devDependencies['@eslint/eslintrc'];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = transformer;
|
|
4
|
+
const parser_1 = require("../lib/parser");
|
|
5
|
+
function transformer(file, _api) {
|
|
6
|
+
// Run on App Router page/layout/route files, except for test environment.
|
|
7
|
+
if (process.env.NODE_ENV !== 'test' &&
|
|
8
|
+
!/[/\\]app[/\\](?:.*[/\\])?(page|layout|route)(\.[^/\\]*)?$/.test(file.path)) {
|
|
9
|
+
return file.source;
|
|
10
|
+
}
|
|
11
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
12
|
+
const root = j(file.source);
|
|
13
|
+
let hasChanges = false;
|
|
14
|
+
// Remove export const experimental_ppr = boolean
|
|
15
|
+
const directExports = root.find(j.ExportNamedDeclaration, {
|
|
16
|
+
declaration: {
|
|
17
|
+
type: 'VariableDeclaration',
|
|
18
|
+
declarations: [
|
|
19
|
+
{
|
|
20
|
+
id: { name: 'experimental_ppr' },
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (directExports.size() > 0) {
|
|
26
|
+
directExports.remove();
|
|
27
|
+
hasChanges = true;
|
|
28
|
+
}
|
|
29
|
+
// Remove const experimental_ppr = boolean declarations
|
|
30
|
+
const variableDeclarations = root.find(j.VariableDeclaration).filter((path) => path.node.declarations.some((decl) => {
|
|
31
|
+
if (j.VariableDeclarator.check(decl) && j.Identifier.check(decl.id)) {
|
|
32
|
+
return decl.id.name === 'experimental_ppr';
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}));
|
|
36
|
+
if (variableDeclarations.size() > 0) {
|
|
37
|
+
variableDeclarations.remove();
|
|
38
|
+
hasChanges = true;
|
|
39
|
+
}
|
|
40
|
+
// Handle export { experimental_ppr } and export { experimental_ppr, other }
|
|
41
|
+
const namedExports = root
|
|
42
|
+
.find(j.ExportNamedDeclaration)
|
|
43
|
+
.filter((path) => path.node.specifiers && path.node.specifiers.length > 0);
|
|
44
|
+
namedExports.forEach((path) => {
|
|
45
|
+
const specifiers = path.node.specifiers;
|
|
46
|
+
if (!specifiers)
|
|
47
|
+
return;
|
|
48
|
+
const filteredSpecifiers = specifiers.filter((spec) => {
|
|
49
|
+
if (j.ExportSpecifier.check(spec) && j.Identifier.check(spec.local)) {
|
|
50
|
+
return spec.local.name !== 'experimental_ppr';
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
// If we removed any specifiers
|
|
55
|
+
if (filteredSpecifiers.length !== specifiers.length) {
|
|
56
|
+
hasChanges = true;
|
|
57
|
+
// If no specifiers left, remove the entire export statement
|
|
58
|
+
if (filteredSpecifiers.length === 0) {
|
|
59
|
+
j(path).remove();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Update the specifiers array
|
|
63
|
+
path.node.specifiers = filteredSpecifiers;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
if (hasChanges) {
|
|
68
|
+
return root.toSource();
|
|
69
|
+
}
|
|
70
|
+
return file.source;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=remove-experimental-ppr.js.map
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = transformer;
|
|
4
|
+
const parser_1 = require("../lib/parser");
|
|
5
|
+
// Mapping of unstable APIs to their stable counterparts
|
|
6
|
+
// This can be easily extended when new APIs are stabilized
|
|
7
|
+
const UNSTABLE_TO_STABLE_MAPPING = {
|
|
8
|
+
unstable_cacheTag: 'cacheTag',
|
|
9
|
+
unstable_cacheLife: 'cacheLife',
|
|
10
|
+
};
|
|
11
|
+
// Helper function to check if a property name should be renamed
|
|
12
|
+
function shouldRenameProperty(propertyName) {
|
|
13
|
+
return propertyName in UNSTABLE_TO_STABLE_MAPPING;
|
|
14
|
+
}
|
|
15
|
+
function transformer(file, _api, options) {
|
|
16
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
17
|
+
const root = j(file.source);
|
|
18
|
+
let hasChanges = false;
|
|
19
|
+
try {
|
|
20
|
+
// Track identifier renames that need to be applied
|
|
21
|
+
const identifierRenames = [];
|
|
22
|
+
// Track variables assigned from next/cache imports/requires
|
|
23
|
+
const cacheVariables = new Set();
|
|
24
|
+
// Handle ES6 imports: import { unstable_cacheTag } from 'next/cache'
|
|
25
|
+
root
|
|
26
|
+
.find(j.ImportDeclaration, { source: { value: 'next/cache' } })
|
|
27
|
+
.forEach((path) => {
|
|
28
|
+
path.node.specifiers?.forEach((specifier) => {
|
|
29
|
+
if (specifier.type === 'ImportSpecifier' &&
|
|
30
|
+
specifier.imported?.type === 'Identifier' &&
|
|
31
|
+
shouldRenameProperty(specifier.imported.name)) {
|
|
32
|
+
const oldName = specifier.imported.name;
|
|
33
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[oldName];
|
|
34
|
+
// Handle alias scenarios
|
|
35
|
+
if (specifier.local && specifier.local.name === newName) {
|
|
36
|
+
// Same alias name: { unstable_cacheTag as cacheTag } -> { cacheTag }
|
|
37
|
+
const newSpecifier = j.importSpecifier(j.identifier(newName));
|
|
38
|
+
const specifierIndex = path.node.specifiers.indexOf(specifier);
|
|
39
|
+
path.node.specifiers[specifierIndex] = newSpecifier;
|
|
40
|
+
identifierRenames.push({ oldName, newName });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Normal case: just update the imported name
|
|
44
|
+
specifier.imported = j.identifier(newName);
|
|
45
|
+
if (!specifier.local || specifier.local.name === oldName) {
|
|
46
|
+
// Not aliased or aliased with old name: add to identifier renames
|
|
47
|
+
identifierRenames.push({ oldName, newName });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
hasChanges = true;
|
|
51
|
+
}
|
|
52
|
+
else if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
53
|
+
// Handle namespace imports: import * as cache from 'next/cache'
|
|
54
|
+
cacheVariables.add(specifier.local.name);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
// Handle export statements: export { unstable_cacheTag } from 'next/cache'
|
|
59
|
+
root
|
|
60
|
+
.find(j.ExportNamedDeclaration, { source: { value: 'next/cache' } })
|
|
61
|
+
.forEach((path) => {
|
|
62
|
+
path.node.specifiers?.forEach((specifier) => {
|
|
63
|
+
if (specifier.type === 'ExportSpecifier' &&
|
|
64
|
+
specifier.local?.type === 'Identifier' &&
|
|
65
|
+
shouldRenameProperty(specifier.local.name)) {
|
|
66
|
+
const oldName = specifier.local.name;
|
|
67
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[oldName];
|
|
68
|
+
specifier.local = j.identifier(newName);
|
|
69
|
+
// Handle export alias scenarios
|
|
70
|
+
if (specifier.exported && specifier.exported.name === newName) {
|
|
71
|
+
// Same alias name: { unstable_cacheTag as cacheTag } -> { cacheTag }
|
|
72
|
+
specifier.exported = specifier.local;
|
|
73
|
+
}
|
|
74
|
+
else if (!specifier.exported ||
|
|
75
|
+
specifier.exported.name === oldName) {
|
|
76
|
+
// Not aliased or aliased with old name
|
|
77
|
+
specifier.exported = j.identifier(newName);
|
|
78
|
+
}
|
|
79
|
+
hasChanges = true;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
// Handle require('next/cache') calls and destructuring
|
|
84
|
+
root
|
|
85
|
+
.find(j.CallExpression, { callee: { name: 'require' } })
|
|
86
|
+
.forEach((path) => {
|
|
87
|
+
if (path.node.arguments[0]?.type === 'StringLiteral' &&
|
|
88
|
+
path.node.arguments[0].value === 'next/cache') {
|
|
89
|
+
// Track variable assignments: const cache = require('next/cache')
|
|
90
|
+
const parent = path.parent?.node;
|
|
91
|
+
if (parent?.type === 'VariableDeclarator' &&
|
|
92
|
+
parent.id?.type === 'Identifier') {
|
|
93
|
+
cacheVariables.add(parent.id.name);
|
|
94
|
+
}
|
|
95
|
+
// Handle destructuring: const { unstable_cacheTag } = require('next/cache')
|
|
96
|
+
if (parent?.type === 'VariableDeclarator' &&
|
|
97
|
+
parent.id?.type === 'ObjectPattern') {
|
|
98
|
+
parent.id.properties?.forEach((property) => {
|
|
99
|
+
if (property.type === 'ObjectProperty' &&
|
|
100
|
+
property.key?.type === 'Identifier' &&
|
|
101
|
+
shouldRenameProperty(property.key.name)) {
|
|
102
|
+
const oldName = property.key.name;
|
|
103
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[oldName];
|
|
104
|
+
property.key = j.identifier(newName);
|
|
105
|
+
// Handle both shorthand and explicit destructuring
|
|
106
|
+
if (!property.value) {
|
|
107
|
+
property.value = j.identifier(newName);
|
|
108
|
+
identifierRenames.push({ oldName, newName });
|
|
109
|
+
}
|
|
110
|
+
else if (property.value.type === 'Identifier') {
|
|
111
|
+
const localName = property.value.name;
|
|
112
|
+
if (localName === oldName) {
|
|
113
|
+
property.value = j.identifier(newName);
|
|
114
|
+
identifierRenames.push({ oldName, newName });
|
|
115
|
+
}
|
|
116
|
+
else if (localName === newName) {
|
|
117
|
+
// Same alias name: { unstable_cacheTag: cacheTag } -> { cacheTag }
|
|
118
|
+
property.value = j.identifier(newName);
|
|
119
|
+
property.shorthand = true;
|
|
120
|
+
identifierRenames.push({ oldName, newName });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
hasChanges = true;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// Handle await import('next/cache') calls and destructuring
|
|
130
|
+
root.find(j.AwaitExpression).forEach((path) => {
|
|
131
|
+
const arg = path.node.argument;
|
|
132
|
+
if (arg?.type === 'CallExpression' &&
|
|
133
|
+
arg.callee?.type === 'Import' &&
|
|
134
|
+
arg.arguments[0]?.type === 'StringLiteral' &&
|
|
135
|
+
arg.arguments[0].value === 'next/cache') {
|
|
136
|
+
// Track variable assignments: const cache = await import('next/cache')
|
|
137
|
+
const parent = path.parent?.node;
|
|
138
|
+
if (parent?.type === 'VariableDeclarator' &&
|
|
139
|
+
parent.id?.type === 'Identifier') {
|
|
140
|
+
cacheVariables.add(parent.id.name);
|
|
141
|
+
}
|
|
142
|
+
// Handle destructuring: const { unstable_cacheTag } = await import('next/cache')
|
|
143
|
+
if (parent?.type === 'VariableDeclarator' &&
|
|
144
|
+
parent.id?.type === 'ObjectPattern') {
|
|
145
|
+
parent.id.properties?.forEach((property) => {
|
|
146
|
+
if (property.type === 'ObjectProperty' &&
|
|
147
|
+
property.key?.type === 'Identifier' &&
|
|
148
|
+
shouldRenameProperty(property.key.name)) {
|
|
149
|
+
const oldName = property.key.name;
|
|
150
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[oldName];
|
|
151
|
+
property.key = j.identifier(newName);
|
|
152
|
+
if (!property.value) {
|
|
153
|
+
property.value = j.identifier(newName);
|
|
154
|
+
identifierRenames.push({ oldName, newName });
|
|
155
|
+
}
|
|
156
|
+
else if (property.value.type === 'Identifier') {
|
|
157
|
+
const localName = property.value.name;
|
|
158
|
+
if (localName === oldName) {
|
|
159
|
+
property.value = j.identifier(newName);
|
|
160
|
+
identifierRenames.push({ oldName, newName });
|
|
161
|
+
}
|
|
162
|
+
else if (localName === newName) {
|
|
163
|
+
// Same alias name: { unstable_cacheTag: cacheTag } -> { cacheTag }
|
|
164
|
+
property.value = j.identifier(newName);
|
|
165
|
+
property.shorthand = true;
|
|
166
|
+
identifierRenames.push({ oldName, newName });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
hasChanges = true;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// Handle .then() chains: import('next/cache').then(({ unstable_cacheTag }) => ...)
|
|
176
|
+
root.find(j.CallExpression).forEach((path) => {
|
|
177
|
+
if (path.node.callee?.type === 'MemberExpression' &&
|
|
178
|
+
path.node.callee.property?.type === 'Identifier' &&
|
|
179
|
+
path.node.callee.property.name === 'then' &&
|
|
180
|
+
path.node.callee.object?.type === 'CallExpression' &&
|
|
181
|
+
path.node.callee.object.callee?.type === 'Import' &&
|
|
182
|
+
path.node.callee.object.arguments[0]?.type === 'StringLiteral' &&
|
|
183
|
+
path.node.callee.object.arguments[0].value === 'next/cache' &&
|
|
184
|
+
path.node.arguments.length > 0) {
|
|
185
|
+
const callback = path.node.arguments[0];
|
|
186
|
+
let params = null;
|
|
187
|
+
if (callback.type === 'ArrowFunctionExpression') {
|
|
188
|
+
params = callback.params;
|
|
189
|
+
}
|
|
190
|
+
else if (callback.type === 'FunctionExpression') {
|
|
191
|
+
params = callback.params;
|
|
192
|
+
}
|
|
193
|
+
if (params && params.length > 0 && params[0].type === 'ObjectPattern') {
|
|
194
|
+
params[0].properties?.forEach((property) => {
|
|
195
|
+
if (property.type === 'ObjectProperty' &&
|
|
196
|
+
property.key?.type === 'Identifier' &&
|
|
197
|
+
shouldRenameProperty(property.key.name)) {
|
|
198
|
+
const oldName = property.key.name;
|
|
199
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[oldName];
|
|
200
|
+
property.key = j.identifier(newName);
|
|
201
|
+
if (!property.value) {
|
|
202
|
+
property.value = j.identifier(newName);
|
|
203
|
+
identifierRenames.push({ oldName, newName });
|
|
204
|
+
}
|
|
205
|
+
else if (property.value.type === 'Identifier') {
|
|
206
|
+
const localName = property.value.name;
|
|
207
|
+
if (localName === oldName) {
|
|
208
|
+
property.value = j.identifier(newName);
|
|
209
|
+
identifierRenames.push({ oldName, newName });
|
|
210
|
+
}
|
|
211
|
+
else if (localName === newName) {
|
|
212
|
+
// Same alias name: { unstable_cacheTag: cacheTag } -> { cacheTag }
|
|
213
|
+
property.value = j.identifier(newName);
|
|
214
|
+
property.shorthand = true;
|
|
215
|
+
identifierRenames.push({ oldName, newName });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
hasChanges = true;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
// Handle member expressions
|
|
225
|
+
root.find(j.MemberExpression).forEach((path) => {
|
|
226
|
+
const node = path.node;
|
|
227
|
+
// Handle direct property access: require('next/cache').unstable_cacheTag
|
|
228
|
+
if (node.object?.type === 'CallExpression' &&
|
|
229
|
+
node.object.callee?.type === 'Identifier' &&
|
|
230
|
+
node.object.callee.name === 'require' &&
|
|
231
|
+
node.object.arguments[0]?.type === 'StringLiteral' &&
|
|
232
|
+
node.object.arguments[0].value === 'next/cache') {
|
|
233
|
+
if (node.computed &&
|
|
234
|
+
node.property?.type === 'StringLiteral' &&
|
|
235
|
+
shouldRenameProperty(node.property.value)) {
|
|
236
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[node.property.value];
|
|
237
|
+
node.property = j.stringLiteral(newName);
|
|
238
|
+
hasChanges = true;
|
|
239
|
+
}
|
|
240
|
+
else if (!node.computed &&
|
|
241
|
+
node.property?.type === 'Identifier' &&
|
|
242
|
+
shouldRenameProperty(node.property.name)) {
|
|
243
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[node.property.name];
|
|
244
|
+
node.property = j.identifier(newName);
|
|
245
|
+
hasChanges = true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Handle property access on cache variables: cache.unstable_cacheTag or cache['unstable_cacheTag']
|
|
249
|
+
if (node.object?.type === 'Identifier' &&
|
|
250
|
+
cacheVariables.has(node.object.name)) {
|
|
251
|
+
if (node.computed &&
|
|
252
|
+
node.property?.type === 'StringLiteral' &&
|
|
253
|
+
shouldRenameProperty(node.property.value)) {
|
|
254
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[node.property.value];
|
|
255
|
+
node.property = j.stringLiteral(newName);
|
|
256
|
+
hasChanges = true;
|
|
257
|
+
}
|
|
258
|
+
else if (!node.computed &&
|
|
259
|
+
node.property?.type === 'Identifier' &&
|
|
260
|
+
shouldRenameProperty(node.property.name)) {
|
|
261
|
+
const newName = UNSTABLE_TO_STABLE_MAPPING[node.property.name];
|
|
262
|
+
node.property = j.identifier(newName);
|
|
263
|
+
hasChanges = true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
// Apply all identifier renames with better scope awareness
|
|
268
|
+
identifierRenames.forEach(({ oldName, newName }) => {
|
|
269
|
+
root
|
|
270
|
+
.find(j.Identifier, { name: oldName })
|
|
271
|
+
.filter((identifierPath) => {
|
|
272
|
+
// Skip renaming declarations themselves
|
|
273
|
+
const parent = identifierPath.parent;
|
|
274
|
+
return !(parent.node.type === 'ImportSpecifier' ||
|
|
275
|
+
parent.node.type === 'ExportSpecifier' ||
|
|
276
|
+
(parent.node.type === 'ObjectProperty' &&
|
|
277
|
+
parent.node.key === identifierPath.node) ||
|
|
278
|
+
(parent.node.type === 'VariableDeclarator' &&
|
|
279
|
+
parent.node.id === identifierPath.node) ||
|
|
280
|
+
(parent.node.type === 'FunctionDeclaration' &&
|
|
281
|
+
parent.node.id === identifierPath.node) ||
|
|
282
|
+
(parent.node.type === 'Property' &&
|
|
283
|
+
parent.node.key === identifierPath.node &&
|
|
284
|
+
!parent.node.computed));
|
|
285
|
+
})
|
|
286
|
+
.forEach((identifierPath) => {
|
|
287
|
+
identifierPath.node.name = newName;
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
return hasChanges ? root.toSource(options) : file.source;
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
console.warn(`Failed to transform ${file.path}: ${error.message}`);
|
|
294
|
+
return file.source;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=remove-unstable-prefix.js.map
|