@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/advanced-features/codemods) to view the documentation for this package.
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('--no-babel');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next/codemod",
3
- "version": "15.4.2-canary.3",
3
+ "version": "15.4.2-canary.30",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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 parsed = (0, path_1.parse)(file.path || '/');
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 result = nextConfigTransformer(j, root, parsed.dir);
202
- return result.toSource();
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"