@next/codemod 15.4.2-canary.3 → 15.4.2-canary.30
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
|
@@ -6,4 +6,4 @@ Codemods are transformations that run on your codebase programmatically. This al
|
|
|
6
6
|
|
|
7
7
|
## Documentation
|
|
8
8
|
|
|
9
|
-
Visit [nextjs.org/docs/advanced-features/codemods](https://nextjs.org/docs/
|
|
9
|
+
Visit [nextjs.org/docs/advanced-features/codemods](https://nextjs.org/docs/app/guides/upgrading/codemods) to view the documentation for this package.
|
package/bin/transform.js
CHANGED
|
@@ -92,7 +92,7 @@ async function runTransform(transform, path, options) {
|
|
|
92
92
|
if (verbose) {
|
|
93
93
|
args.push('--verbose=2');
|
|
94
94
|
}
|
|
95
|
-
args.push('--
|
|
95
|
+
args.push('--parser=tsx');
|
|
96
96
|
args.push('--ignore-pattern=**/node_modules/**');
|
|
97
97
|
args.push('--ignore-pattern=**/.next/**');
|
|
98
98
|
args.push('--extensions=tsx,ts,jsx,js');
|
package/lib/utils.js
CHANGED
|
@@ -106,5 +106,10 @@ exports.TRANSFORMER_INQUIRER_CHOICES = [
|
|
|
106
106
|
value: 'app-dir-runtime-config-experimental-edge',
|
|
107
107
|
version: '15.0.0-canary.179',
|
|
108
108
|
},
|
|
109
|
+
{
|
|
110
|
+
title: 'Updates `next.config.js` to use the new `turbopack` configuration',
|
|
111
|
+
value: 'next-experimental-turbo-to-turbopack',
|
|
112
|
+
version: '10.0.0',
|
|
113
|
+
},
|
|
109
114
|
];
|
|
110
115
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isNextConfigFile = isNextConfigFile;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
function isNextConfigFile(file) {
|
|
9
|
+
const parsed = node_path_1.default.parse(file.path || '/');
|
|
10
|
+
return (parsed.base === 'next.config.js' ||
|
|
11
|
+
parsed.base === 'next.config.ts' ||
|
|
12
|
+
parsed.base === 'next.config.mjs' ||
|
|
13
|
+
parsed.base === 'next.config.cjs');
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* This codemod transforms the experimental turbo configuration in Next.js config to
|
|
4
|
+
* the new top-level `turbopack` configuration.
|
|
5
|
+
*
|
|
6
|
+
* It moves most properties from experimental.turbo to the top-level turbopack
|
|
7
|
+
* property, with special handling for certain properties like memoryLimit, minify,
|
|
8
|
+
* treeShaking, and sourceMaps which become experimental.turbopack* properties instead.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.default = transformer;
|
|
12
|
+
const parser_1 = require("../lib/parser");
|
|
13
|
+
const utils_1 = require("./lib/utils");
|
|
14
|
+
// Properties that need to be moved to experimental.turbopack*
|
|
15
|
+
const RENAMED_EXPERIMENTAL_PROPERTIES = {
|
|
16
|
+
memoryLimit: 'turbopackMemoryLimit',
|
|
17
|
+
minify: 'turbopackMinify',
|
|
18
|
+
treeShaking: 'turbopackTreeShaking',
|
|
19
|
+
sourceMaps: 'turbopackSourceMaps',
|
|
20
|
+
};
|
|
21
|
+
function transformer(file, _api, options) {
|
|
22
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
23
|
+
const root = j(file.source);
|
|
24
|
+
let hasChanges = false;
|
|
25
|
+
if (!(0, utils_1.isNextConfigFile)(file) &&
|
|
26
|
+
process.env.NODE_ENV !== 'test' // fixtures have unique basenames in test
|
|
27
|
+
) {
|
|
28
|
+
return file.source;
|
|
29
|
+
}
|
|
30
|
+
// Process a config object once we find it
|
|
31
|
+
function processConfigObject(configObj) {
|
|
32
|
+
// Check for `experimental` property in the config
|
|
33
|
+
const experimentalProp = configObj.properties.find((prop) => isStaticProperty(prop) &&
|
|
34
|
+
prop.key &&
|
|
35
|
+
prop.key.type === 'Identifier' &&
|
|
36
|
+
prop.key.name === 'experimental');
|
|
37
|
+
if (!experimentalProp || !isStaticProperty(experimentalProp)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const experimentalObj = experimentalProp.value;
|
|
41
|
+
if (experimentalObj.type !== 'ObjectExpression') {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// Check for `experimental.turbo` property in the config
|
|
45
|
+
const turboProp = experimentalObj.properties.find((prop) => isStaticProperty(prop) &&
|
|
46
|
+
prop.key &&
|
|
47
|
+
prop.key.type === 'Identifier' &&
|
|
48
|
+
prop.key.name === 'turbo');
|
|
49
|
+
if (!turboProp || !isStaticProperty(turboProp)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const turboObj = turboProp.value;
|
|
53
|
+
if (turboObj.type !== 'ObjectExpression') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const regularProps = [];
|
|
57
|
+
const specialProps = [];
|
|
58
|
+
turboObj.properties.forEach((prop) => {
|
|
59
|
+
if (isStaticProperty(prop) &&
|
|
60
|
+
prop.key &&
|
|
61
|
+
prop.key.type === 'Identifier' &&
|
|
62
|
+
RENAMED_EXPERIMENTAL_PROPERTIES[prop.key.name]) {
|
|
63
|
+
// Create a new property with the renamed key
|
|
64
|
+
specialProps.push(j.objectProperty(j.identifier(RENAMED_EXPERIMENTAL_PROPERTIES[prop.key.name]), prop.value));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Keep the property for turbopack
|
|
68
|
+
regularProps.push(prop);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
const existingProps = experimentalObj.properties.filter((prop) => !(isStaticProperty(prop) &&
|
|
72
|
+
prop.key &&
|
|
73
|
+
prop.key.type === 'Identifier' &&
|
|
74
|
+
prop.key.name === 'turbo'));
|
|
75
|
+
experimentalObj.properties = [...existingProps, ...specialProps];
|
|
76
|
+
// If experimental has no properties, remove it
|
|
77
|
+
if (experimentalObj.properties.length === 0) {
|
|
78
|
+
configObj.properties = configObj.properties.filter((prop) => !(isStaticProperty(prop) &&
|
|
79
|
+
prop.key &&
|
|
80
|
+
prop.key.type === 'Identifier' &&
|
|
81
|
+
prop.key.name === 'experimental'));
|
|
82
|
+
}
|
|
83
|
+
// Add turbopack property at top level if there are regular props
|
|
84
|
+
if (regularProps.length > 0) {
|
|
85
|
+
// Create the turbopack property
|
|
86
|
+
const turbopackProp = j.objectProperty(j.identifier('turbopack'), j.objectExpression(regularProps));
|
|
87
|
+
configObj.properties.push(turbopackProp);
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
root.find(j.ObjectExpression).forEach((path) => {
|
|
92
|
+
if (processConfigObject(path.value)) {
|
|
93
|
+
hasChanges = true;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// Transform config.experimental.turbo.X = value to config.turbopack.X = value
|
|
97
|
+
// or config.experimental.turbopackX = value for special properties
|
|
98
|
+
root
|
|
99
|
+
.find(j.AssignmentExpression, {
|
|
100
|
+
left: {
|
|
101
|
+
type: 'MemberExpression',
|
|
102
|
+
object: {
|
|
103
|
+
type: 'MemberExpression',
|
|
104
|
+
object: {
|
|
105
|
+
type: 'MemberExpression',
|
|
106
|
+
property: { type: 'Identifier', name: 'experimental' },
|
|
107
|
+
},
|
|
108
|
+
property: { type: 'Identifier', name: 'turbo' },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
.forEach((path) => {
|
|
113
|
+
if (path.node.left.type !== 'MemberExpression')
|
|
114
|
+
return;
|
|
115
|
+
// Get the variable name (e.g., config in config.experimental.turbo.sourceMaps)
|
|
116
|
+
let varName = null;
|
|
117
|
+
let currentPath = path.node.left.object;
|
|
118
|
+
while (currentPath?.type === 'MemberExpression') {
|
|
119
|
+
currentPath = currentPath.object;
|
|
120
|
+
}
|
|
121
|
+
if (currentPath?.type === 'Identifier') {
|
|
122
|
+
varName = currentPath.name;
|
|
123
|
+
}
|
|
124
|
+
if (!varName)
|
|
125
|
+
return;
|
|
126
|
+
// Get the property name being assigned (e.g., sourceMaps)
|
|
127
|
+
let propName = undefined;
|
|
128
|
+
if (path.node.left.property &&
|
|
129
|
+
path.node.left.property.type === 'Identifier') {
|
|
130
|
+
propName = path.node.left.property.name;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// For special properties like memoryLimit, minify, etc.
|
|
136
|
+
if (propName && RENAMED_EXPERIMENTAL_PROPERTIES[propName]) {
|
|
137
|
+
const newAssignment = j.assignmentExpression('=', j.memberExpression(j.memberExpression(j.identifier(varName), j.identifier('experimental')), j.identifier(RENAMED_EXPERIMENTAL_PROPERTIES[propName])), path.node.right);
|
|
138
|
+
j(path).replaceWith(newAssignment);
|
|
139
|
+
hasChanges = true;
|
|
140
|
+
}
|
|
141
|
+
else if (propName) {
|
|
142
|
+
// Create new assignment: config.turbopack.propName = value
|
|
143
|
+
const newAssignment = j.assignmentExpression('=', j.memberExpression(j.memberExpression(j.identifier(varName), j.identifier('turbopack')), j.identifier(propName)), path.node.right);
|
|
144
|
+
j(path).replaceWith(newAssignment);
|
|
145
|
+
hasChanges = true;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
// For nested property assignments like config.experimental.turbo.resolveAlias.foo = 'bar';
|
|
149
|
+
root.find(j.AssignmentExpression).forEach((path) => {
|
|
150
|
+
if (path.node.left.type !== 'MemberExpression')
|
|
151
|
+
return;
|
|
152
|
+
// Build a path to check if this is like `experimental.turbo.resolveAlias.foo`
|
|
153
|
+
let obj = path.node.left.object;
|
|
154
|
+
let props = [];
|
|
155
|
+
// Collect the property chain
|
|
156
|
+
while (obj && obj.type === 'MemberExpression') {
|
|
157
|
+
if (obj.property && obj.property.type === 'Identifier') {
|
|
158
|
+
props.unshift(obj.property.name);
|
|
159
|
+
}
|
|
160
|
+
obj = obj.object;
|
|
161
|
+
}
|
|
162
|
+
// Get the root variable name (e.g., 'config')
|
|
163
|
+
let varName = null;
|
|
164
|
+
if (obj && obj.type === 'Identifier') {
|
|
165
|
+
varName = obj.name;
|
|
166
|
+
}
|
|
167
|
+
if (!varName)
|
|
168
|
+
return;
|
|
169
|
+
// Check if this matches the pattern: config.experimental.turbo.resolveAlias.foo
|
|
170
|
+
if (props.length >= 3 &&
|
|
171
|
+
props[0] === 'experimental' &&
|
|
172
|
+
props[1] === 'turbo') {
|
|
173
|
+
// Get the final property name, only if it's an Identifier
|
|
174
|
+
let finalProp = undefined;
|
|
175
|
+
if (path.node.left.property &&
|
|
176
|
+
path.node.left.property.type === 'Identifier') {
|
|
177
|
+
finalProp = path.node.left.property.name;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// If not an Identifier, skip this assignment
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// The properties after 'turbo'
|
|
184
|
+
const middleProps = props.slice(2); // e.g. ['resolveAlias']
|
|
185
|
+
// Start building the new left side: config.turbopack
|
|
186
|
+
let newLeft = j.memberExpression(j.identifier(varName), j.identifier('turbopack'));
|
|
187
|
+
// Add the middle properties
|
|
188
|
+
for (const prop of middleProps) {
|
|
189
|
+
newLeft = j.memberExpression(newLeft, j.identifier(prop));
|
|
190
|
+
}
|
|
191
|
+
// Add the final property
|
|
192
|
+
newLeft = j.memberExpression(newLeft, j.identifier(finalProp));
|
|
193
|
+
const newAssignment = j.assignmentExpression('=', newLeft, path.node.right);
|
|
194
|
+
j(path).replaceWith(newAssignment);
|
|
195
|
+
hasChanges = true;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
// Only return a string if we changed the AST, otherwise return the original source
|
|
199
|
+
return hasChanges ? root.toSource(options) : file.source;
|
|
200
|
+
}
|
|
201
|
+
function isStaticProperty(prop) {
|
|
202
|
+
return prop.type === 'Property' || prop.type === 'ObjectProperty';
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=next-experimental-turbo-to-turbopack.js.map
|
|
@@ -4,6 +4,7 @@ exports.default = transformer;
|
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
6
|
const parser_1 = require("../lib/parser");
|
|
7
|
+
const utils_1 = require("./lib/utils");
|
|
7
8
|
function findAndReplaceProps(j, root, tagName) {
|
|
8
9
|
const layoutToStyle = {
|
|
9
10
|
intrinsic: { maxWidth: '100%', height: 'auto' },
|
|
@@ -192,14 +193,11 @@ function nextConfigTransformer(j, root, appDir) {
|
|
|
192
193
|
function transformer(file, _api, options) {
|
|
193
194
|
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
194
195
|
const root = j(file.source);
|
|
195
|
-
const
|
|
196
|
-
const isConfig = parsed.base === 'next.config.js' ||
|
|
197
|
-
parsed.base === 'next.config.ts' ||
|
|
198
|
-
parsed.base === 'next.config.mjs' ||
|
|
199
|
-
parsed.base === 'next.config.cjs';
|
|
196
|
+
const isConfig = (0, utils_1.isNextConfigFile)(file);
|
|
200
197
|
if (isConfig) {
|
|
201
|
-
const
|
|
202
|
-
|
|
198
|
+
const fileDir = (0, path_1.parse)(file.path).dir;
|
|
199
|
+
const result = nextConfigTransformer(j, root, fileDir);
|
|
200
|
+
return result.toSource(options);
|
|
203
201
|
}
|
|
204
202
|
// Before: import Image from "next/legacy/image"
|
|
205
203
|
// After: import Image from "next/image"
|