@next/codemod 15.0.0-rc.0 → 15.0.0-rc.1

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.
Files changed (33) hide show
  1. package/bin/next-codemod.js +55 -3
  2. package/bin/shared.js +7 -0
  3. package/bin/transform.js +124 -0
  4. package/bin/upgrade.js +390 -0
  5. package/lib/cra-to-next/global-css-transform.js +5 -5
  6. package/lib/cra-to-next/index-to-component.js +5 -5
  7. package/lib/handle-package.js +110 -0
  8. package/lib/install.js +2 -3
  9. package/lib/parser.js +28 -0
  10. package/lib/run-jscodeshift.js +18 -2
  11. package/lib/utils.js +115 -0
  12. package/package.json +13 -6
  13. package/transforms/add-missing-react-import.js +4 -3
  14. package/transforms/app-dir-runtime-config-experimental-edge.js +34 -0
  15. package/transforms/built-in-next-font.js +4 -3
  16. package/transforms/cra-to-next.js +238 -236
  17. package/transforms/lib/async-request-api/index.js +16 -0
  18. package/transforms/lib/async-request-api/next-async-dynamic-api.js +274 -0
  19. package/transforms/lib/async-request-api/next-async-dynamic-prop.js +715 -0
  20. package/transforms/lib/async-request-api/utils.js +374 -0
  21. package/transforms/metadata-to-viewport-export.js +4 -3
  22. package/transforms/name-default-component.js +6 -6
  23. package/transforms/new-link.js +9 -7
  24. package/transforms/next-async-request-api.js +9 -0
  25. package/transforms/next-dynamic-access-named-export.js +66 -0
  26. package/transforms/next-image-experimental.js +12 -15
  27. package/transforms/next-image-to-legacy-image.js +8 -9
  28. package/transforms/next-og-import.js +4 -3
  29. package/transforms/next-request-geo-ip.js +339 -0
  30. package/transforms/url-to-withrouter.js +1 -1
  31. package/transforms/withamp-to-config.js +1 -1
  32. package/bin/cli.js +0 -216
  33. package/lib/uninstall-package.js +0 -32
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- function transformer(file, api, options) {
4
- const j = api.jscodeshift.withParser('tsx');
3
+ exports.default = transformer;
4
+ const parser_1 = require("../lib/parser");
5
+ function transformer(file, _api, options) {
6
+ const j = (0, parser_1.createParserFromPath)(file.path);
5
7
  const root = j(file.source);
6
8
  // Before: import Image from "next/image"
7
9
  // After: import Image from "next/legacy/image"
@@ -16,7 +18,7 @@ function transformer(file, api, options) {
16
18
  // After: const Image = await import("next/legacy/image")
17
19
  root.find(j.AwaitExpression).forEach((awaitExp) => {
18
20
  const arg = awaitExp.value.argument;
19
- if ((arg === null || arg === void 0 ? void 0 : arg.type) === 'CallExpression' && arg.callee.type === 'Import') {
21
+ if (arg?.type === 'CallExpression' && arg.callee.type === 'Import') {
20
22
  if (arg.arguments[0].type === 'StringLiteral' &&
21
23
  arg.arguments[0].value === 'next/image') {
22
24
  arg.arguments[0] = j.stringLiteral('next/legacy/image');
@@ -36,7 +38,7 @@ function transformer(file, api, options) {
36
38
  // After: const Image = await import("next/image")
37
39
  root.find(j.AwaitExpression).forEach((awaitExp) => {
38
40
  const arg = awaitExp.value.argument;
39
- if ((arg === null || arg === void 0 ? void 0 : arg.type) === 'CallExpression' && arg.callee.type === 'Import') {
41
+ if (arg?.type === 'CallExpression' && arg.callee.type === 'Import') {
40
42
  if (arg.arguments[0].type === 'StringLiteral' &&
41
43
  arg.arguments[0].value === 'next/future/image') {
42
44
  arg.arguments[0] = j.stringLiteral('next/image');
@@ -46,8 +48,7 @@ function transformer(file, api, options) {
46
48
  // Before: const Image = require("next/image")
47
49
  // After: const Image = require("next/legacy/image")
48
50
  root.find(j.CallExpression).forEach((requireExp) => {
49
- var _a, _b;
50
- if (((_b = (_a = requireExp === null || requireExp === void 0 ? void 0 : requireExp.value) === null || _a === void 0 ? void 0 : _a.callee) === null || _b === void 0 ? void 0 : _b.type) === 'Identifier' &&
51
+ if (requireExp?.value?.callee?.type === 'Identifier' &&
51
52
  requireExp.value.callee.name === 'require') {
52
53
  let firstArg = requireExp.value.arguments[0];
53
54
  if (firstArg &&
@@ -60,8 +61,7 @@ function transformer(file, api, options) {
60
61
  // Before: const Image = require("next/future/image")
61
62
  // After: const Image = require("next/image")
62
63
  root.find(j.CallExpression).forEach((requireExp) => {
63
- var _a, _b;
64
- if (((_b = (_a = requireExp === null || requireExp === void 0 ? void 0 : requireExp.value) === null || _a === void 0 ? void 0 : _a.callee) === null || _b === void 0 ? void 0 : _b.type) === 'Identifier' &&
64
+ if (requireExp?.value?.callee?.type === 'Identifier' &&
65
65
  requireExp.value.callee.name === 'require') {
66
66
  let firstArg = requireExp.value.arguments[0];
67
67
  if (firstArg &&
@@ -75,5 +75,4 @@ function transformer(file, api, options) {
75
75
  // https://www.codeshiftcommunity.com/docs/import-manipulation/#replacerename-an-import-declaration
76
76
  return root.toSource(options);
77
77
  }
78
- exports.default = transformer;
79
78
  //# sourceMappingURL=next-image-to-legacy-image.js.map
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = transformer;
4
+ const parser_1 = require("../lib/parser");
3
5
  const importToChange = 'ImageResponse';
4
- function transformer(file, api) {
5
- const j = api.jscodeshift;
6
+ function transformer(file, _api) {
7
+ const j = (0, parser_1.createParserFromPath)(file.path);
6
8
  // Find import declarations that match the pattern
7
9
  file.source = j(file.source)
8
10
  .find(j.ImportDeclaration, {
@@ -31,5 +33,4 @@ function transformer(file, api) {
31
33
  .toSource();
32
34
  return file.source;
33
35
  }
34
- exports.default = transformer;
35
36
  //# sourceMappingURL=next-og-import.js.map
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const parser_1 = require("../lib/parser");
5
+ const GEO = 'geo';
6
+ const IP = 'ip';
7
+ const GEOLOCATION = 'geolocation';
8
+ const IP_ADDRESS = 'ipAddress';
9
+ const GEO_TYPE = 'Geo';
10
+ function default_1(file, _api) {
11
+ const j = (0, parser_1.createParserFromPath)(file.path);
12
+ const root = j(file.source);
13
+ if (!root.length) {
14
+ return file.source;
15
+ }
16
+ const nextReqType = root
17
+ .find(j.FunctionDeclaration)
18
+ .find(j.Identifier, (id) => {
19
+ if (id.typeAnnotation?.type !== 'TSTypeAnnotation') {
20
+ return false;
21
+ }
22
+ const typeAnn = id.typeAnnotation.typeAnnotation;
23
+ return (typeAnn.type === 'TSTypeReference' &&
24
+ typeAnn.typeName.type === 'Identifier' &&
25
+ typeAnn.typeName.name === 'NextRequest');
26
+ });
27
+ const vercelFuncImports = root.find(j.ImportDeclaration, {
28
+ source: {
29
+ value: '@vercel/functions',
30
+ },
31
+ });
32
+ const vercelFuncImportSpecifiers = vercelFuncImports
33
+ .find(j.ImportSpecifier)
34
+ .nodes();
35
+ const vercelFuncImportNames = new Set(vercelFuncImportSpecifiers.map((node) => node.imported.name));
36
+ const hasGeolocation = vercelFuncImportNames.has(GEOLOCATION);
37
+ const hasIpAddress = vercelFuncImportNames.has(IP_ADDRESS);
38
+ const hasGeoType = vercelFuncImportNames.has(GEO_TYPE);
39
+ let identifierNames = new Set();
40
+ // if all identifiers are already imported, we don't need to create
41
+ // a unique identifier for them, therefore we don't look for all
42
+ // identifier names in the file
43
+ if (!hasGeolocation || !hasIpAddress || !hasGeoType) {
44
+ const allIdentifiers = root.find(j.Identifier).nodes();
45
+ identifierNames = new Set(allIdentifiers.map((node) => node.name));
46
+ }
47
+ let geoIdentifier = hasGeolocation
48
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, GEOLOCATION)
49
+ : getUniqueIdentifier(identifierNames, GEOLOCATION);
50
+ let ipIdentifier = hasIpAddress
51
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, IP_ADDRESS)
52
+ : getUniqueIdentifier(identifierNames, IP_ADDRESS);
53
+ let geoTypeIdentifier = hasGeoType
54
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, GEO_TYPE)
55
+ : getUniqueIdentifier(identifierNames, GEO_TYPE);
56
+ let { needImportGeolocation, needImportIpAddress } = replaceGeoIpValues(j, nextReqType, geoIdentifier, ipIdentifier);
57
+ let { needImportGeoType, hasChangedIpType } = replaceGeoIpTypes(j, root, geoTypeIdentifier);
58
+ let needChanges = needImportGeolocation ||
59
+ needImportIpAddress ||
60
+ needImportGeoType ||
61
+ hasChangedIpType;
62
+ if (!needChanges) {
63
+ return file.source;
64
+ }
65
+ // Even if there was a change above, if there's an existing import,
66
+ // we don't need to import them again.
67
+ needImportGeolocation = !hasGeolocation && needImportGeolocation;
68
+ needImportIpAddress = !hasIpAddress && needImportIpAddress;
69
+ needImportGeoType = !hasGeoType && needImportGeoType;
70
+ insertImportDeclarations(j, root, vercelFuncImports, needImportGeolocation, needImportIpAddress, needImportGeoType, geoIdentifier, ipIdentifier, geoTypeIdentifier);
71
+ return root.toSource();
72
+ }
73
+ /**
74
+ * Returns an existing identifier from the Vercel functions import declaration.
75
+ */
76
+ function getExistingIdentifier(vercelFuncImportSpecifiers, identifier) {
77
+ const existingIdentifier = vercelFuncImportSpecifiers.find((node) => node.imported.name === identifier);
78
+ return (existingIdentifier?.local?.name ||
79
+ existingIdentifier.imported.name ||
80
+ identifier);
81
+ }
82
+ /**
83
+ * Returns a unique identifier by adding a suffix to the original identifier
84
+ * if it already exists in the set.
85
+ */
86
+ function getUniqueIdentifier(identifierNames, identifier) {
87
+ let suffix = 1;
88
+ let uniqueIdentifier = identifier;
89
+ while (identifierNames.has(uniqueIdentifier)) {
90
+ uniqueIdentifier = `${identifier}${suffix}`;
91
+ suffix++;
92
+ }
93
+ return uniqueIdentifier;
94
+ }
95
+ /**
96
+ * Replaces accessors `geo` and `ip` of NextRequest with corresponding
97
+ * function calls from `@vercel/functions`.
98
+ *
99
+ * Creates new variable declarations for destructuring assignments.
100
+ */
101
+ function replaceGeoIpValues(j, nextReqType, geoIdentifier, ipIdentifier) {
102
+ let needImportGeolocation = false;
103
+ let needImportIpAddress = false;
104
+ for (const nextReqPath of nextReqType.paths()) {
105
+ const fnPath = nextReqPath.parentPath.parentPath;
106
+ const fn = j(fnPath);
107
+ const blockStatement = fn.find(j.BlockStatement);
108
+ const varDeclarators = fn.find(j.VariableDeclarator);
109
+ // req.geo, req.ip
110
+ const geoAccesses = blockStatement.find(j.MemberExpression, (me) => me.object.type === 'Identifier' &&
111
+ me.object.name === nextReqPath.node.name &&
112
+ me.property.type === 'Identifier' &&
113
+ me.property.name === GEO);
114
+ const ipAccesses = blockStatement.find(j.MemberExpression, (me) => me.object.type === 'Identifier' &&
115
+ me.object.name === nextReqPath.node.name &&
116
+ me.property.type === 'Identifier' &&
117
+ me.property.name === IP);
118
+ // var { geo, ip } = req
119
+ const geoDestructuring = varDeclarators.filter((path) => path.node.id.type === 'ObjectPattern' &&
120
+ path.node.id.properties.some((prop) => prop.type === 'ObjectProperty' &&
121
+ prop.key.type === 'Identifier' &&
122
+ prop.key.name === GEO));
123
+ const ipDestructuring = varDeclarators.filter((path) => path.node.id.type === 'ObjectPattern' &&
124
+ path.node.id.properties.some((prop) => prop.type === 'ObjectProperty' &&
125
+ prop.key.type === 'Identifier' &&
126
+ prop.key.name === IP));
127
+ // geolocation(req), ipAddress(req)
128
+ const geoCall = j.callExpression(j.identifier(geoIdentifier), [
129
+ {
130
+ ...nextReqPath.node,
131
+ typeAnnotation: null,
132
+ },
133
+ ]);
134
+ const ipCall = j.callExpression(j.identifier(ipIdentifier), [
135
+ {
136
+ ...nextReqPath.node,
137
+ typeAnnotation: null,
138
+ },
139
+ ]);
140
+ geoAccesses.replaceWith(geoCall);
141
+ ipAccesses.replaceWith(ipCall);
142
+ /**
143
+ * For each destructuring assignment, we create a new variable
144
+ * declaration and insert it after the current block statement.
145
+ *
146
+ * Before:
147
+ *
148
+ * ```
149
+ * const { buildId, geo, ip } = req;
150
+ * ```
151
+ *
152
+ * After:
153
+ *
154
+ * ```
155
+ * const { buildId } = req;
156
+ * const geo = geolocation(req);
157
+ * const ip = ipAddress(req);
158
+ * ```
159
+ */
160
+ geoDestructuring.forEach((path) => {
161
+ if (path.node.id.type === 'ObjectPattern') {
162
+ const properties = path.node.id.properties;
163
+ const geoProperty = properties.find((prop) => prop.type === 'ObjectProperty' &&
164
+ prop.key.type === 'Identifier' &&
165
+ prop.key.name === GEO);
166
+ const otherProperties = properties.filter((prop) => prop !== geoProperty);
167
+ const geoDeclaration = j.variableDeclaration('const', [
168
+ j.variableDeclarator(j.identifier(
169
+ // Use alias from destructuring (if present) to retain references:
170
+ // const { geo: geoAlias } = req; -> const geoAlias = geolocation(req);
171
+ // This prevents errors from undeclared variables.
172
+ geoProperty.type === 'ObjectProperty' &&
173
+ geoProperty.value.type === 'Identifier'
174
+ ? geoProperty.value.name
175
+ : GEO), geoCall),
176
+ ]);
177
+ path.node.id.properties = otherProperties;
178
+ path.parent.insertAfter(geoDeclaration);
179
+ }
180
+ });
181
+ ipDestructuring.forEach((path) => {
182
+ if (path.node.id.type === 'ObjectPattern') {
183
+ const properties = path.node.id.properties;
184
+ const ipProperty = properties.find((prop) => prop.type === 'ObjectProperty' &&
185
+ prop.key.type === 'Identifier' &&
186
+ prop.key.name === IP);
187
+ const otherProperties = properties.filter((prop) => prop !== ipProperty);
188
+ const ipDeclaration = j.variableDeclaration('const', [
189
+ j.variableDeclarator(j.identifier(
190
+ // Use alias from destructuring (if present) to retain references:
191
+ // const { ip: ipAlias } = req; -> const ipAlias = ipAddress(req);
192
+ // This prevents errors from undeclared variables.
193
+ ipProperty.type === 'ObjectProperty' &&
194
+ ipProperty.value.type === 'Identifier'
195
+ ? ipProperty.value.name
196
+ : IP), ipCall),
197
+ ]);
198
+ path.node.id.properties = otherProperties;
199
+ path.parent.insertAfter(ipDeclaration);
200
+ }
201
+ });
202
+ needImportGeolocation =
203
+ needImportGeolocation ||
204
+ geoAccesses.length > 0 ||
205
+ geoDestructuring.length > 0;
206
+ needImportIpAddress =
207
+ needImportIpAddress || ipAccesses.length > 0 || ipDestructuring.length > 0;
208
+ }
209
+ return {
210
+ needImportGeolocation,
211
+ needImportIpAddress,
212
+ };
213
+ }
214
+ /**
215
+ * Replaces the types of `NextRequest["geo"]` and `NextRequest["ip"]` with
216
+ * corresponding types from `@vercel/functions`.
217
+ */
218
+ function replaceGeoIpTypes(j, root, geoTypeIdentifier) {
219
+ let needImportGeoType = false;
220
+ let hasChangedIpType = false;
221
+ // get the type of NextRequest that has accessed for ip and geo
222
+ // NextRequest['geo'], NextRequest['ip']
223
+ const nextReqGeoType = root.find(j.TSIndexedAccessType, (tsIndexedAccessType) => {
224
+ return (tsIndexedAccessType.objectType.type === 'TSTypeReference' &&
225
+ tsIndexedAccessType.objectType.typeName.type === 'Identifier' &&
226
+ tsIndexedAccessType.objectType.typeName.name === 'NextRequest' &&
227
+ tsIndexedAccessType.indexType.type === 'TSLiteralType' &&
228
+ tsIndexedAccessType.indexType.literal.type === 'StringLiteral' &&
229
+ tsIndexedAccessType.indexType.literal.value === GEO);
230
+ });
231
+ const nextReqIpType = root.find(j.TSIndexedAccessType, (tsIndexedAccessType) => {
232
+ return (tsIndexedAccessType.objectType.type === 'TSTypeReference' &&
233
+ tsIndexedAccessType.objectType.typeName.type === 'Identifier' &&
234
+ tsIndexedAccessType.objectType.typeName.name === 'NextRequest' &&
235
+ tsIndexedAccessType.indexType.type === 'TSLiteralType' &&
236
+ tsIndexedAccessType.indexType.literal.type === 'StringLiteral' &&
237
+ tsIndexedAccessType.indexType.literal.value === IP);
238
+ });
239
+ if (nextReqGeoType.length > 0) {
240
+ needImportGeoType = true;
241
+ // replace with type Geo
242
+ nextReqGeoType.replaceWith(j.identifier(geoTypeIdentifier));
243
+ }
244
+ if (nextReqIpType.length > 0) {
245
+ hasChangedIpType = true;
246
+ // replace with type string | undefined
247
+ nextReqIpType.replaceWith(j.tsUnionType([j.tsStringKeyword(), j.tsUndefinedKeyword()]));
248
+ }
249
+ return {
250
+ needImportGeoType,
251
+ hasChangedIpType,
252
+ };
253
+ }
254
+ /**
255
+ * Inserts import declarations from `"@vercel/functions"`.
256
+ *
257
+ * For the `Geo` type that needs to be imported to replace `NextRequest["geo"]`,
258
+ * if it is the only import needed, we import it as a type.
259
+ *
260
+ * ```ts
261
+ * import type { Geo } from "@vercel/functions";
262
+ * ```
263
+ *
264
+ * Otherwise, we import it as an inline type import.
265
+ *
266
+ * ```ts
267
+ * import { type Geo, ... } from "@vercel/functions";
268
+ * ```
269
+ */
270
+ function insertImportDeclarations(j, root, vercelFuncImports, needImportGeolocation, needImportIpAddress, needImportGeoType, geoIdentifier, ipIdentifier, geoTypeIdentifier) {
271
+ // No need inserting import.
272
+ if (!needImportGeolocation && !needImportIpAddress && !needImportGeoType) {
273
+ return;
274
+ }
275
+ // As we run this only when `NextRequest` is imported, there should be
276
+ // a "next/server" import.
277
+ const firstNextServerImport = root
278
+ .find(j.ImportDeclaration, { source: { value: 'next/server' } })
279
+ .at(0);
280
+ const firstVercelFuncImport = vercelFuncImports.at(0);
281
+ const hasVercelFuncImport = firstVercelFuncImport.length > 0;
282
+ // If there's no "@vercel/functions" import, and we only need to import
283
+ // `Geo` type, we create a type import to avoid side effect with
284
+ // `verbatimModuleSyntax`.
285
+ // x-ref: https://typescript-eslint.io/rules/no-import-type-side-effects
286
+ if (!hasVercelFuncImport &&
287
+ !needImportGeolocation &&
288
+ !needImportIpAddress &&
289
+ needImportGeoType) {
290
+ const geoTypeImportDeclaration = j.importDeclaration([
291
+ needImportGeoType
292
+ ? j.importSpecifier(j.identifier(GEO_TYPE), j.identifier(geoTypeIdentifier))
293
+ : null,
294
+ ].filter(Boolean), j.literal('@vercel/functions'),
295
+ // import type { Geo } ...
296
+ 'type');
297
+ firstNextServerImport.insertAfter(geoTypeImportDeclaration);
298
+ return;
299
+ }
300
+ const importDeclaration = j.importDeclaration([
301
+ // If there was a duplicate identifier, we add an
302
+ // incremental number suffix to it and we use alias:
303
+ // `import { geolocation as geolocation1 } from ...`
304
+ needImportGeolocation
305
+ ? j.importSpecifier(j.identifier(GEOLOCATION), j.identifier(geoIdentifier))
306
+ : null,
307
+ needImportIpAddress
308
+ ? j.importSpecifier(j.identifier(IP_ADDRESS), j.identifier(ipIdentifier))
309
+ : null,
310
+ needImportGeoType
311
+ ? j.importSpecifier(j.identifier(GEO_TYPE), j.identifier(geoTypeIdentifier))
312
+ : null,
313
+ ].filter(Boolean), j.literal('@vercel/functions'));
314
+ if (hasVercelFuncImport) {
315
+ firstVercelFuncImport
316
+ .get()
317
+ .node.specifiers.push(...importDeclaration.specifiers);
318
+ if (needImportGeoType) {
319
+ const targetGeo = firstVercelFuncImport
320
+ .get()
321
+ .node.specifiers.find((specifier) => specifier.imported.name === GEO_TYPE);
322
+ if (targetGeo) {
323
+ targetGeo.importKind = 'type';
324
+ }
325
+ }
326
+ }
327
+ else {
328
+ if (needImportGeoType) {
329
+ const targetGeo = importDeclaration.specifiers.find((specifier) => specifier.type === 'ImportSpecifier' &&
330
+ specifier.imported.name === GEO_TYPE);
331
+ if (targetGeo) {
332
+ // @ts-expect-error -- Missing types in jscodeshift.
333
+ targetGeo.importKind = 'type';
334
+ }
335
+ }
336
+ firstNextServerImport.insertAfter(importDeclaration);
337
+ }
338
+ }
339
+ //# sourceMappingURL=next-request-geo-ip.js.map
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  // One-time usage file. You can delete me after running the codemod!
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.default = transformer;
4
5
  function addWithRouterImport(j, root) {
5
6
  // We create an import specifier, this is the value of an import, eg:
6
7
  // import {withRouter} from 'next/router
@@ -317,5 +318,4 @@ function transformer(file, api) {
317
318
  });
318
319
  return root.toSource();
319
320
  }
320
- exports.default = transformer;
321
321
  //# sourceMappingURL=url-to-withrouter.js.map
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  // One-time usage file. You can delete me after running the codemod!
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.default = transformer;
4
5
  function injectAmp(j, o, desiredAmpValue) {
5
6
  const init = o.node.init;
6
7
  switch (init.type) {
@@ -131,5 +132,4 @@ function transformer(file, api) {
131
132
  }
132
133
  return done();
133
134
  }
134
- exports.default = transformer;
135
135
  //# sourceMappingURL=withamp-to-config.js.map
package/bin/cli.js DELETED
@@ -1,216 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright 2015-present, Facebook, Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- *
8
- */
9
- // Based on https://github.com/reactjs/react-codemod/blob/dd8671c9a470a2c342b221ec903c574cf31e9f57/bin/cli.js
10
- // @next/codemod optional-name-of-transform optional/path/to/src [...options]
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.run = exports.runTransform = exports.checkGitStatus = exports.transformerDirectory = exports.jscodeshiftExecutable = void 0;
16
- const globby_1 = __importDefault(require("globby"));
17
- const inquirer_1 = __importDefault(require("inquirer"));
18
- const meow_1 = __importDefault(require("meow"));
19
- const path_1 = __importDefault(require("path"));
20
- const execa_1 = __importDefault(require("execa"));
21
- const picocolors_1 = require("picocolors");
22
- const is_git_clean_1 = __importDefault(require("is-git-clean"));
23
- const uninstall_package_1 = require("../lib/uninstall-package");
24
- exports.jscodeshiftExecutable = require.resolve('.bin/jscodeshift');
25
- exports.transformerDirectory = path_1.default.join(__dirname, '../', 'transforms');
26
- function checkGitStatus(force) {
27
- let clean = false;
28
- let errorMessage = 'Unable to determine if git directory is clean';
29
- try {
30
- clean = is_git_clean_1.default.sync(process.cwd());
31
- errorMessage = 'Git directory is not clean';
32
- }
33
- catch (err) {
34
- if (err && err.stderr && err.stderr.includes('Not a git repository')) {
35
- clean = true;
36
- }
37
- }
38
- if (!clean) {
39
- if (force) {
40
- console.log(`WARNING: ${errorMessage}. Forcibly continuing.`);
41
- }
42
- else {
43
- console.log('Thank you for using @next/codemod!');
44
- console.log((0, picocolors_1.yellow)('\nBut before we continue, please stash or commit your git changes.'));
45
- console.log('\nYou may use the --force flag to override this safety check.');
46
- process.exit(1);
47
- }
48
- }
49
- }
50
- exports.checkGitStatus = checkGitStatus;
51
- function runTransform({ files, flags, transformer }) {
52
- const transformerPath = path_1.default.join(exports.transformerDirectory, `${transformer}.js`);
53
- if (transformer === 'cra-to-next') {
54
- // cra-to-next transform doesn't use jscodeshift directly
55
- return require(transformerPath).default(files, flags);
56
- }
57
- let args = [];
58
- const { dry, print, runInBand } = flags;
59
- if (dry) {
60
- args.push('--dry');
61
- }
62
- if (print) {
63
- args.push('--print');
64
- }
65
- if (runInBand) {
66
- args.push('--run-in-band');
67
- }
68
- args.push('--verbose=2');
69
- args.push('--ignore-pattern=**/node_modules/**');
70
- args.push('--ignore-pattern=**/.next/**');
71
- args.push('--extensions=tsx,ts,jsx,js');
72
- args = args.concat(['--transform', transformerPath]);
73
- if (flags.jscodeshift) {
74
- args = args.concat(flags.jscodeshift);
75
- }
76
- args = args.concat(files);
77
- console.log(`Executing command: jscodeshift ${args.join(' ')}`);
78
- const result = execa_1.default.sync(exports.jscodeshiftExecutable, args, {
79
- stdio: 'inherit',
80
- stripFinalNewline: false,
81
- });
82
- if (result.failed) {
83
- throw new Error(`jscodeshift exited with code ${result.exitCode}`);
84
- }
85
- if (!dry && transformer === 'built-in-next-font') {
86
- console.log('Uninstalling `@next/font`');
87
- try {
88
- (0, uninstall_package_1.uninstallPackage)('@next/font');
89
- }
90
- catch (_a) {
91
- console.error("Couldn't uninstall `@next/font`, please uninstall it manually");
92
- }
93
- }
94
- }
95
- exports.runTransform = runTransform;
96
- const TRANSFORMER_INQUIRER_CHOICES = [
97
- {
98
- name: 'name-default-component: Transforms anonymous components into named components to make sure they work with Fast Refresh',
99
- value: 'name-default-component',
100
- },
101
- {
102
- name: 'add-missing-react-import: Transforms files that do not import `React` to include the import in order for the new React JSX transform',
103
- value: 'add-missing-react-import',
104
- },
105
- {
106
- name: 'withamp-to-config: Transforms the withAmp HOC into Next.js 9 page configuration',
107
- value: 'withamp-to-config',
108
- },
109
- {
110
- name: 'url-to-withrouter: Transforms the deprecated automatically injected url property on top level pages to using withRouter',
111
- value: 'url-to-withrouter',
112
- },
113
- {
114
- name: 'cra-to-next (experimental): automatically migrates a Create React App project to Next.js',
115
- value: 'cra-to-next',
116
- },
117
- {
118
- name: 'new-link: Ensures your <Link> usage is backwards compatible.',
119
- value: 'new-link',
120
- },
121
- {
122
- name: 'next-og-import: Transforms imports from `next/server` to `next/og` for usage of Dynamic OG Image Generation.',
123
- value: 'next-og-import',
124
- },
125
- {
126
- name: 'metadata-to-viewport-export: Migrates certain viewport related metadata from the `metadata` export to a new `viewport` export.',
127
- value: 'metadata-to-viewport-export',
128
- },
129
- {
130
- name: 'next-image-to-legacy-image: safely migrate Next.js 10, 11, 12 applications importing `next/image` to the renamed `next/legacy/image` import in Next.js 13',
131
- value: 'next-image-to-legacy-image',
132
- },
133
- {
134
- name: 'next-image-experimental (experimental): dangerously migrates from `next/legacy/image` to the new `next/image` by adding inline styles and removing unused props',
135
- value: 'next-image-experimental',
136
- },
137
- {
138
- name: 'built-in-next-font: Uninstall `@next/font` and transform imports to `next/font`',
139
- value: 'built-in-next-font',
140
- },
141
- ];
142
- function expandFilePathsIfNeeded(filesBeforeExpansion) {
143
- const shouldExpandFiles = filesBeforeExpansion.some((file) => file.includes('*'));
144
- return shouldExpandFiles
145
- ? globby_1.default.sync(filesBeforeExpansion)
146
- : filesBeforeExpansion;
147
- }
148
- function run() {
149
- const cli = (0, meow_1.default)({
150
- description: 'Codemods for updating Next.js apps.',
151
- help: `
152
- Usage
153
- $ npx @next/codemod <transform> <path> <...options>
154
- transform One of the choices from https://github.com/vercel/next.js/tree/canary/packages/next-codemod
155
- path Files or directory to transform. Can be a glob like pages/**.js
156
- Options
157
- --force Bypass Git safety checks and forcibly run codemods
158
- --dry Dry run (no changes are made to files)
159
- --print Print transformed files to your terminal
160
- --jscodeshift (Advanced) Pass options directly to jscodeshift
161
- `,
162
- flags: {
163
- boolean: ['force', 'dry', 'print', 'help'],
164
- string: ['_'],
165
- alias: {
166
- h: 'help',
167
- },
168
- },
169
- });
170
- if (!cli.flags.dry) {
171
- checkGitStatus(cli.flags.force);
172
- }
173
- if (cli.input[0] &&
174
- !TRANSFORMER_INQUIRER_CHOICES.find((x) => x.value === cli.input[0])) {
175
- console.error('Invalid transform choice, pick one of:');
176
- console.error(TRANSFORMER_INQUIRER_CHOICES.map((x) => '- ' + x.value).join('\n'));
177
- process.exit(1);
178
- }
179
- inquirer_1.default
180
- .prompt([
181
- {
182
- type: 'input',
183
- name: 'files',
184
- message: 'On which files or directory should the codemods be applied?',
185
- when: !cli.input[1],
186
- default: '.',
187
- // validate: () =>
188
- filter: (files) => files.trim(),
189
- },
190
- {
191
- type: 'list',
192
- name: 'transformer',
193
- message: 'Which transform would you like to apply?',
194
- when: !cli.input[0],
195
- pageSize: TRANSFORMER_INQUIRER_CHOICES.length,
196
- choices: TRANSFORMER_INQUIRER_CHOICES,
197
- },
198
- ])
199
- .then((answers) => {
200
- const { files, transformer } = answers;
201
- const filesBeforeExpansion = cli.input[1] || files;
202
- const filesExpanded = expandFilePathsIfNeeded([filesBeforeExpansion]);
203
- const selectedTransformer = cli.input[0] || transformer;
204
- if (!filesExpanded.length) {
205
- console.log(`No files found matching ${filesBeforeExpansion.join(' ')}`);
206
- return null;
207
- }
208
- return runTransform({
209
- files: filesExpanded,
210
- flags: cli.flags,
211
- transformer: selectedTransformer,
212
- });
213
- });
214
- }
215
- exports.run = run;
216
- //# sourceMappingURL=cli.js.map