@next/codemod 15.0.0-rc.0 → 15.0.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/next-codemod.js +55 -3
- package/bin/shared.js +7 -0
- package/bin/transform.js +124 -0
- package/bin/upgrade.js +473 -0
- package/lib/cra-to-next/global-css-transform.js +5 -5
- package/lib/cra-to-next/index-to-component.js +5 -5
- package/lib/handle-package.js +110 -0
- package/lib/install.js +2 -3
- package/lib/parser.js +28 -0
- package/lib/run-jscodeshift.js +18 -2
- package/lib/utils.js +115 -0
- package/package.json +15 -7
- package/transforms/add-missing-react-import.js +4 -3
- package/transforms/app-dir-runtime-config-experimental-edge.js +34 -0
- package/transforms/built-in-next-font.js +4 -3
- package/transforms/cra-to-next.js +238 -236
- package/transforms/lib/async-request-api/index.js +16 -0
- package/transforms/lib/async-request-api/next-async-dynamic-api.js +284 -0
- package/transforms/lib/async-request-api/next-async-dynamic-prop.js +713 -0
- package/transforms/lib/async-request-api/utils.js +473 -0
- package/transforms/metadata-to-viewport-export.js +4 -3
- package/transforms/name-default-component.js +6 -6
- package/transforms/new-link.js +9 -7
- package/transforms/next-async-request-api.js +9 -0
- package/transforms/next-dynamic-access-named-export.js +66 -0
- package/transforms/next-image-experimental.js +12 -15
- package/transforms/next-image-to-legacy-image.js +8 -9
- package/transforms/next-og-import.js +4 -3
- package/transforms/next-request-geo-ip.js +339 -0
- package/transforms/url-to-withrouter.js +1 -1
- package/transforms/withamp-to-config.js +1 -1
- package/bin/cli.js +0 -216
- package/lib/uninstall-package.js +0 -32
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isReactHookName = exports.TARGET_PROP_NAMES = exports.TARGET_NAMED_EXPORTS = exports.TARGET_ROUTE_EXPORTS = exports.NEXT_CODEMOD_ERROR_PREFIX = exports.NEXTJS_ENTRY_FILES = void 0;
|
|
4
|
+
exports.isFunctionType = isFunctionType;
|
|
5
|
+
exports.isMatchedFunctionExported = isMatchedFunctionExported;
|
|
6
|
+
exports.determineClientDirective = determineClientDirective;
|
|
7
|
+
exports.isPromiseType = isPromiseType;
|
|
8
|
+
exports.turnFunctionReturnTypeToAsync = turnFunctionReturnTypeToAsync;
|
|
9
|
+
exports.insertReactUseImport = insertReactUseImport;
|
|
10
|
+
exports.generateUniqueIdentifier = generateUniqueIdentifier;
|
|
11
|
+
exports.isFunctionScope = isFunctionScope;
|
|
12
|
+
exports.findClosetParentFunctionScope = findClosetParentFunctionScope;
|
|
13
|
+
exports.getFunctionPathFromExportPath = getFunctionPathFromExportPath;
|
|
14
|
+
exports.wrapParentheseIfNeeded = wrapParentheseIfNeeded;
|
|
15
|
+
exports.insertCommentOnce = insertCommentOnce;
|
|
16
|
+
exports.getVariableDeclaratorId = getVariableDeclaratorId;
|
|
17
|
+
exports.findFunctionBody = findFunctionBody;
|
|
18
|
+
exports.containsReactHooksCallExpressions = containsReactHooksCallExpressions;
|
|
19
|
+
exports.isParentUseCallExpression = isParentUseCallExpression;
|
|
20
|
+
exports.isParentPromiseAllCallExpression = isParentPromiseAllCallExpression;
|
|
21
|
+
exports.NEXTJS_ENTRY_FILES = /([\\/]|^)(page|layout|route|default)\.(t|j)sx?$/;
|
|
22
|
+
exports.NEXT_CODEMOD_ERROR_PREFIX = '@next-codemod-error';
|
|
23
|
+
const NEXT_CODEMOD_IGNORE_ERROR_PREFIX = '@next-codemod-ignore';
|
|
24
|
+
exports.TARGET_ROUTE_EXPORTS = new Set([
|
|
25
|
+
'GET',
|
|
26
|
+
'POST',
|
|
27
|
+
'PUT',
|
|
28
|
+
'PATCH',
|
|
29
|
+
'DELETE',
|
|
30
|
+
'OPTIONS',
|
|
31
|
+
'HEAD',
|
|
32
|
+
]);
|
|
33
|
+
exports.TARGET_NAMED_EXPORTS = new Set([
|
|
34
|
+
// For page and layout
|
|
35
|
+
'generateMetadata',
|
|
36
|
+
'generateViewport',
|
|
37
|
+
...exports.TARGET_ROUTE_EXPORTS,
|
|
38
|
+
]);
|
|
39
|
+
exports.TARGET_PROP_NAMES = new Set(['params', 'searchParams']);
|
|
40
|
+
function isFunctionType(type) {
|
|
41
|
+
return (type === 'FunctionDeclaration' ||
|
|
42
|
+
type === 'FunctionExpression' ||
|
|
43
|
+
type === 'ArrowFunctionExpression');
|
|
44
|
+
}
|
|
45
|
+
function isMatchedFunctionExported(path, j) {
|
|
46
|
+
const matchedFunctionNameFilter = (idName) => exports.TARGET_NAMED_EXPORTS.has(idName);
|
|
47
|
+
const directNamedExport = j(path).closest(j.ExportNamedDeclaration, {
|
|
48
|
+
declaration: {
|
|
49
|
+
type: 'FunctionDeclaration',
|
|
50
|
+
id: {
|
|
51
|
+
name: matchedFunctionNameFilter,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
if (directNamedExport.size() > 0) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
// Check for default export (`export default function() {}`)
|
|
59
|
+
const isDefaultExport = j(path).closest(j.ExportDefaultDeclaration).size() > 0;
|
|
60
|
+
if (isDefaultExport) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// Look for named export elsewhere in the file (`export { <named> }`)
|
|
64
|
+
const root = j(path).closestScope().closest(j.Program);
|
|
65
|
+
const isNamedExport = root
|
|
66
|
+
.find(j.ExportNamedDeclaration, {
|
|
67
|
+
specifiers: [
|
|
68
|
+
{
|
|
69
|
+
type: 'ExportSpecifier',
|
|
70
|
+
exported: {
|
|
71
|
+
name: matchedFunctionNameFilter,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
})
|
|
76
|
+
.size() > 0;
|
|
77
|
+
// Look for variable export but still function, e.g. `export const <named> = function() {}`,
|
|
78
|
+
// also check if variable is a function or arrow function
|
|
79
|
+
const isVariableExport = root
|
|
80
|
+
.find(j.ExportNamedDeclaration, {
|
|
81
|
+
declaration: {
|
|
82
|
+
declarations: [
|
|
83
|
+
{
|
|
84
|
+
type: 'VariableDeclarator',
|
|
85
|
+
id: {
|
|
86
|
+
type: 'Identifier',
|
|
87
|
+
name: matchedFunctionNameFilter,
|
|
88
|
+
},
|
|
89
|
+
init: {
|
|
90
|
+
type: isFunctionType,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
.size() > 0;
|
|
97
|
+
if (isVariableExport)
|
|
98
|
+
return true;
|
|
99
|
+
return isNamedExport;
|
|
100
|
+
}
|
|
101
|
+
// directive is not parsed into AST, so we need to manually find it
|
|
102
|
+
// by going through the tokens. Use the 1st string token as the directive
|
|
103
|
+
function determineClientDirective(root, j) {
|
|
104
|
+
const { program } = root.get().node;
|
|
105
|
+
const directive = program.directives[0];
|
|
106
|
+
if (j.Directive.check(directive)) {
|
|
107
|
+
return directive.value.value === 'use client';
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function isPromiseType(typeAnnotation) {
|
|
112
|
+
return (typeAnnotation.type === 'TSTypeReference' &&
|
|
113
|
+
typeAnnotation.typeName.name === 'Promise');
|
|
114
|
+
}
|
|
115
|
+
function turnFunctionReturnTypeToAsync(node, j) {
|
|
116
|
+
if (j.FunctionDeclaration.check(node) ||
|
|
117
|
+
j.FunctionExpression.check(node) ||
|
|
118
|
+
j.ArrowFunctionExpression.check(node)) {
|
|
119
|
+
if (node.returnType) {
|
|
120
|
+
const returnTypeAnnotation = node.returnType.typeAnnotation;
|
|
121
|
+
const isReturnTypePromise = isPromiseType(returnTypeAnnotation);
|
|
122
|
+
// Turn <return type> to Promise<return type>
|
|
123
|
+
// e.g. () => { slug: string } to () => Promise<{ slug: string }>
|
|
124
|
+
// e.g. Anything to Promise<Anything>
|
|
125
|
+
if (!isReturnTypePromise) {
|
|
126
|
+
if (node.returnType &&
|
|
127
|
+
j.TSTypeAnnotation.check(node.returnType) &&
|
|
128
|
+
(j.TSTypeReference.check(node.returnType.typeAnnotation) ||
|
|
129
|
+
j.TSUnionType.check(node.returnType.typeAnnotation) ||
|
|
130
|
+
j.TSTypePredicate.check(node.returnType.typeAnnotation))) {
|
|
131
|
+
// Change the return type to Promise<void>
|
|
132
|
+
node.returnType.typeAnnotation = j.tsTypeReference(j.identifier('Promise'),
|
|
133
|
+
// @ts-ignore ignore the super strict type checking on the type annotation
|
|
134
|
+
j.tsTypeParameterInstantiation([returnTypeAnnotation]));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function insertReactUseImport(root, j) {
|
|
141
|
+
const hasReactUseImport = root
|
|
142
|
+
.find(j.ImportSpecifier, {
|
|
143
|
+
imported: {
|
|
144
|
+
type: 'Identifier',
|
|
145
|
+
name: 'use',
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
.size() > 0;
|
|
149
|
+
if (!hasReactUseImport) {
|
|
150
|
+
const reactImportDeclaration = root.find(j.ImportDeclaration, {
|
|
151
|
+
source: {
|
|
152
|
+
value: 'react',
|
|
153
|
+
},
|
|
154
|
+
// Skip the type only react imports
|
|
155
|
+
importKind: 'value',
|
|
156
|
+
});
|
|
157
|
+
if (reactImportDeclaration.size() > 0) {
|
|
158
|
+
const importNode = reactImportDeclaration.get().node;
|
|
159
|
+
// Add 'use' to existing 'react' import declaration
|
|
160
|
+
importNode.specifiers.push(j.importSpecifier(j.identifier('use')));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Final all type imports to 'react'
|
|
164
|
+
if (reactImportDeclaration.size() > 0) {
|
|
165
|
+
reactImportDeclaration
|
|
166
|
+
.get()
|
|
167
|
+
.node.specifiers.push(j.importSpecifier(j.identifier('use')));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Add new import declaration for 'react' and 'use'
|
|
171
|
+
root
|
|
172
|
+
.get()
|
|
173
|
+
.node.program.body.unshift(j.importDeclaration([j.importSpecifier(j.identifier('use'))], j.literal('react')));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function findSubScopeArgumentIdentifier(path, j, argName) {
|
|
179
|
+
const defCount = j(path).find(j.Identifier, { name: argName }).size();
|
|
180
|
+
return defCount > 0;
|
|
181
|
+
}
|
|
182
|
+
function generateUniqueIdentifier(defaultIdName, path, j) {
|
|
183
|
+
let idName = defaultIdName;
|
|
184
|
+
let idNameSuffix = 0;
|
|
185
|
+
while (findSubScopeArgumentIdentifier(path, j, idName)) {
|
|
186
|
+
idName = defaultIdName + idNameSuffix;
|
|
187
|
+
idNameSuffix++;
|
|
188
|
+
}
|
|
189
|
+
const propsIdentifier = j.identifier(idName);
|
|
190
|
+
return propsIdentifier;
|
|
191
|
+
}
|
|
192
|
+
function isFunctionScope(path, j) {
|
|
193
|
+
if (!path)
|
|
194
|
+
return false;
|
|
195
|
+
const node = path.node;
|
|
196
|
+
// Check if the node is a function (declaration, expression, or arrow function)
|
|
197
|
+
return (j.FunctionDeclaration.check(node) ||
|
|
198
|
+
j.FunctionExpression.check(node) ||
|
|
199
|
+
j.ArrowFunctionExpression.check(node));
|
|
200
|
+
}
|
|
201
|
+
function findClosetParentFunctionScope(path, j) {
|
|
202
|
+
let parentFunctionPath = path.scope.path;
|
|
203
|
+
while (parentFunctionPath && !isFunctionScope(parentFunctionPath, j)) {
|
|
204
|
+
parentFunctionPath = parentFunctionPath.parent;
|
|
205
|
+
}
|
|
206
|
+
return parentFunctionPath;
|
|
207
|
+
}
|
|
208
|
+
function getFunctionNodeFromBinding(bindingPath, idName, j, root) {
|
|
209
|
+
const bindingNode = bindingPath.node;
|
|
210
|
+
if (j.FunctionDeclaration.check(bindingNode) ||
|
|
211
|
+
j.FunctionExpression.check(bindingNode) ||
|
|
212
|
+
j.ArrowFunctionExpression.check(bindingNode)) {
|
|
213
|
+
return bindingPath;
|
|
214
|
+
}
|
|
215
|
+
else if (j.VariableDeclarator.check(bindingNode)) {
|
|
216
|
+
const init = bindingNode.init;
|
|
217
|
+
// If the initializer is a function (arrow or function expression), record it
|
|
218
|
+
if (j.FunctionExpression.check(init) ||
|
|
219
|
+
j.ArrowFunctionExpression.check(init)) {
|
|
220
|
+
return bindingPath.get('init');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else if (j.Identifier.check(bindingNode)) {
|
|
224
|
+
const variablePath = root.find(j.VariableDeclaration, {
|
|
225
|
+
// declarations, each is VariableDeclarator
|
|
226
|
+
declarations: [
|
|
227
|
+
{
|
|
228
|
+
// VariableDeclarator
|
|
229
|
+
type: 'VariableDeclarator',
|
|
230
|
+
// id is Identifier
|
|
231
|
+
id: {
|
|
232
|
+
type: 'Identifier',
|
|
233
|
+
name: idName,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
if (variablePath.size()) {
|
|
239
|
+
const variableDeclarator = variablePath.get()?.node?.declarations?.[0];
|
|
240
|
+
if (j.VariableDeclarator.check(variableDeclarator)) {
|
|
241
|
+
const init = variableDeclarator.init;
|
|
242
|
+
if (j.FunctionExpression.check(init) ||
|
|
243
|
+
j.ArrowFunctionExpression.check(init)) {
|
|
244
|
+
return variablePath.get('declarations', 0, 'init');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const functionDeclarations = root.find(j.FunctionDeclaration, {
|
|
249
|
+
id: {
|
|
250
|
+
name: idName,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
if (functionDeclarations.size()) {
|
|
254
|
+
return functionDeclarations.get();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
function getFunctionPathFromExportPath(exportPath, j, root, namedExportFilter) {
|
|
260
|
+
// Default export
|
|
261
|
+
if (j.ExportDefaultDeclaration.check(exportPath.node)) {
|
|
262
|
+
const { declaration } = exportPath.node;
|
|
263
|
+
if (declaration) {
|
|
264
|
+
if (j.FunctionDeclaration.check(declaration) ||
|
|
265
|
+
j.FunctionExpression.check(declaration) ||
|
|
266
|
+
j.ArrowFunctionExpression.check(declaration)) {
|
|
267
|
+
return exportPath.get('declaration');
|
|
268
|
+
}
|
|
269
|
+
else if (j.Identifier.check(declaration)) {
|
|
270
|
+
const idName = declaration.name;
|
|
271
|
+
if (!namedExportFilter(idName))
|
|
272
|
+
return;
|
|
273
|
+
const exportBinding = exportPath.scope.getBindings()[idName]?.[0];
|
|
274
|
+
if (exportBinding) {
|
|
275
|
+
return getFunctionNodeFromBinding(exportBinding, idName, j, root);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else if (
|
|
281
|
+
// Named exports
|
|
282
|
+
j.ExportNamedDeclaration.check(exportPath.node)) {
|
|
283
|
+
const namedExportPath = exportPath;
|
|
284
|
+
// extract the named exports, name specifiers, and default specifiers
|
|
285
|
+
const { declaration, specifiers } = namedExportPath.node;
|
|
286
|
+
if (declaration) {
|
|
287
|
+
if (j.VariableDeclaration.check(declaration)) {
|
|
288
|
+
const { declarations } = declaration;
|
|
289
|
+
for (const decl of declarations) {
|
|
290
|
+
if (j.VariableDeclarator.check(decl) && j.Identifier.check(decl.id)) {
|
|
291
|
+
const idName = decl.id.name;
|
|
292
|
+
if (!namedExportFilter(idName))
|
|
293
|
+
return;
|
|
294
|
+
// get bindings for each variable declarator
|
|
295
|
+
const exportBinding = namedExportPath.scope.getBindings()[idName]?.[0];
|
|
296
|
+
if (exportBinding) {
|
|
297
|
+
return getFunctionNodeFromBinding(exportBinding, idName, j, root);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else if (j.FunctionDeclaration.check(declaration) ||
|
|
303
|
+
j.FunctionExpression.check(declaration) ||
|
|
304
|
+
j.ArrowFunctionExpression.check(declaration)) {
|
|
305
|
+
const funcName = declaration.id?.name;
|
|
306
|
+
if (!namedExportFilter(funcName))
|
|
307
|
+
return;
|
|
308
|
+
return namedExportPath.get('declaration');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (specifiers) {
|
|
312
|
+
for (const specifier of specifiers) {
|
|
313
|
+
if (j.ExportSpecifier.check(specifier)) {
|
|
314
|
+
const idName = specifier.local.name;
|
|
315
|
+
if (!namedExportFilter(idName))
|
|
316
|
+
return;
|
|
317
|
+
const exportBinding = namedExportPath.scope.getBindings()[idName]?.[0];
|
|
318
|
+
if (exportBinding) {
|
|
319
|
+
return getFunctionNodeFromBinding(exportBinding, idName, j, root);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
function wrapParentheseIfNeeded(hasChainAccess, j, expression) {
|
|
328
|
+
return hasChainAccess ? j.parenthesizedExpression(expression) : expression;
|
|
329
|
+
}
|
|
330
|
+
function existsComment(comments, comment) {
|
|
331
|
+
const isCodemodErrorComment = comment
|
|
332
|
+
.trim()
|
|
333
|
+
.startsWith(exports.NEXT_CODEMOD_ERROR_PREFIX);
|
|
334
|
+
let hasIgnoreComment = false;
|
|
335
|
+
let hasComment = false;
|
|
336
|
+
if (comments) {
|
|
337
|
+
comments.forEach((commentNode) => {
|
|
338
|
+
const currentComment = commentNode.value;
|
|
339
|
+
if (currentComment.trim().startsWith(NEXT_CODEMOD_IGNORE_ERROR_PREFIX)) {
|
|
340
|
+
hasIgnoreComment = true;
|
|
341
|
+
}
|
|
342
|
+
if (currentComment === comment) {
|
|
343
|
+
hasComment = true;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
// If it's inserting codemod error comment,
|
|
347
|
+
// check if there's already a @next-codemod-ignore comment.
|
|
348
|
+
// if ignore comment exists, bypass the comment insertion.
|
|
349
|
+
if (hasIgnoreComment && isCodemodErrorComment) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
if (hasComment) {
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
function insertCommentOnce(node, j, comment) {
|
|
359
|
+
const hasCommentInInlineComments = existsComment(node.comments, comment);
|
|
360
|
+
const hasCommentInLeadingComments = existsComment(node.leadingComments, comment);
|
|
361
|
+
if (!hasCommentInInlineComments && !hasCommentInLeadingComments) {
|
|
362
|
+
// Always insert into inline comment
|
|
363
|
+
node.comments = [j.commentBlock(comment), ...(node.comments || [])];
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
function getVariableDeclaratorId(path, j) {
|
|
369
|
+
const parent = path.parentPath;
|
|
370
|
+
if (j.VariableDeclarator.check(parent.node)) {
|
|
371
|
+
const id = parent.node.id;
|
|
372
|
+
if (j.Identifier.check(id)) {
|
|
373
|
+
return id;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
function findFunctionBody(path) {
|
|
379
|
+
let functionBody = path.node.body;
|
|
380
|
+
if (functionBody && functionBody.type === 'BlockStatement') {
|
|
381
|
+
return functionBody.body;
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
const isPascalCase = (s) => /^[A-Z][a-z0-9]*$/.test(s);
|
|
386
|
+
const isReactHookName = (name) =>
|
|
387
|
+
// function name is `use`
|
|
388
|
+
name === 'use' ||
|
|
389
|
+
// function name is `useX*`
|
|
390
|
+
(name.startsWith('use') && name[3] === name[3].toUpperCase());
|
|
391
|
+
exports.isReactHookName = isReactHookName;
|
|
392
|
+
// Determine a path of function contains any React hooks call expressions.
|
|
393
|
+
// e.g. if there's any of those call expressions in the function body:
|
|
394
|
+
// use() => true
|
|
395
|
+
// React.use() => false
|
|
396
|
+
// useXxxx() => true
|
|
397
|
+
// Foo.use() => true
|
|
398
|
+
// Foo.useXxxx() => true
|
|
399
|
+
function containsReactHooksCallExpressions(path, j) {
|
|
400
|
+
const hasReactHooks = j(path)
|
|
401
|
+
.find(j.CallExpression)
|
|
402
|
+
.filter((callPath) => {
|
|
403
|
+
// It's matching:
|
|
404
|
+
// - use(<callPath>) => true
|
|
405
|
+
// - useX*(<callPath>) => true
|
|
406
|
+
const isUseHookOrReactHookCall = j.Identifier.check(callPath.value.callee) &&
|
|
407
|
+
(0, exports.isReactHookName)(callPath.value.callee.name);
|
|
408
|
+
// It's matching member access:
|
|
409
|
+
// - React.use(<callPath>) => true
|
|
410
|
+
// - Foo.useFoo(<callPath>) => true
|
|
411
|
+
// - foo.useFoo(<callPath>) => false
|
|
412
|
+
// - foo.use(<callPath>) => false
|
|
413
|
+
const isReactUseCall = j.MemberExpression.check(callPath.value.callee) &&
|
|
414
|
+
j.Identifier.check(callPath.value.callee.object) &&
|
|
415
|
+
j.Identifier.check(callPath.value.callee.property) &&
|
|
416
|
+
isPascalCase(callPath.value.callee.object.name) &&
|
|
417
|
+
(0, exports.isReactHookName)(callPath.value.callee.property.name);
|
|
418
|
+
return isUseHookOrReactHookCall || isReactUseCall;
|
|
419
|
+
})
|
|
420
|
+
.size() > 0;
|
|
421
|
+
return hasReactHooks;
|
|
422
|
+
}
|
|
423
|
+
// Capture the parent of the current path is wrapped by `use()` call expression
|
|
424
|
+
// e.g.
|
|
425
|
+
// use(<path>) => true
|
|
426
|
+
// use2(<path>) => false
|
|
427
|
+
// React.use(<path>) => true
|
|
428
|
+
// Robust.use(<path>) => false
|
|
429
|
+
function isParentUseCallExpression(path, j) {
|
|
430
|
+
const isParentUseCall =
|
|
431
|
+
// member access parentPath is argument
|
|
432
|
+
j.CallExpression.check(path.parent.value) &&
|
|
433
|
+
// member access is first argument
|
|
434
|
+
path.parent.value.arguments[0] === path.value &&
|
|
435
|
+
path.parent.value.arguments.length === 1 &&
|
|
436
|
+
// function name is `use`
|
|
437
|
+
j.Identifier.check(path.parent.value.callee) &&
|
|
438
|
+
path.parent.value.callee.name === 'use';
|
|
439
|
+
const isParentReactUseCall =
|
|
440
|
+
// member access parentPath is argument
|
|
441
|
+
j.CallExpression.check(path.parent.value) &&
|
|
442
|
+
// member access is first argument
|
|
443
|
+
path.parent.value.arguments[0] === path.value &&
|
|
444
|
+
path.parent.value.arguments.length === 1 &&
|
|
445
|
+
// function name is `use`
|
|
446
|
+
j.MemberExpression.check(path.parent.value.callee) &&
|
|
447
|
+
j.Identifier.check(path.parent.value.callee.object) &&
|
|
448
|
+
path.parent.value.callee.object.name === 'React' &&
|
|
449
|
+
j.Identifier.check(path.parent.value.callee.property) &&
|
|
450
|
+
path.parent.value.callee.property.name === 'use';
|
|
451
|
+
return isParentUseCall || isParentReactUseCall;
|
|
452
|
+
}
|
|
453
|
+
// Determine if a path is wrapped by `Promise.all()`
|
|
454
|
+
// e.g.
|
|
455
|
+
// Promise.all(<path>) => true
|
|
456
|
+
// Promise.allSettled(<path>) => false
|
|
457
|
+
function isParentPromiseAllCallExpression(path, j) {
|
|
458
|
+
const argsParent = path.parent;
|
|
459
|
+
const callParent = argsParent?.parent;
|
|
460
|
+
if (argsParent &&
|
|
461
|
+
callParent &&
|
|
462
|
+
j.ArrayExpression.check(argsParent.value) &&
|
|
463
|
+
j.CallExpression.check(callParent.value) &&
|
|
464
|
+
j.MemberExpression.check(callParent.value.callee) &&
|
|
465
|
+
j.Identifier.check(callParent.value.callee.object) &&
|
|
466
|
+
callParent.value.callee.object.name === 'Promise' &&
|
|
467
|
+
j.Identifier.check(callParent.value.callee.property) &&
|
|
468
|
+
callParent.value.callee.property.name === 'all') {
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
exports.default = transformer;
|
|
4
|
+
const parser_1 = require("../lib/parser");
|
|
5
|
+
function transformer(file, _api) {
|
|
6
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
5
7
|
const root = j(file.source);
|
|
6
8
|
// Find the metadata export
|
|
7
9
|
const metadataExport = root.find(j.ExportNamedDeclaration, {
|
|
@@ -56,5 +58,4 @@ function transformer(file, api) {
|
|
|
56
58
|
}
|
|
57
59
|
return root.toSource();
|
|
58
60
|
}
|
|
59
|
-
exports.default = transformer;
|
|
60
61
|
//# sourceMappingURL=metadata-to-viewport-export.js.map
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = transformer;
|
|
3
4
|
const path_1 = require("path");
|
|
5
|
+
const parser_1 = require("../lib/parser");
|
|
4
6
|
const camelCase = (value) => {
|
|
5
7
|
const val = value.replace(/[-_\s.]+(.)?/g, (_match, chr) => chr ? chr.toUpperCase() : '');
|
|
6
8
|
return val.slice(0, 1).toUpperCase() + val.slice(1);
|
|
7
9
|
};
|
|
8
10
|
const isValidIdentifier = (value) => /^[a-zA-ZÀ-ÿ][0-9a-zA-ZÀ-ÿ]+$/.test(value);
|
|
9
|
-
function transformer(file,
|
|
10
|
-
const j =
|
|
11
|
+
function transformer(file, _api, options) {
|
|
12
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
11
13
|
const root = j(file.source);
|
|
12
14
|
let hasModifications;
|
|
13
15
|
const returnsJSX = (node) => node.type === 'JSXElement' ||
|
|
14
16
|
(node.type === 'BlockStatement' &&
|
|
15
17
|
j(node)
|
|
16
18
|
.find(j.ReturnStatement)
|
|
17
|
-
.some((path) =>
|
|
19
|
+
.some((path) => path.value.argument?.type === 'JSXElement'));
|
|
18
20
|
const hasRootAsParent = (path) => {
|
|
19
|
-
var _a;
|
|
20
21
|
const program = path.parentPath.parentPath.parentPath.parentPath.parentPath;
|
|
21
|
-
return !program ||
|
|
22
|
+
return !program || program?.value?.type === 'Program';
|
|
22
23
|
};
|
|
23
24
|
const nameFunctionComponent = (path) => {
|
|
24
25
|
const node = path.value;
|
|
@@ -62,5 +63,4 @@ function transformer(file, api, options) {
|
|
|
62
63
|
root.find(j.ExportDefaultDeclaration).forEach(nameFunctionComponent);
|
|
63
64
|
return hasModifications ? root.toSource(options) : null;
|
|
64
65
|
}
|
|
65
|
-
exports.default = transformer;
|
|
66
66
|
//# sourceMappingURL=name-default-component.js.map
|
package/transforms/new-link.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// It might insert extra parnes for JSX components
|
|
3
|
+
// x-ref: https://github.com/facebook/jscodeshift/issues/534
|
|
2
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
exports.default = transformer;
|
|
6
|
+
const parser_1 = require("../lib/parser");
|
|
7
|
+
function transformer(file, _api) {
|
|
8
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
5
9
|
const $j = j(file.source);
|
|
6
10
|
return $j
|
|
7
11
|
.find(j.ImportDeclaration, { source: { value: 'next/link' } })
|
|
@@ -34,7 +38,7 @@ function transformer(file, api) {
|
|
|
34
38
|
return;
|
|
35
39
|
}
|
|
36
40
|
// If file has <style jsx> enable legacyBehavior
|
|
37
|
-
// and keep <a> to
|
|
41
|
+
// and keep <a> to stay on the safe side
|
|
38
42
|
if (hasStylesJSX) {
|
|
39
43
|
$link
|
|
40
44
|
.get('attributes')
|
|
@@ -68,11 +72,10 @@ function transformer(file, api) {
|
|
|
68
72
|
// Add only unique props to <Link> (skip duplicate props)
|
|
69
73
|
const linkPropNames = $link
|
|
70
74
|
.get('attributes')
|
|
71
|
-
.value.map((linkProp) =>
|
|
75
|
+
.value.map((linkProp) => linkProp?.name?.name);
|
|
72
76
|
const uniqueProps = [];
|
|
73
77
|
props.forEach((anchorProp) => {
|
|
74
|
-
|
|
75
|
-
if (!linkPropNames.includes((_a = anchorProp === null || anchorProp === void 0 ? void 0 : anchorProp.name) === null || _a === void 0 ? void 0 : _a.name)) {
|
|
78
|
+
if (!linkPropNames.includes(anchorProp?.name?.name)) {
|
|
76
79
|
uniqueProps.push(anchorProp);
|
|
77
80
|
}
|
|
78
81
|
});
|
|
@@ -86,5 +89,4 @@ function transformer(file, api) {
|
|
|
86
89
|
})
|
|
87
90
|
.toSource();
|
|
88
91
|
}
|
|
89
|
-
exports.default = transformer;
|
|
90
92
|
//# sourceMappingURL=new-link.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
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.default = void 0;
|
|
7
|
+
var index_1 = require("./lib/async-request-api/index");
|
|
8
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(index_1).default; } });
|
|
9
|
+
//# sourceMappingURL=next-async-request-api.js.map
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
const j = (0, parser_1.createParserFromPath)(file.path);
|
|
7
|
+
const root = j(file.source);
|
|
8
|
+
// Find the import declaration for 'next/dynamic'
|
|
9
|
+
const dynamicImportDeclaration = root.find(j.ImportDeclaration, {
|
|
10
|
+
source: { value: 'next/dynamic' },
|
|
11
|
+
});
|
|
12
|
+
// If the import declaration is found
|
|
13
|
+
if (dynamicImportDeclaration.size() > 0) {
|
|
14
|
+
const importDecl = dynamicImportDeclaration.get(0).node;
|
|
15
|
+
const dynamicImportName = importDecl.specifiers?.[0]?.local?.name;
|
|
16
|
+
if (!dynamicImportName) {
|
|
17
|
+
return file.source;
|
|
18
|
+
}
|
|
19
|
+
// Find call expressions where the callee is the imported 'dynamic'
|
|
20
|
+
root
|
|
21
|
+
.find(j.CallExpression, {
|
|
22
|
+
callee: { name: dynamicImportName },
|
|
23
|
+
})
|
|
24
|
+
.forEach((path) => {
|
|
25
|
+
const arrowFunction = path.node.arguments[0];
|
|
26
|
+
// Ensure the argument is an ArrowFunctionExpression
|
|
27
|
+
if (arrowFunction && arrowFunction.type === 'ArrowFunctionExpression') {
|
|
28
|
+
const importCall = arrowFunction.body;
|
|
29
|
+
// Ensure the parent of the import call is a CallExpression with a .then
|
|
30
|
+
if (importCall &&
|
|
31
|
+
importCall.type === 'CallExpression' &&
|
|
32
|
+
importCall.callee.type === 'MemberExpression' &&
|
|
33
|
+
'name' in importCall.callee.property &&
|
|
34
|
+
importCall.callee.property.name === 'then') {
|
|
35
|
+
const thenFunction = importCall.arguments[0];
|
|
36
|
+
// handle case of block statement case `=> { return mod.Component }`
|
|
37
|
+
// transform to`=> { return { default: mod.Component } }`
|
|
38
|
+
if (thenFunction &&
|
|
39
|
+
thenFunction.type === 'ArrowFunctionExpression' &&
|
|
40
|
+
thenFunction.body.type === 'BlockStatement') {
|
|
41
|
+
const returnStatement = thenFunction.body.body[0];
|
|
42
|
+
// Ensure the body of the arrow function has a return statement with a MemberExpression
|
|
43
|
+
if (returnStatement &&
|
|
44
|
+
returnStatement.type === 'ReturnStatement' &&
|
|
45
|
+
returnStatement.argument?.type === 'MemberExpression') {
|
|
46
|
+
returnStatement.argument = j.objectExpression([
|
|
47
|
+
j.property('init', j.identifier('default'), returnStatement.argument),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// handle case `=> mod.Component`
|
|
52
|
+
// transform to`=> ({ default: mod.Component })`
|
|
53
|
+
if (thenFunction &&
|
|
54
|
+
thenFunction.type === 'ArrowFunctionExpression' &&
|
|
55
|
+
thenFunction.body.type === 'MemberExpression') {
|
|
56
|
+
thenFunction.body = j.objectExpression([
|
|
57
|
+
j.property('init', j.identifier('default'), thenFunction.body),
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return root.toSource();
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=next-dynamic-access-named-export.js.map
|