@next/codemod 15.0.0-canary.200 → 15.0.0-canary.201
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
|
@@ -110,6 +110,10 @@ async function runUpgrade(revision, options) {
|
|
|
110
110
|
console.log(` - React: v${installedReactVersion}`);
|
|
111
111
|
console.log(` - Next.js: v${installedNextVersion}`);
|
|
112
112
|
let shouldStayOnReact18 = false;
|
|
113
|
+
const usesAppDir = isUsingAppDir(process.cwd());
|
|
114
|
+
const usesPagesDir = isUsingPagesDir(process.cwd());
|
|
115
|
+
const isPureAppRouter = usesAppDir && !usesPagesDir;
|
|
116
|
+
const isMixedApp = usesPagesDir && usesAppDir;
|
|
113
117
|
if (
|
|
114
118
|
// From release v14.3.0-canary.45, Next.js expects the React version to be 19.0.0-beta.0
|
|
115
119
|
// If the user is on a version higher than this but is still on React 18, we ask them
|
|
@@ -119,11 +123,18 @@ async function runUpgrade(revision, options) {
|
|
|
119
123
|
// x-ref(PR): https://github.com/vercel/next.js/pull/65058
|
|
120
124
|
// x-ref(release): https://github.com/vercel/next.js/releases/tag/v14.3.0-canary.45
|
|
121
125
|
(0, compare_1.default)(targetNextVersion, '14.3.0-canary.45') >= 0 &&
|
|
122
|
-
installedReactVersion.startsWith('18')
|
|
126
|
+
installedReactVersion.startsWith('18') &&
|
|
127
|
+
// Pure App Router always uses React 19
|
|
128
|
+
// The mixed case is tricky to handle from a types perspective.
|
|
129
|
+
// We'll recommend to upgrade in the prompt but users can decide to try 18.
|
|
130
|
+
!isPureAppRouter) {
|
|
123
131
|
const shouldStayOnReact18Res = await (0, prompts_1.default)({
|
|
124
132
|
type: 'confirm',
|
|
125
133
|
name: 'shouldStayOnReact18',
|
|
126
|
-
message: `
|
|
134
|
+
message: `Do you prefer to stay on React 18?` +
|
|
135
|
+
(isMixedApp
|
|
136
|
+
? " Since you're using both pages/ and app/, we recommend upgrading React to use a consistent version throughout your app."
|
|
137
|
+
: ''),
|
|
127
138
|
initial: false,
|
|
128
139
|
active: 'Yes',
|
|
129
140
|
inactive: 'No',
|
|
@@ -296,6 +307,14 @@ function getInstalledReactVersion() {
|
|
|
296
307
|
});
|
|
297
308
|
}
|
|
298
309
|
}
|
|
310
|
+
function isUsingPagesDir(projectPath) {
|
|
311
|
+
return (fs_1.default.existsSync(path_1.default.resolve(projectPath, 'pages')) ||
|
|
312
|
+
fs_1.default.existsSync(path_1.default.resolve(projectPath, 'src/pages')));
|
|
313
|
+
}
|
|
314
|
+
function isUsingAppDir(projectPath) {
|
|
315
|
+
return (fs_1.default.existsSync(path_1.default.resolve(projectPath, 'app')) ||
|
|
316
|
+
fs_1.default.existsSync(path_1.default.resolve(projectPath, 'src/app')));
|
|
317
|
+
}
|
|
299
318
|
/*
|
|
300
319
|
* Heuristics are used to determine whether to Turbopack is enabled or not and
|
|
301
320
|
* to determine how to update the dev script.
|
package/package.json
CHANGED
|
@@ -155,7 +155,6 @@ function modifyTypes(paramTypeAnnotation, propsIdentifier, root, j) {
|
|
|
155
155
|
member.typeAnnotation.typeAnnotation &&
|
|
156
156
|
j.TSType.check(member.typeAnnotation.typeAnnotation)) {
|
|
157
157
|
member.typeAnnotation.typeAnnotation = j.tsTypeReference(j.identifier('Promise'), j.tsTypeParameterInstantiation([
|
|
158
|
-
// @ts-ignore
|
|
159
158
|
member.typeAnnotation.typeAnnotation,
|
|
160
159
|
]));
|
|
161
160
|
modified = true;
|
|
@@ -203,6 +202,42 @@ function modifyTypes(paramTypeAnnotation, propsIdentifier, root, j) {
|
|
|
203
202
|
});
|
|
204
203
|
}
|
|
205
204
|
}
|
|
205
|
+
// Deal with type aliases
|
|
206
|
+
if (foundTypes.typeAliases.length > 0) {
|
|
207
|
+
const typeAliasDeclaration = foundTypes.typeAliases[0];
|
|
208
|
+
if (j.TSTypeAliasDeclaration.check(typeAliasDeclaration)) {
|
|
209
|
+
const typeAlias = typeAliasDeclaration.typeAnnotation;
|
|
210
|
+
if (j.TSTypeLiteral.check(typeAlias) &&
|
|
211
|
+
typeAlias.members.length > 0) {
|
|
212
|
+
const typeLiteral = typeAlias;
|
|
213
|
+
typeLiteral.members.forEach((member) => {
|
|
214
|
+
if (j.TSPropertySignature.check(member) &&
|
|
215
|
+
j.Identifier.check(member.key) &&
|
|
216
|
+
utils_1.TARGET_PROP_NAMES.has(member.key.name)) {
|
|
217
|
+
// if it's already a Promise, don't wrap it again, return
|
|
218
|
+
if (member.typeAnnotation &&
|
|
219
|
+
member.typeAnnotation.typeAnnotation &&
|
|
220
|
+
member.typeAnnotation.typeAnnotation.type ===
|
|
221
|
+
'TSTypeReference' &&
|
|
222
|
+
member.typeAnnotation.typeAnnotation.typeName.type ===
|
|
223
|
+
'Identifier' &&
|
|
224
|
+
member.typeAnnotation.typeAnnotation.typeName.name ===
|
|
225
|
+
'Promise') {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// Wrap the prop type in Promise<>
|
|
229
|
+
if (member.typeAnnotation &&
|
|
230
|
+
j.TSTypeLiteral.check(member.typeAnnotation.typeAnnotation)) {
|
|
231
|
+
member.typeAnnotation.typeAnnotation = j.tsTypeReference(j.identifier('Promise'), j.tsTypeParameterInstantiation([
|
|
232
|
+
member.typeAnnotation.typeAnnotation,
|
|
233
|
+
]));
|
|
234
|
+
modified = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
206
241
|
}
|
|
207
242
|
}
|
|
208
243
|
propsIdentifier.typeAnnotation = paramTypeAnnotation;
|
|
@@ -303,9 +338,7 @@ function transformDynamicProps(source, _api, filePath) {
|
|
|
303
338
|
const awaited = awaitMemberAccessOfProp(argName, path, j);
|
|
304
339
|
modified ||= awaited;
|
|
305
340
|
}
|
|
306
|
-
|
|
307
|
-
modifyTypes(currentParam.typeAnnotation, propsIdentifier, root, j);
|
|
308
|
-
}
|
|
341
|
+
modified ||= modifyTypes(currentParam.typeAnnotation, propsIdentifier, root, j);
|
|
309
342
|
// cases of passing down `props` into any function
|
|
310
343
|
// Page(props) { callback(props) }
|
|
311
344
|
// search for all the argument of CallExpression, where currentParam is one of the arguments
|