@next/codemod 15.0.0-canary.18 → 15.0.0-canary.182

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.
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const GEO = 'geo';
5
+ const IP = 'ip';
6
+ const GEOLOCATION = 'geolocation';
7
+ const IP_ADDRESS = 'ipAddress';
8
+ const GEO_TYPE = 'Geo';
9
+ function default_1(fileInfo, api) {
10
+ const j = api.jscodeshift.withParser('tsx');
11
+ const root = j(fileInfo.source);
12
+ if (!root.length) {
13
+ return fileInfo.source;
14
+ }
15
+ const nextReqType = root
16
+ .find(j.FunctionDeclaration)
17
+ .find(j.Identifier, (id) => {
18
+ if (id.typeAnnotation?.type !== 'TSTypeAnnotation') {
19
+ return false;
20
+ }
21
+ const typeAnn = id.typeAnnotation.typeAnnotation;
22
+ return (typeAnn.type === 'TSTypeReference' &&
23
+ typeAnn.typeName.type === 'Identifier' &&
24
+ typeAnn.typeName.name === 'NextRequest');
25
+ });
26
+ const vercelFuncImports = root.find(j.ImportDeclaration, {
27
+ source: {
28
+ value: '@vercel/functions',
29
+ },
30
+ });
31
+ const vercelFuncImportSpecifiers = vercelFuncImports
32
+ .find(j.ImportSpecifier)
33
+ .nodes();
34
+ const vercelFuncImportNames = new Set(vercelFuncImportSpecifiers.map((node) => node.imported.name));
35
+ const hasGeolocation = vercelFuncImportNames.has(GEOLOCATION);
36
+ const hasIpAddress = vercelFuncImportNames.has(IP_ADDRESS);
37
+ const hasGeoType = vercelFuncImportNames.has(GEO_TYPE);
38
+ let identifierNames = new Set();
39
+ // if all identifiers are already imported, we don't need to create
40
+ // a unique identifier for them, therefore we don't look for all
41
+ // identifier names in the file
42
+ if (!hasGeolocation || !hasIpAddress || !hasGeoType) {
43
+ const allIdentifiers = root.find(j.Identifier).nodes();
44
+ identifierNames = new Set(allIdentifiers.map((node) => node.name));
45
+ }
46
+ let geoIdentifier = hasGeolocation
47
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, GEOLOCATION)
48
+ : getUniqueIdentifier(identifierNames, GEOLOCATION);
49
+ let ipIdentifier = hasIpAddress
50
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, IP_ADDRESS)
51
+ : getUniqueIdentifier(identifierNames, IP_ADDRESS);
52
+ let geoTypeIdentifier = hasGeoType
53
+ ? getExistingIdentifier(vercelFuncImportSpecifiers, GEO_TYPE)
54
+ : getUniqueIdentifier(identifierNames, GEO_TYPE);
55
+ let { needImportGeolocation, needImportIpAddress } = replaceGeoIpValues(j, nextReqType, geoIdentifier, ipIdentifier);
56
+ let { needImportGeoType, hasChangedIpType } = replaceGeoIpTypes(j, root, geoTypeIdentifier);
57
+ let needChanges = needImportGeolocation ||
58
+ needImportIpAddress ||
59
+ needImportGeoType ||
60
+ hasChangedIpType;
61
+ if (!needChanges) {
62
+ return fileInfo.source;
63
+ }
64
+ // Even if there was a change above, if there's an existing import,
65
+ // we don't need to import them again.
66
+ needImportGeolocation = !hasGeolocation && needImportGeolocation;
67
+ needImportIpAddress = !hasIpAddress && needImportIpAddress;
68
+ needImportGeoType = !hasGeoType && needImportGeoType;
69
+ insertImportDeclarations(j, root, vercelFuncImports, needImportGeolocation, needImportIpAddress, needImportGeoType, geoIdentifier, ipIdentifier, geoTypeIdentifier);
70
+ return root.toSource();
71
+ }
72
+ /**
73
+ * Returns an existing identifier from the Vercel functions import declaration.
74
+ */
75
+ function getExistingIdentifier(vercelFuncImportSpecifiers, identifier) {
76
+ const existingIdentifier = vercelFuncImportSpecifiers.find((node) => node.imported.name === identifier);
77
+ return (existingIdentifier?.local?.name ||
78
+ existingIdentifier.imported.name ||
79
+ identifier);
80
+ }
81
+ /**
82
+ * Returns a unique identifier by adding a suffix to the original identifier
83
+ * if it already exists in the set.
84
+ */
85
+ function getUniqueIdentifier(identifierNames, identifier) {
86
+ let suffix = 1;
87
+ let uniqueIdentifier = identifier;
88
+ while (identifierNames.has(uniqueIdentifier)) {
89
+ uniqueIdentifier = `${identifier}${suffix}`;
90
+ suffix++;
91
+ }
92
+ return uniqueIdentifier;
93
+ }
94
+ /**
95
+ * Replaces accessors `geo` and `ip` of NextRequest with corresponding
96
+ * function calls from `@vercel/functions`.
97
+ *
98
+ * Creates new variable declarations for destructuring assignments.
99
+ */
100
+ function replaceGeoIpValues(j, nextReqType, geoIdentifier, ipIdentifier) {
101
+ let needImportGeolocation = false;
102
+ let needImportIpAddress = false;
103
+ for (const nextReqPath of nextReqType.paths()) {
104
+ const fnPath = nextReqPath.parentPath.parentPath;
105
+ const fn = j(fnPath);
106
+ const blockStatement = fn.find(j.BlockStatement);
107
+ const varDeclarators = fn.find(j.VariableDeclarator);
108
+ // req.geo, req.ip
109
+ const geoAccesses = blockStatement.find(j.MemberExpression, (me) => me.object.type === 'Identifier' &&
110
+ me.object.name === nextReqPath.node.name &&
111
+ me.property.type === 'Identifier' &&
112
+ me.property.name === GEO);
113
+ const ipAccesses = blockStatement.find(j.MemberExpression, (me) => me.object.type === 'Identifier' &&
114
+ me.object.name === nextReqPath.node.name &&
115
+ me.property.type === 'Identifier' &&
116
+ me.property.name === IP);
117
+ // var { geo, ip } = req
118
+ const geoDestructuring = varDeclarators.filter((path) => path.node.id.type === 'ObjectPattern' &&
119
+ path.node.id.properties.some((prop) => prop.type === 'ObjectProperty' &&
120
+ prop.key.type === 'Identifier' &&
121
+ prop.key.name === GEO));
122
+ const ipDestructuring = varDeclarators.filter((path) => path.node.id.type === 'ObjectPattern' &&
123
+ path.node.id.properties.some((prop) => prop.type === 'ObjectProperty' &&
124
+ prop.key.type === 'Identifier' &&
125
+ prop.key.name === IP));
126
+ // geolocation(req), ipAddress(req)
127
+ const geoCall = j.callExpression(j.identifier(geoIdentifier), [
128
+ {
129
+ ...nextReqPath.node,
130
+ typeAnnotation: null,
131
+ },
132
+ ]);
133
+ const ipCall = j.callExpression(j.identifier(ipIdentifier), [
134
+ {
135
+ ...nextReqPath.node,
136
+ typeAnnotation: null,
137
+ },
138
+ ]);
139
+ geoAccesses.replaceWith(geoCall);
140
+ ipAccesses.replaceWith(ipCall);
141
+ /**
142
+ * For each destructuring assignment, we create a new variable
143
+ * declaration and insert it after the current block statement.
144
+ *
145
+ * Before:
146
+ *
147
+ * ```
148
+ * const { buildId, geo, ip } = req;
149
+ * ```
150
+ *
151
+ * After:
152
+ *
153
+ * ```
154
+ * const { buildId } = req;
155
+ * const geo = geolocation(req);
156
+ * const ip = ipAddress(req);
157
+ * ```
158
+ */
159
+ geoDestructuring.forEach((path) => {
160
+ if (path.node.id.type === 'ObjectPattern') {
161
+ const properties = path.node.id.properties;
162
+ const geoProperty = properties.find((prop) => prop.type === 'ObjectProperty' &&
163
+ prop.key.type === 'Identifier' &&
164
+ prop.key.name === GEO);
165
+ const otherProperties = properties.filter((prop) => prop !== geoProperty);
166
+ const geoDeclaration = j.variableDeclaration('const', [
167
+ j.variableDeclarator(j.identifier(
168
+ // Use alias from destructuring (if present) to retain references:
169
+ // const { geo: geoAlias } = req; -> const geoAlias = geolocation(req);
170
+ // This prevents errors from undeclared variables.
171
+ geoProperty.type === 'ObjectProperty' &&
172
+ geoProperty.value.type === 'Identifier'
173
+ ? geoProperty.value.name
174
+ : GEO), geoCall),
175
+ ]);
176
+ path.node.id.properties = otherProperties;
177
+ path.parent.insertAfter(geoDeclaration);
178
+ }
179
+ });
180
+ ipDestructuring.forEach((path) => {
181
+ if (path.node.id.type === 'ObjectPattern') {
182
+ const properties = path.node.id.properties;
183
+ const ipProperty = properties.find((prop) => prop.type === 'ObjectProperty' &&
184
+ prop.key.type === 'Identifier' &&
185
+ prop.key.name === IP);
186
+ const otherProperties = properties.filter((prop) => prop !== ipProperty);
187
+ const ipDeclaration = j.variableDeclaration('const', [
188
+ j.variableDeclarator(j.identifier(
189
+ // Use alias from destructuring (if present) to retain references:
190
+ // const { ip: ipAlias } = req; -> const ipAlias = ipAddress(req);
191
+ // This prevents errors from undeclared variables.
192
+ ipProperty.type === 'ObjectProperty' &&
193
+ ipProperty.value.type === 'Identifier'
194
+ ? ipProperty.value.name
195
+ : IP), ipCall),
196
+ ]);
197
+ path.node.id.properties = otherProperties;
198
+ path.parent.insertAfter(ipDeclaration);
199
+ }
200
+ });
201
+ needImportGeolocation =
202
+ needImportGeolocation ||
203
+ geoAccesses.length > 0 ||
204
+ geoDestructuring.length > 0;
205
+ needImportIpAddress =
206
+ needImportIpAddress || ipAccesses.length > 0 || ipDestructuring.length > 0;
207
+ }
208
+ return {
209
+ needImportGeolocation,
210
+ needImportIpAddress,
211
+ };
212
+ }
213
+ /**
214
+ * Replaces the types of `NextRequest["geo"]` and `NextRequest["ip"]` with
215
+ * corresponding types from `@vercel/functions`.
216
+ */
217
+ function replaceGeoIpTypes(j, root, geoTypeIdentifier) {
218
+ let needImportGeoType = false;
219
+ let hasChangedIpType = false;
220
+ // get the type of NextRequest that has accessed for ip and geo
221
+ // NextRequest['geo'], NextRequest['ip']
222
+ const nextReqGeoType = root.find(j.TSIndexedAccessType, (tsIndexedAccessType) => {
223
+ return (tsIndexedAccessType.objectType.type === 'TSTypeReference' &&
224
+ tsIndexedAccessType.objectType.typeName.type === 'Identifier' &&
225
+ tsIndexedAccessType.objectType.typeName.name === 'NextRequest' &&
226
+ tsIndexedAccessType.indexType.type === 'TSLiteralType' &&
227
+ tsIndexedAccessType.indexType.literal.type === 'StringLiteral' &&
228
+ tsIndexedAccessType.indexType.literal.value === GEO);
229
+ });
230
+ const nextReqIpType = root.find(j.TSIndexedAccessType, (tsIndexedAccessType) => {
231
+ return (tsIndexedAccessType.objectType.type === 'TSTypeReference' &&
232
+ tsIndexedAccessType.objectType.typeName.type === 'Identifier' &&
233
+ tsIndexedAccessType.objectType.typeName.name === 'NextRequest' &&
234
+ tsIndexedAccessType.indexType.type === 'TSLiteralType' &&
235
+ tsIndexedAccessType.indexType.literal.type === 'StringLiteral' &&
236
+ tsIndexedAccessType.indexType.literal.value === IP);
237
+ });
238
+ if (nextReqGeoType.length > 0) {
239
+ needImportGeoType = true;
240
+ // replace with type Geo
241
+ nextReqGeoType.replaceWith(j.identifier(geoTypeIdentifier));
242
+ }
243
+ if (nextReqIpType.length > 0) {
244
+ hasChangedIpType = true;
245
+ // replace with type string | undefined
246
+ nextReqIpType.replaceWith(j.tsUnionType([j.tsStringKeyword(), j.tsUndefinedKeyword()]));
247
+ }
248
+ return {
249
+ needImportGeoType,
250
+ hasChangedIpType,
251
+ };
252
+ }
253
+ /**
254
+ * Inserts import declarations from `"@vercel/functions"`.
255
+ *
256
+ * For the `Geo` type that needs to be imported to replace `NextRequest["geo"]`,
257
+ * if it is the only import needed, we import it as a type.
258
+ *
259
+ * ```ts
260
+ * import type { Geo } from "@vercel/functions";
261
+ * ```
262
+ *
263
+ * Otherwise, we import it as an inline type import.
264
+ *
265
+ * ```ts
266
+ * import { type Geo, ... } from "@vercel/functions";
267
+ * ```
268
+ */
269
+ function insertImportDeclarations(j, root, vercelFuncImports, needImportGeolocation, needImportIpAddress, needImportGeoType, geoIdentifier, ipIdentifier, geoTypeIdentifier) {
270
+ // No need inserting import.
271
+ if (!needImportGeolocation && !needImportIpAddress && !needImportGeoType) {
272
+ return;
273
+ }
274
+ // As we run this only when `NextRequest` is imported, there should be
275
+ // a "next/server" import.
276
+ const firstNextServerImport = root
277
+ .find(j.ImportDeclaration, { source: { value: 'next/server' } })
278
+ .at(0);
279
+ const firstVercelFuncImport = vercelFuncImports.at(0);
280
+ const hasVercelFuncImport = firstVercelFuncImport.length > 0;
281
+ // If there's no "@vercel/functions" import, and we only need to import
282
+ // `Geo` type, we create a type import to avoid side effect with
283
+ // `verbatimModuleSyntax`.
284
+ // x-ref: https://typescript-eslint.io/rules/no-import-type-side-effects
285
+ if (!hasVercelFuncImport &&
286
+ !needImportGeolocation &&
287
+ !needImportIpAddress &&
288
+ needImportGeoType) {
289
+ const geoTypeImportDeclaration = j.importDeclaration([
290
+ needImportGeoType
291
+ ? j.importSpecifier(j.identifier(GEO_TYPE), j.identifier(geoTypeIdentifier))
292
+ : null,
293
+ ].filter(Boolean), j.literal('@vercel/functions'),
294
+ // import type { Geo } ...
295
+ 'type');
296
+ firstNextServerImport.insertAfter(geoTypeImportDeclaration);
297
+ return;
298
+ }
299
+ const importDeclaration = j.importDeclaration([
300
+ // If there was a duplicate identifier, we add an
301
+ // incremental number suffix to it and we use alias:
302
+ // `import { geolocation as geolocation1 } from ...`
303
+ needImportGeolocation
304
+ ? j.importSpecifier(j.identifier(GEOLOCATION), j.identifier(geoIdentifier))
305
+ : null,
306
+ needImportIpAddress
307
+ ? j.importSpecifier(j.identifier(IP_ADDRESS), j.identifier(ipIdentifier))
308
+ : null,
309
+ needImportGeoType
310
+ ? j.importSpecifier(j.identifier(GEO_TYPE), j.identifier(geoTypeIdentifier))
311
+ : null,
312
+ ].filter(Boolean), j.literal('@vercel/functions'));
313
+ if (hasVercelFuncImport) {
314
+ firstVercelFuncImport
315
+ .get()
316
+ .node.specifiers.push(...importDeclaration.specifiers);
317
+ if (needImportGeoType) {
318
+ const targetGeo = firstVercelFuncImport
319
+ .get()
320
+ .node.specifiers.find((specifier) => specifier.imported.name === GEO_TYPE);
321
+ if (targetGeo) {
322
+ targetGeo.importKind = 'type';
323
+ }
324
+ }
325
+ }
326
+ else {
327
+ if (needImportGeoType) {
328
+ const targetGeo = importDeclaration.specifiers.find((specifier) => specifier.type === 'ImportSpecifier' &&
329
+ specifier.imported.name === GEO_TYPE);
330
+ if (targetGeo) {
331
+ // @ts-expect-error -- Missing types in jscodeshift.
332
+ targetGeo.importKind = 'type';
333
+ }
334
+ }
335
+ firstNextServerImport.insertAfter(importDeclaration);
336
+ }
337
+ }
338
+ //# 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
@@ -1,32 +0,0 @@
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.uninstallPackage = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const execa_1 = __importDefault(require("execa"));
10
- function getPkgManager(baseDir) {
11
- for (const { lockFile, packageManager } of [
12
- { lockFile: 'yarn.lock', packageManager: 'yarn' },
13
- { lockFile: 'pnpm-lock.yaml', packageManager: 'pnpm' },
14
- { lockFile: 'package-lock.json', packageManager: 'npm' },
15
- ]) {
16
- if (fs_1.default.existsSync(path_1.default.join(baseDir, lockFile))) {
17
- return packageManager;
18
- }
19
- }
20
- }
21
- function uninstallPackage(packageToUninstall) {
22
- const pkgManager = getPkgManager(process.cwd());
23
- if (!pkgManager)
24
- throw new Error('Failed to find package manager');
25
- let command = 'uninstall';
26
- if (pkgManager === 'yarn') {
27
- command = 'remove';
28
- }
29
- execa_1.default.sync(pkgManager, [command, packageToUninstall], { stdio: 'inherit' });
30
- }
31
- exports.uninstallPackage = uninstallPackage;
32
- //# sourceMappingURL=uninstall-package.js.map