@next/codemod 15.0.0-canary.167 → 15.0.0-canary.169

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.
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
@@ -33,6 +24,18 @@ const craTransformsPath = path_1.default.join('../lib/cra-to-next');
33
24
  const globalCssTransformPath = require.resolve(path_1.default.join(craTransformsPath, 'global-css-transform.js'));
34
25
  const indexTransformPath = require.resolve(path_1.default.join(craTransformsPath, 'index-to-component.js'));
35
26
  class CraTransform {
27
+ appDir;
28
+ pagesDir;
29
+ isVite;
30
+ isCra;
31
+ isDryRun;
32
+ indexPage;
33
+ installClient;
34
+ shouldLogInfo;
35
+ packageJsonPath;
36
+ shouldUseTypeScript;
37
+ packageJsonData;
38
+ jscodeShiftFlags;
36
39
  constructor(files, flags) {
37
40
  this.isDryRun = flags.dry;
38
41
  this.jscodeShiftFlags = flags;
@@ -43,7 +46,7 @@ class CraTransform {
43
46
  this.pagesDir = this.getPagesDir();
44
47
  this.installClient = this.checkForYarn() ? 'yarn' : 'npm';
45
48
  const { dependencies, devDependencies } = this.packageJsonData;
46
- const hasDep = (dep) => (dependencies === null || dependencies === void 0 ? void 0 : dependencies[dep]) || (devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[dep]);
49
+ const hasDep = (dep) => dependencies?.[dep] || devDependencies?.[dep];
47
50
  this.isCra = hasDep('react-scripts');
48
51
  this.isVite = !this.isCra && hasDep('vite');
49
52
  if (!this.isCra && !this.isVite) {
@@ -61,45 +64,43 @@ class CraTransform {
61
64
  fatalMessage('Error: unable to find `src/index`');
62
65
  }
63
66
  }
64
- transform() {
65
- return __awaiter(this, void 0, void 0, function* () {
66
- console.log('Transforming CRA project at:', this.appDir);
67
- // convert src/index.js to a react component to render
68
- // inside of Next.js instead of the custom render root
69
- const indexTransformRes = yield (0, run_jscodeshift_1.default)(indexTransformPath, Object.assign(Object.assign({}, this.jscodeShiftFlags), { silent: true, verbose: 0 }), [path_1.default.join(this.appDir, 'src', this.indexPage)]);
70
- if (indexTransformRes.error > 0) {
71
- fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
72
- }
73
- if (index_to_component_1.indexContext.multipleRenderRoots) {
74
- fatalMessage(`Error: multiple ReactDOM.render roots in src/${this.indexPage}, migrate additional render roots to use portals instead to continue.\n` +
75
- `See here for more info: https://react.dev/reference/react-dom/createPortal`);
76
- }
77
- if (index_to_component_1.indexContext.nestedRender) {
78
- fatalMessage(`Error: nested ReactDOM.render found in src/${this.indexPage}, please migrate this to a top-level render (no wrapping functions) to continue`);
79
- }
80
- // comment out global style imports and collect them
81
- // so that we can add them to _app
82
- const globalCssRes = yield (0, run_jscodeshift_1.default)(globalCssTransformPath, Object.assign({}, this.jscodeShiftFlags), [this.appDir]);
83
- if (globalCssRes.error > 0) {
84
- fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
85
- }
86
- if (!this.isDryRun) {
87
- yield fs_1.default.promises.mkdir(path_1.default.join(this.appDir, this.pagesDir));
88
- }
89
- this.logCreate(this.pagesDir);
90
- if (global_css_transform_1.globalCssContext.reactSvgImports.size > 0) {
91
- // This de-opts webpack 5 since svg/webpack doesn't support webpack 5 yet,
92
- // so we don't support this automatically
93
- fatalMessage(`Error: import {ReactComponent} from './logo.svg' is not supported, please use normal SVG imports to continue.\n` +
94
- `React SVG imports found in:\n${[
95
- ...global_css_transform_1.globalCssContext.reactSvgImports,
96
- ].join('\n')}`);
97
- }
98
- yield this.updatePackageJson();
99
- yield this.createNextConfig();
100
- yield this.updateGitIgnore();
101
- yield this.createPages();
102
- });
67
+ async transform() {
68
+ console.log('Transforming CRA project at:', this.appDir);
69
+ // convert src/index.js to a react component to render
70
+ // inside of Next.js instead of the custom render root
71
+ const indexTransformRes = await (0, run_jscodeshift_1.default)(indexTransformPath, { ...this.jscodeShiftFlags, silent: true, verbose: 0 }, [path_1.default.join(this.appDir, 'src', this.indexPage)]);
72
+ if (indexTransformRes.error > 0) {
73
+ fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
74
+ }
75
+ if (index_to_component_1.indexContext.multipleRenderRoots) {
76
+ fatalMessage(`Error: multiple ReactDOM.render roots in src/${this.indexPage}, migrate additional render roots to use portals instead to continue.\n` +
77
+ `See here for more info: https://react.dev/reference/react-dom/createPortal`);
78
+ }
79
+ if (index_to_component_1.indexContext.nestedRender) {
80
+ fatalMessage(`Error: nested ReactDOM.render found in src/${this.indexPage}, please migrate this to a top-level render (no wrapping functions) to continue`);
81
+ }
82
+ // comment out global style imports and collect them
83
+ // so that we can add them to _app
84
+ const globalCssRes = await (0, run_jscodeshift_1.default)(globalCssTransformPath, { ...this.jscodeShiftFlags }, [this.appDir]);
85
+ if (globalCssRes.error > 0) {
86
+ fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
87
+ }
88
+ if (!this.isDryRun) {
89
+ await fs_1.default.promises.mkdir(path_1.default.join(this.appDir, this.pagesDir));
90
+ }
91
+ this.logCreate(this.pagesDir);
92
+ if (global_css_transform_1.globalCssContext.reactSvgImports.size > 0) {
93
+ // This de-opts webpack 5 since svg/webpack doesn't support webpack 5 yet,
94
+ // so we don't support this automatically
95
+ fatalMessage(`Error: import {ReactComponent} from './logo.svg' is not supported, please use normal SVG imports to continue.\n` +
96
+ `React SVG imports found in:\n${[
97
+ ...global_css_transform_1.globalCssContext.reactSvgImports,
98
+ ].join('\n')}`);
99
+ }
100
+ await this.updatePackageJson();
101
+ await this.createNextConfig();
102
+ await this.updateGitIgnore();
103
+ await this.createPages();
103
104
  }
104
105
  checkForYarn() {
105
106
  try {
@@ -130,112 +131,111 @@ class CraTransform {
130
131
  console.log(...args);
131
132
  }
132
133
  }
133
- createPages() {
134
- return __awaiter(this, void 0, void 0, function* () {
135
- // load public/index.html and add tags to _document
136
- const htmlContent = yield fs_1.default.promises.readFile(path_1.default.join(this.appDir, `${this.isCra ? 'public/' : ''}index.html`), 'utf8');
137
- const $ = cheerio_1.default.load(htmlContent);
138
- // note: title tag and meta[viewport] needs to be placed in _app
139
- // not _document
140
- const titleTag = $('title')[0];
141
- const metaViewport = $('meta[name="viewport"]')[0];
142
- const headTags = $('head').children();
143
- const bodyTags = $('body').children();
144
- const pageExt = this.shouldUseTypeScript ? 'tsx' : 'js';
145
- const appPage = path_1.default.join(this.pagesDir, `_app.${pageExt}`);
146
- const documentPage = path_1.default.join(this.pagesDir, `_document.${pageExt}`);
147
- const catchAllPage = path_1.default.join(this.pagesDir, `[[...slug]].${pageExt}`);
148
- const gatherTextChildren = (children) => {
149
- return children
150
- .map((child) => {
151
- if (child.type === 'text') {
152
- return child.data;
153
- }
154
- return '';
155
- })
156
- .join('');
157
- };
158
- const serializeAttrs = (attrs) => {
159
- const attrStr = Object.keys(attrs || {})
160
- .map((name) => {
161
- const reactName = html_to_react_attributes_1.default[name] || name;
162
- const value = attrs[name];
163
- // allow process.env access to work dynamically still
164
- if (value.match(/%([a-zA-Z0-9_]{0,})%/)) {
165
- return `${reactName}={\`${value.replace(/%([a-zA-Z0-9_]{0,})%/g, (subStr) => {
166
- return `\${process.env.${subStr.slice(1, -1)}}`;
167
- })}\`}`;
168
- }
169
- return `${reactName}="${value}"`;
170
- })
171
- .join(' ');
172
- return attrStr.length > 0 ? ` ${attrStr}` : '';
173
- };
174
- const serializedHeadTags = [];
175
- const serializedBodyTags = [];
176
- headTags.map((_index, element) => {
177
- if (element.tagName === 'title' ||
178
- (element.tagName === 'meta' && element.attribs.name === 'viewport')) {
179
- return element;
134
+ async createPages() {
135
+ // load public/index.html and add tags to _document
136
+ const htmlContent = await fs_1.default.promises.readFile(path_1.default.join(this.appDir, `${this.isCra ? 'public/' : ''}index.html`), 'utf8');
137
+ const $ = cheerio_1.default.load(htmlContent);
138
+ // note: title tag and meta[viewport] needs to be placed in _app
139
+ // not _document
140
+ const titleTag = $('title')[0];
141
+ const metaViewport = $('meta[name="viewport"]')[0];
142
+ const headTags = $('head').children();
143
+ const bodyTags = $('body').children();
144
+ const pageExt = this.shouldUseTypeScript ? 'tsx' : 'js';
145
+ const appPage = path_1.default.join(this.pagesDir, `_app.${pageExt}`);
146
+ const documentPage = path_1.default.join(this.pagesDir, `_document.${pageExt}`);
147
+ const catchAllPage = path_1.default.join(this.pagesDir, `[[...slug]].${pageExt}`);
148
+ const gatherTextChildren = (children) => {
149
+ return children
150
+ .map((child) => {
151
+ if (child.type === 'text') {
152
+ return child.data;
180
153
  }
181
- let hasChildren = element.children.length > 0;
182
- let serializedAttrs = serializeAttrs(element.attribs);
183
- if (element.tagName === 'script' || element.tagName === 'style') {
184
- hasChildren = false;
185
- serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
154
+ return '';
155
+ })
156
+ .join('');
157
+ };
158
+ const serializeAttrs = (attrs) => {
159
+ const attrStr = Object.keys(attrs || {})
160
+ .map((name) => {
161
+ const reactName = html_to_react_attributes_1.default[name] || name;
162
+ const value = attrs[name];
163
+ // allow process.env access to work dynamically still
164
+ if (value.match(/%([a-zA-Z0-9_]{0,})%/)) {
165
+ return `${reactName}={\`${value.replace(/%([a-zA-Z0-9_]{0,})%/g, (subStr) => {
166
+ return `\${process.env.${subStr.slice(1, -1)}}`;
167
+ })}\`}`;
186
168
  }
187
- serializedHeadTags.push(hasChildren
188
- ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
189
- : `<${element.tagName}${serializedAttrs} />`);
169
+ return `${reactName}="${value}"`;
170
+ })
171
+ .join(' ');
172
+ return attrStr.length > 0 ? ` ${attrStr}` : '';
173
+ };
174
+ const serializedHeadTags = [];
175
+ const serializedBodyTags = [];
176
+ headTags.map((_index, element) => {
177
+ if (element.tagName === 'title' ||
178
+ (element.tagName === 'meta' && element.attribs.name === 'viewport')) {
190
179
  return element;
191
- });
192
- bodyTags.map((_index, element) => {
193
- if (element.tagName === 'div' && element.attribs.id === 'root') {
194
- return element;
195
- }
196
- let hasChildren = element.children.length > 0;
197
- let serializedAttrs = serializeAttrs(element.attribs);
198
- if (element.tagName === 'script' || element.tagName === 'style') {
199
- hasChildren = false;
200
- serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
201
- }
202
- serializedHeadTags.push(hasChildren
203
- ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
204
- : `<${element.tagName}${serializedAttrs} />`);
180
+ }
181
+ let hasChildren = element.children.length > 0;
182
+ let serializedAttrs = serializeAttrs(element.attribs);
183
+ if (element.tagName === 'script' || element.tagName === 'style') {
184
+ hasChildren = false;
185
+ serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
186
+ }
187
+ serializedHeadTags.push(hasChildren
188
+ ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
189
+ : `<${element.tagName}${serializedAttrs} />`);
190
+ return element;
191
+ });
192
+ bodyTags.map((_index, element) => {
193
+ if (element.tagName === 'div' && element.attribs.id === 'root') {
205
194
  return element;
206
- });
207
- if (!this.isDryRun) {
208
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, appPage), `${global_css_transform_1.globalCssContext.cssImports.size === 0
209
- ? ''
210
- : [...global_css_transform_1.globalCssContext.cssImports]
211
- .map((file) => {
212
- if (!this.isCra) {
213
- file = file.startsWith('/') ? file.slice(1) : file;
214
- }
215
- return `import '${file.startsWith('/')
216
- ? path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), file)
217
- : file}'`;
218
- })
219
- .join('\n') + '\n'}${titleTag ? `import Head from 'next/head'` : ''}
195
+ }
196
+ let hasChildren = element.children.length > 0;
197
+ let serializedAttrs = serializeAttrs(element.attribs);
198
+ if (element.tagName === 'script' || element.tagName === 'style') {
199
+ hasChildren = false;
200
+ serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
201
+ }
202
+ serializedHeadTags.push(hasChildren
203
+ ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
204
+ : `<${element.tagName}${serializedAttrs} />`);
205
+ return element;
206
+ });
207
+ if (!this.isDryRun) {
208
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, appPage), `${global_css_transform_1.globalCssContext.cssImports.size === 0
209
+ ? ''
210
+ : [...global_css_transform_1.globalCssContext.cssImports]
211
+ .map((file) => {
212
+ if (!this.isCra) {
213
+ file = file.startsWith('/') ? file.slice(1) : file;
214
+ }
215
+ return `import '${file.startsWith('/')
216
+ ? path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), file)
217
+ : file}'`;
218
+ })
219
+ .join('\n') + '\n'}${titleTag ? `import Head from 'next/head'` : ''}
220
220
 
221
221
  export default function MyApp({ Component, pageProps}) {
222
222
  ${titleTag || metaViewport
223
- ? `return (
223
+ ? `return (
224
224
  <>
225
225
  <Head>
226
226
  ${titleTag
227
- ? `<title${serializeAttrs(titleTag.attribs)}>${gatherTextChildren(titleTag.children)}</title>`
228
- : ''}
227
+ ? `<title${serializeAttrs(titleTag.attribs)}>${gatherTextChildren(titleTag.children)}</title>`
228
+ : ''}
229
229
  ${metaViewport ? `<meta${serializeAttrs(metaViewport.attribs)} />` : ''}
230
230
  </Head>
231
231
 
232
232
  <Component {...pageProps} />
233
233
  </>
234
234
  )`
235
- : 'return <Component {...pageProps} />'}
235
+ : 'return <Component {...pageProps} />'}
236
236
  }
237
237
  `);
238
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, documentPage), `import Document, { Html, Head, Main, NextScript } from 'next/document'
238
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, documentPage), `import Document, { Html, Head, Main, NextScript } from 'next/document'
239
239
 
240
240
  class MyDocument extends Document {
241
241
  render() {
@@ -257,11 +257,11 @@ class MyDocument extends Document {
257
257
 
258
258
  export default MyDocument
259
259
  `);
260
- const relativeIndexPath = path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), path_1.default.join(this.appDir, 'src', this.isCra ? '' : 'main'));
261
- // TODO: should we default to ssr: true below and recommend they
262
- // set it to false if they encounter errors or prefer the more safe
263
- // option to prevent their first start from having any errors?
264
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, catchAllPage), `// import NextIndexWrapper from '${relativeIndexPath}'
260
+ const relativeIndexPath = path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), path_1.default.join(this.appDir, 'src', this.isCra ? '' : 'main'));
261
+ // TODO: should we default to ssr: true below and recommend they
262
+ // set it to false if they encounter errors or prefer the more safe
263
+ // option to prevent their first start from having any errors?
264
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, catchAllPage), `// import NextIndexWrapper from '${relativeIndexPath}'
265
265
 
266
266
  // next/dynamic is used to prevent breaking incompatibilities
267
267
  // with SSR from window.SOME_VAR usage, if this is not used
@@ -277,90 +277,95 @@ export default function Page(props) {
277
277
  return <NextIndexWrapper {...props} />
278
278
  }
279
279
  `);
280
- }
281
- this.logCreate(appPage);
282
- this.logCreate(documentPage);
283
- this.logCreate(catchAllPage);
284
- });
280
+ }
281
+ this.logCreate(appPage);
282
+ this.logCreate(documentPage);
283
+ this.logCreate(catchAllPage);
285
284
  }
286
- updatePackageJson() {
287
- return __awaiter(this, void 0, void 0, function* () {
288
- // rename react-scripts -> next and react-scripts test -> jest
289
- // add needed dependencies for webpack compatibility
290
- const newDependencies = [
291
- // TODO: do we want to install jest automatically?
292
- {
293
- name: 'next',
294
- version: 'latest',
295
- },
296
- ];
297
- const packageName = this.isCra ? 'react-scripts' : 'vite';
298
- const packagesToRemove = {
299
- [packageName]: undefined,
300
- };
301
- const neededDependencies = [];
302
- const { devDependencies, dependencies, scripts } = this.packageJsonData;
303
- for (const dep of newDependencies) {
304
- if (!(devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[dep.name]) && !(dependencies === null || dependencies === void 0 ? void 0 : dependencies[dep.name])) {
305
- neededDependencies.push(`${dep.name}@${dep.version}`);
306
- }
285
+ async updatePackageJson() {
286
+ // rename react-scripts -> next and react-scripts test -> jest
287
+ // add needed dependencies for webpack compatibility
288
+ const newDependencies = [
289
+ // TODO: do we want to install jest automatically?
290
+ {
291
+ name: 'next',
292
+ version: 'latest',
293
+ },
294
+ ];
295
+ const packageName = this.isCra ? 'react-scripts' : 'vite';
296
+ const packagesToRemove = {
297
+ [packageName]: undefined,
298
+ };
299
+ const neededDependencies = [];
300
+ const { devDependencies, dependencies, scripts } = this.packageJsonData;
301
+ for (const dep of newDependencies) {
302
+ if (!devDependencies?.[dep.name] && !dependencies?.[dep.name]) {
303
+ neededDependencies.push(`${dep.name}@${dep.version}`);
307
304
  }
308
- this.logInfo(`Installing ${neededDependencies.join(' ')} with ${this.installClient}`);
309
- if (!this.isDryRun) {
310
- yield fs_1.default.promises.writeFile(this.packageJsonPath, JSON.stringify(Object.assign(Object.assign({}, this.packageJsonData), { scripts: Object.keys(scripts).reduce((prev, cur) => {
311
- const command = scripts[cur];
312
- prev[cur] = command;
313
- if (command === packageName) {
314
- prev[cur] = 'next dev';
315
- }
316
- if (command.includes(`${packageName} `)) {
317
- prev[cur] = command.replace(`${packageName} `, command.includes(`${packageName} test`) ? 'jest ' : 'next ');
318
- }
319
- if (cur === 'eject') {
320
- prev[cur] = undefined;
321
- }
322
- // TODO: do we want to map start -> next start instead of CRA's
323
- // default of mapping starting to dev mode?
324
- if (cur === 'start') {
325
- prev[cur] = prev[cur].replace('next start', 'next dev');
326
- prev['start-production'] = 'next start';
327
- }
328
- return prev;
329
- }, {}), dependencies: Object.assign(Object.assign({}, dependencies), packagesToRemove), devDependencies: Object.assign(Object.assign({}, devDependencies), packagesToRemove) }), null, 2));
330
- yield (0, install_1.install)(this.appDir, neededDependencies, {
331
- useYarn: this.installClient === 'yarn',
332
- // do we want to detect offline as well? they might not
333
- // have next in the local cache already
334
- isOnline: true,
335
- });
336
- }
337
- });
338
- }
339
- updateGitIgnore() {
340
- return __awaiter(this, void 0, void 0, function* () {
341
- // add Next.js specific items to .gitignore e.g. '.next'
342
- const gitignorePath = path_1.default.join(this.appDir, '.gitignore');
343
- let ignoreContent = yield fs_1.default.promises.readFile(gitignorePath, 'utf8');
344
- const nextIgnores = (yield fs_1.default.promises.readFile(path_1.default.join(path_1.default.dirname(globalCssTransformPath), 'gitignore'), 'utf8')).split('\n');
345
- if (!this.isDryRun) {
346
- for (const ignore of nextIgnores) {
347
- if (!ignoreContent.includes(ignore)) {
348
- ignoreContent += `\n${ignore}`;
305
+ }
306
+ this.logInfo(`Installing ${neededDependencies.join(' ')} with ${this.installClient}`);
307
+ if (!this.isDryRun) {
308
+ await fs_1.default.promises.writeFile(this.packageJsonPath, JSON.stringify({
309
+ ...this.packageJsonData,
310
+ scripts: Object.keys(scripts).reduce((prev, cur) => {
311
+ const command = scripts[cur];
312
+ prev[cur] = command;
313
+ if (command === packageName) {
314
+ prev[cur] = 'next dev';
315
+ }
316
+ if (command.includes(`${packageName} `)) {
317
+ prev[cur] = command.replace(`${packageName} `, command.includes(`${packageName} test`) ? 'jest ' : 'next ');
318
+ }
319
+ if (cur === 'eject') {
320
+ prev[cur] = undefined;
349
321
  }
322
+ // TODO: do we want to map start -> next start instead of CRA's
323
+ // default of mapping starting to dev mode?
324
+ if (cur === 'start') {
325
+ prev[cur] = prev[cur].replace('next start', 'next dev');
326
+ prev['start-production'] = 'next start';
327
+ }
328
+ return prev;
329
+ }, {}),
330
+ dependencies: {
331
+ ...dependencies,
332
+ ...packagesToRemove,
333
+ },
334
+ devDependencies: {
335
+ ...devDependencies,
336
+ ...packagesToRemove,
337
+ },
338
+ }, null, 2));
339
+ await (0, install_1.install)(this.appDir, neededDependencies, {
340
+ useYarn: this.installClient === 'yarn',
341
+ // do we want to detect offline as well? they might not
342
+ // have next in the local cache already
343
+ isOnline: true,
344
+ });
345
+ }
346
+ }
347
+ async updateGitIgnore() {
348
+ // add Next.js specific items to .gitignore e.g. '.next'
349
+ const gitignorePath = path_1.default.join(this.appDir, '.gitignore');
350
+ let ignoreContent = await fs_1.default.promises.readFile(gitignorePath, 'utf8');
351
+ const nextIgnores = (await fs_1.default.promises.readFile(path_1.default.join(path_1.default.dirname(globalCssTransformPath), 'gitignore'), 'utf8')).split('\n');
352
+ if (!this.isDryRun) {
353
+ for (const ignore of nextIgnores) {
354
+ if (!ignoreContent.includes(ignore)) {
355
+ ignoreContent += `\n${ignore}`;
350
356
  }
351
- yield fs_1.default.promises.writeFile(gitignorePath, ignoreContent);
352
357
  }
353
- this.logModify('.gitignore');
354
- });
358
+ await fs_1.default.promises.writeFile(gitignorePath, ignoreContent);
359
+ }
360
+ this.logModify('.gitignore');
355
361
  }
356
- createNextConfig() {
357
- return __awaiter(this, void 0, void 0, function* () {
358
- if (!this.isDryRun) {
359
- const { proxy, homepage } = this.packageJsonData;
360
- const homepagePath = new URL(homepage || '/', 'http://example.com')
361
- .pathname;
362
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, 'next.config.js'), `module.exports = {${proxy
363
- ? `
362
+ async createNextConfig() {
363
+ if (!this.isDryRun) {
364
+ const { proxy, homepage } = this.packageJsonData;
365
+ const homepagePath = new URL(homepage || '/', 'http://example.com')
366
+ .pathname;
367
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, 'next.config.js'), `module.exports = {${proxy
368
+ ? `
364
369
  async rewrites() {
365
370
  return {
366
371
  fallback: [
@@ -371,7 +376,7 @@ export default function Page(props) {
371
376
  ]
372
377
  }
373
378
  },`
374
- : ''}
379
+ : ''}
375
380
  env: {
376
381
  PUBLIC_URL: '${homepagePath === '/' ? '' : homepagePath || ''}'
377
382
  },
@@ -385,9 +390,8 @@ export default function Page(props) {
385
390
  }
386
391
  }
387
392
  `);
388
- }
389
- this.logCreate('next.config.js');
390
- });
393
+ }
394
+ this.logCreate('next.config.js');
391
395
  }
392
396
  getPagesDir() {
393
397
  // prefer src/pages as CRA uses the src dir by default
@@ -429,16 +433,14 @@ export default function Page(props) {
429
433
  return appDir;
430
434
  }
431
435
  }
432
- function transformer(files, flags) {
433
- return __awaiter(this, void 0, void 0, function* () {
434
- try {
435
- const craTransform = new CraTransform(files, flags);
436
- yield craTransform.transform();
437
- console.log(`CRA to Next.js migration complete`, `\n${feedbackMessage}`);
438
- }
439
- catch (err) {
440
- fatalMessage(`Error: failed to complete transform`, err);
441
- }
442
- });
436
+ async function transformer(files, flags) {
437
+ try {
438
+ const craTransform = new CraTransform(files, flags);
439
+ await craTransform.transform();
440
+ console.log(`CRA to Next.js migration complete`, `\n${feedbackMessage}`);
441
+ }
442
+ catch (err) {
443
+ fatalMessage(`Error: failed to complete transform`, err);
444
+ }
443
445
  }
444
446
  //# sourceMappingURL=cra-to-next.js.map
@@ -28,7 +28,6 @@ function transformDynamicAPI(source, api, filePath) {
28
28
  },
29
29
  })
30
30
  .forEach((path) => {
31
- var _a, _b, _c;
32
31
  const isImportedTopLevel = isImportedInModule(path, asyncRequestApiName);
33
32
  if (!isImportedTopLevel) {
34
33
  return;
@@ -46,7 +45,7 @@ function transformDynamicAPI(source, api, filePath) {
46
45
  const isAsyncFunction = closestFunction
47
46
  .nodes()
48
47
  .some((node) => node.async);
49
- const isCallAwaited = ((_b = (_a = path.parentPath) === null || _a === void 0 ? void 0 : _a.node) === null || _b === void 0 ? void 0 : _b.type) === 'AwaitExpression';
48
+ const isCallAwaited = path.parentPath?.node?.type === 'AwaitExpression';
50
49
  const hasChainAccess = path.parentPath.value.type === 'MemberExpression' &&
51
50
  path.parentPath.value.object === path.node;
52
51
  // For cookies/headers API, only transform server and shared components
@@ -107,8 +106,8 @@ function transformDynamicAPI(source, api, filePath) {
107
106
  j(path).closest(j.FunctionExpression) ||
108
107
  j(path).closest(j.ArrowFunctionExpression);
109
108
  if (parentFunction.size() > 0) {
110
- const parentFunctionName = (_c = parentFunction.get().node.id) === null || _c === void 0 ? void 0 : _c.name;
111
- const isParentFunctionHook = parentFunctionName === null || parentFunctionName === void 0 ? void 0 : parentFunctionName.startsWith('use');
109
+ const parentFunctionName = parentFunction.get().node.id?.name;
110
+ const isParentFunctionHook = parentFunctionName?.startsWith('use');
112
111
  if (isParentFunctionHook) {
113
112
  j(path).replaceWith(j.callExpression(j.identifier('use'), [
114
113
  j.callExpression(j.identifier(asyncRequestApiName), []),