@startupjs/cli 0.56.0-alpha.6 → 0.57.0-canary.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/index.js CHANGED
@@ -1,682 +1,36 @@
1
- const commander = require('commander')
2
- const execa = require('execa')
3
- const path = require('path')
4
- const fs = require('fs')
5
- const template = require('lodash/template')
6
- const CLI_VERSION = require('./package.json').version
1
+ import { Command } from 'commander'
2
+ import url from 'url'
3
+ import { dirname, join } from 'path'
4
+ import { readFileSync } from 'fs'
5
+ import * as commands from './commands/index.js'
7
6
 
8
- const IS_PRERELEASE = /(?:alpha|canary)/.test(CLI_VERSION)
9
- const STARTUPJS_VERSION = IS_PRERELEASE ? `^${CLI_VERSION.replace(/\.\d+$/, '.0')}` : 'latest'
7
+ const __filename = url.fileURLToPath(import.meta.url)
8
+ const packageJson = JSON.parse(readFileSync(join(dirname(__filename), 'package.json')))
10
9
 
11
- let PATCHES_DIR
12
- try {
13
- PATCHES_DIR = path.join(
14
- path.dirname(require.resolve('@startupjs/patches')),
15
- 'patches'
16
- )
17
- // patch-package requires the path to be relative
18
- PATCHES_DIR = path.relative(process.cwd(), PATCHES_DIR)
19
- } catch (err) {
20
- console.error(err)
21
- console.error('ERROR!!! Patches packages not found. Falling back to local patches folder')
22
- PATCHES_DIR = './patches'
23
- }
24
-
25
- let PM_SCRIPTS_PATH
26
- try {
27
- PM_SCRIPTS_PATH = path.join(
28
- path.dirname(require.resolve('@startupjs/pm')),
29
- 'scripts.sh'
30
- )
31
- } catch (err) {
32
- console.error(err)
33
- console.error('ERROR!!! @startupjs/pm package wasn\'t found.')
34
- }
35
-
36
- let PATCHES_GESTURE_HANDLER_DIR
37
- try {
38
- PATCHES_GESTURE_HANDLER_DIR = path.join(
39
- path.dirname(require.resolve('@startupjs/patches')),
40
- 'patches_gestureHandler'
41
- )
42
- // patch-package requires the path to be relative
43
- PATCHES_GESTURE_HANDLER_DIR = path.relative(process.cwd(), PATCHES_GESTURE_HANDLER_DIR)
44
- } catch (err) {
45
- console.error(err)
46
- console.error('ERROR!!! Gesture handler patches not found.')
47
- }
48
-
49
- const LINK = !!process.env.LINK
50
- const LOCAL_DIR = process.env.LOCAL_DIR || '.'
51
-
52
- const DEPENDENCIES = [
53
- // Install alpha version of startupjs when running the alpha of cli
54
- `startupjs@${STARTUPJS_VERSION}`,
55
- 'react-native-svg@^14.0.0',
56
- 'nconf@^0.10.0',
57
- 'react',
58
- 'react-dom',
59
- 'axios@^0.26.0' // For making AJAX requests
60
- ]
61
-
62
- const DEV_DEPENDENCIES = [
63
- 'eslint@latest',
64
- 'eslint-config-startupjs',
65
- 'husky@^4.3.0',
66
- 'lint-staged'
67
- ]
68
-
69
- const REMOVE_DEPENDENCIES = [
70
- '@babel/core',
71
- '@babel/runtime',
72
- '@react-native/eslint-config',
73
- 'metro-react-native-babel-preset'
74
- ]
75
-
76
- const REMOVE_FILES = [
77
- '.prettierrc.js',
78
- '.eslintrc.js',
79
- '.flowconfig',
80
- 'App.js',
81
- 'babel.config.js',
82
- 'metro.config.js'
83
- ]
84
-
85
- const SCRIPTS_ORIG = {}
86
-
87
- // Development
88
-
89
- SCRIPTS_ORIG.start = ({ inspect } = {}) => oneLine(`
90
- npx concurrently
91
- "${SCRIPTS_ORIG.web}"
92
- "${SCRIPTS_ORIG.server({ inspect })}"
93
- `)
94
-
95
- // Web
96
-
97
- SCRIPTS_ORIG.web = oneLine(`
98
- npx cross-env WEBPACK_DEV=1
99
- npx webpack-dev-server --config webpack.web.config.cjs
100
- `)
101
-
102
- // Server
103
-
104
- SCRIPTS_ORIG.server = ({ inspect } = {}) => oneLine(`
105
- node
106
- ${inspect ? '--inspect' : ''}
107
- --watch
108
- --experimental-detect-module
109
- server.js
110
- `)
111
-
112
- // Production
113
-
114
- SCRIPTS_ORIG.build = ({ async } = {}) => oneLine(`
115
- npx rimraf ./build &&
116
- ${async ? 'npx cross-env ASYNC=1' : ''}
117
- npx webpack --config webpack.web.config.cjs
118
- `)
119
-
120
- SCRIPTS_ORIG.expoBuild = ({ async } = {}) => oneLine(`
121
- npx expo export -p web
122
- `)
123
-
124
- SCRIPTS_ORIG.startProduction = oneLine(`
125
- npx cross-env NODE_ENV=production
126
- node --experimental-detect-module server.js
127
- `)
128
-
129
- SCRIPTS_ORIG.expoStartProduction = oneLine(`
130
- npx cross-env NODE_ENV=production
131
- node --experimental-detect-module --import='startupjs/nodeRegister' -e 'import("startupjs/startServer")'
132
- `)
133
-
134
- // Etc
135
-
136
- SCRIPTS_ORIG.patchPackage = () => oneLine(`
137
- npx patch-package --patch-dir ${PATCHES_DIR} && ${SCRIPTS_ORIG.patchGestureHandler()}
138
- `)
139
-
140
- SCRIPTS_ORIG.patchGestureHandler = () => PATCHES_GESTURE_HANDLER_DIR
141
- ? oneLine(`
142
- (cat package.json | grep -q react-native-gesture-handler && npx patch-package --patch-dir ${PATCHES_GESTURE_HANDLER_DIR} || true)
143
- `)
144
- : 'true'
145
-
146
- SCRIPTS_ORIG.postinstall = () => oneLine(`
147
- ${SCRIPTS_ORIG.patchPackage()}
148
- `)
149
-
150
- SCRIPTS_ORIG.testE2E = ({ inspect } = {}) => {
151
- return oneLine(`
152
- startupjs build --async && npx concurrently "startupjs start-production" "sleep 15s && npx playwright test $@" --kill-others --success first
153
- `)
154
- }
155
-
156
- SCRIPTS_ORIG.codegenTestE2E = ({ inspect } = {}) => {
157
- return oneLine(`
158
- startupjs build --async && npx concurrently "startupjs start-production" "npx playwright codegen $@"
159
- `)
160
- }
161
-
162
- const SCRIPTS = {
163
- start: 'startupjs start',
164
- metro: 'react-native start --reset-cache',
165
- web: 'startupjs web',
166
- server: 'startupjs server',
167
- postinstall: 'startupjs postinstall',
168
- adb: 'adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3000 tcp:3000 && adb reverse tcp:3010 tcp:3010',
169
- 'log-android-color': 'react-native log-android | ccze -m ansi -C -o nolookups',
170
- 'log-android': 'hash ccze 2>/dev/null && npm run log-android-color || (echo "WARNING! Falling back to plain logging. For colored logs install ccze - brew install ccze" && react-native log-android)',
171
- android: 'react-native run-android && (npm run adb || true) && npm run log-android',
172
- 'android-release': 'react-native run-android --variant Release',
173
- ios: 'react-native run-ios',
174
- 'ios-release': 'react-native run-ios --configuration Release',
175
- build: 'startupjs build --async',
176
- 'start-production': 'startupjs start-production',
177
- 'test-e2e': 'startupjs test-e2e',
178
- 'codegen-test-e2e': 'startupjs codegen-test-e2e'
179
- }
180
-
181
- const DEFAULT_TEMPLATE = 'ui'
182
- const DEFAULT_YARN_VERSION = '4'
183
- const TEMPLATES = {
184
- simple: {
185
- subTemplates: ['simple']
186
- },
187
- routing: {
188
- subTemplates: ['simple', 'routing'],
189
- packages: [
190
- // === START APP PEER DEPS ===
191
- 'react-native-restart@^0.0.22'
192
- // === END APP PEER DEPS ===
193
- ]
194
- },
195
- ui: {
196
- subTemplates: ['simple', 'routing', 'ui'],
197
- packages: [
198
- // === START APP PEER DEPS ===
199
- 'react-native-restart@^0.0.22',
200
- // === END APP PEER DEPS ===
10
+ const program = new Command()
11
+ .usage('<command> [options]')
12
+ .version(packageJson.version, '-v, --version', 'output the version of startupjs cli utility in this project')
201
13
 
202
- // === START UI PEER PEDS ===
203
- `@startupjs/ui@${STARTUPJS_VERSION}`,
204
- '@react-native-picker/picker@^1.16.1',
205
- 'react-native-gesture-handler@^2.14.0',
206
- 'react-native-pager-view@^6.2.0'
207
- // === END UI PEER DEPS ===
208
- ]
209
- }
210
- }
211
-
212
- let templatesPath
213
-
214
- // ----- init
215
-
216
- commander
217
- .command('init <projectName>')
218
- .description('bootstrap a new startupjs application')
219
- .option('--react-native <semver>', 'Use a particular semver of React Native as a template', 'latest')
220
- .option('-t, --template <name>', 'Which startupjs template to use to bootstrap the project', DEFAULT_TEMPLATE)
221
- .option('-y, --yarn <semver>', 'Use a particular semver of yarn', DEFAULT_YARN_VERSION)
222
- .action(async (projectName, { reactNative, template, yarn }) => {
223
- console.log('> run npx', projectName, { reactNative, template, yarn })
14
+ async function run () {
15
+ for (const command of Object.values(commands)) {
16
+ const { name, description, options = [], action } = command
224
17
 
225
- // setup corepack
226
- try {
227
- await execa.command(
228
- `${path.join(__dirname, 'corepack.sh')} ${yarn}`,
229
- { shell: true, stdio: 'inherit' }
230
- )
231
- } catch (e) {
232
- throw Error('Setup corepack: ', e)
18
+ if (program.commands.find(cmd => cmd.name() === name)) {
19
+ throw new Error(`Attempted to override an already registered command: ${name}`)
233
20
  }
234
21
 
235
- const projectPath = path.join(process.cwd(), LOCAL_DIR, projectName)
22
+ const cmd = program.command(name)
23
+ if (description) cmd.description(description)
236
24
 
237
- // check if template exists
238
- if (!TEMPLATES[template]) {
239
- throw Error(`Template '${template}' doesn't exist. Templates available: ${Object.keys(TEMPLATES).join(', ')}`)
25
+ for (const option of options) {
26
+ const { name, description } = option
27
+ cmd.option(name, description)
240
28
  }
241
29
 
242
- if (LOCAL_DIR !== '.') {
243
- await execa(
244
- 'mkdir',
245
- ['-p', LOCAL_DIR],
246
- { stdio: 'inherit' }
247
- )
248
- }
249
-
250
- // init react-native application
251
- await execa('npx', [
252
- '--yes',
253
- `react-native${'@' + reactNative}`,
254
- 'init',
255
- '--skip-install',
256
- projectName
257
- ].concat(['--version', reactNative]), {
258
- cwd: path.join(process.cwd(), LOCAL_DIR),
259
- stdio: 'inherit'
260
- })
261
-
262
- // specify yarn version
263
- await execa('rm', ['-rf', 'node_modules'], {
264
- cwd: projectPath,
265
- stdio: 'inherit'
266
- })
267
- await execa('rm', ['-f', 'yarn.lock'], {
268
- cwd: projectPath,
269
- stdio: 'inherit'
270
- })
271
- await execa('corepack', ['use', `yarn@${yarn}`], {
272
- cwd: projectPath,
273
- stdio: 'inherit'
274
- })
275
-
276
- // remove extra files which are covered by startupjs core
277
- if (REMOVE_FILES.length) {
278
- await execa('rm', ['-f'].concat(REMOVE_FILES), {
279
- cwd: projectPath,
280
- stdio: 'inherit'
281
- })
282
- }
283
-
284
- await execa('yarn', ['config', 'set', 'nodeLinker', 'node-modules'], {
285
- cwd: projectPath,
286
- stdio: 'inherit'
287
- })
288
-
289
- // remove extra dependencies which are covered by startupjs core
290
- if (REMOVE_DEPENDENCIES.length) {
291
- await execa('yarn', ['remove'].concat(REMOVE_DEPENDENCIES), {
292
- cwd: projectPath,
293
- stdio: 'inherit'
294
- })
295
- }
296
-
297
- // copy additional startupjs template files over react-native ones
298
- console.log(`> Copy template '${template}'`)
299
- for (const subTemplate of TEMPLATES[template].subTemplates) {
300
- const subTemplatePath = path.join(templatesPath, subTemplate)
301
- await recursivelyCopyFiles(subTemplatePath, projectPath)
302
- }
303
-
304
- // install startupjs dependencies
305
- await execa('yarn', ['add'].concat(DEPENDENCIES).concat(TEMPLATES[template].packages || []), {
306
- cwd: projectPath,
307
- stdio: 'inherit'
308
- })
309
-
310
- if (LINK) {
311
- // TODO: Link startupjs packages. ref:
312
- // https://stackoverflow.com/questions/48681642/yarn-workspaces-and-yarn-link
313
- console.log('> TODO: Link startupjs packages for local install')
314
- }
315
-
316
- if (DEV_DEPENDENCIES.length) {
317
- // install startupjs devDependencies
318
- await execa('yarn', ['add', '-D'].concat(DEV_DEPENDENCIES), {
319
- cwd: projectPath,
320
- stdio: 'inherit'
321
- })
322
- }
323
-
324
- console.log('> Update config.json')
325
- updateConfigJson(projectPath, { projectName })
326
-
327
- console.log('> Patch package.json')
328
- patchPackageJson(projectPath)
329
-
330
- console.log('> Add additional things to .gitignore')
331
- appendGitignore(projectPath)
332
-
333
- console.log('> Apply module patches from /patches/ folder')
334
- await execa('yarn', ['postinstall'], {
335
- cwd: projectPath,
336
- stdio: 'inherit'
337
- })
338
-
339
- if (process.platform === 'darwin') {
340
- await execa('pod', ['install'], {
341
- cwd: path.join(projectPath, 'ios'),
342
- stdio: 'inherit'
343
- })
344
- }
345
-
346
- if (template === 'ui') {
347
- await execa('startupjs', ['link'], {
348
- cwd: projectPath,
349
- stdio: 'inherit'
350
- })
351
- }
352
-
353
- console.log(getSuccessInstructions(projectName))
354
- })
355
-
356
- // ----- init
357
-
358
- commander
359
- .command('start')
360
- .description('Run "startupjs web" and "startupjs server" at the same time.')
361
- .option('-i, --inspect', 'Use node --inspect')
362
- .action(async (options) => {
363
- await execa.command(
364
- SCRIPTS_ORIG.start(options),
365
- { stdio: 'inherit', shell: true }
366
- )
367
- })
368
-
369
- commander
370
- .command('test-e2e')
371
- .description('Run e2e tests')
372
- .action(async (options) => {
373
- await execa.command(
374
- SCRIPTS_ORIG.testE2E(options),
375
- { stdio: 'inherit', shell: true }
376
- )
377
- })
378
-
379
- commander
380
- .command('codegen-test-e2e')
381
- .description('Run codegen for e2e tests')
382
- .action(async (options) => {
383
- await execa.command(
384
- SCRIPTS_ORIG.codegenTestE2E(options),
385
- { stdio: 'inherit', shell: true }
386
- )
387
- })
388
-
389
- commander
390
- .command('web')
391
- .description('Compile (with webpack) and run web')
392
- .action(async (options) => {
393
- await execa.command(
394
- SCRIPTS_ORIG.web,
395
- { stdio: 'inherit', shell: true }
396
- )
397
- })
398
-
399
- commander
400
- .command('server')
401
- .description('Compile (with webpack) and run server')
402
- .option('-i, --inspect', 'Use node --inspect')
403
- .action(async (options) => {
404
- await execa.command(
405
- SCRIPTS_ORIG.server(options),
406
- { stdio: 'inherit', shell: true }
407
- )
408
- })
409
-
410
- commander
411
- .command('build')
412
- .description('Build web bundles')
413
- .option('-a, --async', 'Build with splitting code into async chunks loaded dynamically')
414
- .action(async (options) => {
415
- await execa.command(
416
- isExpo() ? SCRIPTS_ORIG.expoBuild(options) : SCRIPTS_ORIG.build(options),
417
- { stdio: 'inherit', shell: true }
418
- )
419
- })
420
-
421
- commander
422
- .command('start-production')
423
- .description('Start production')
424
- .action(async (options) => {
425
- await execa.command(
426
- isExpo() ? SCRIPTS_ORIG.expoStartProduction : SCRIPTS_ORIG.startProduction,
427
- { stdio: 'inherit', shell: true }
428
- )
429
- })
430
-
431
- commander
432
- .command('patch-package')
433
- .description('Apply required patches to libraries used by startupjs')
434
- .action(async (options) => {
435
- await execa.command(
436
- SCRIPTS_ORIG.patchPackage(options),
437
- { stdio: 'inherit', shell: true }
438
- )
439
- })
440
-
441
- commander
442
- .command('link')
443
- .description('Links files')
444
- .action(async () => {
445
- // this is important because ./link contains files that are initialized on require. Thus, 'glob' in ./linc/path does not work correctly when required in a header
446
- const link = require('./link')
447
- link()
448
- })
449
-
450
- commander
451
- .command('android-link')
452
- .description('Links android files')
453
- .action(async () => {
454
- console.warn('"startupjs android-link" is deprecated. Use "startupjs link" instead.')
455
- // this is important because ./link contains files that are initialized on require. Thus, 'glob' in ./linc/path does not work correctly when required in a header
456
- const link = require('./link')
457
- link()
458
- })
459
-
460
- commander
461
- .command('postinstall')
462
- .description('Run startupjs postinstall scripts')
463
- .action(async (options) => {
464
- await execa.command(
465
- SCRIPTS_ORIG.postinstall(options),
466
- { stdio: 'inherit', shell: true }
467
- )
468
- })
469
-
470
- // ----- project management commands
471
-
472
- commander
473
- .command('init-pm')
474
- .description('Create a new project on github from template')
475
- .action(async () => {
476
- await execa.command(`${PM_SCRIPTS_PATH} init-pm`, { shell: true, stdio: 'inherit' })
477
- addPmScriptsToPackageJson() // add `yarn pm` and `yarn task` to package.json/scripts
478
- })
479
-
480
- commander
481
- .command('task <issueNumber>')
482
- .description('Create a task branch (or just switch to it if it already exists)')
483
- .action(async (issueNumber) => {
484
- await execa.command(`${PM_SCRIPTS_PATH} task ${issueNumber}`, { shell: true, stdio: 'inherit' })
485
- })
486
-
487
- commander
488
- .command('pr [issueNumber]')
489
- .description('Make PR for this task (or re-request review if it already exists)')
490
- .action(async (issueNumber = '') => {
491
- await execa.command(`${PM_SCRIPTS_PATH} pr ${issueNumber}`, { shell: true, stdio: 'inherit' })
492
- })
493
-
494
- // ----- helpers
495
-
496
- async function recursivelyCopyFiles (sourcePath, targetPath) {
497
- const fileNames = fs.readdirSync(sourcePath)
498
-
499
- if (fileNames.length === 0) return
500
-
501
- for (const fileName of fileNames) {
502
- const filePath = path.join(sourcePath, fileName)
503
- if (fs.lstatSync(filePath).isDirectory()) {
504
- const subTargetPath = path.join(targetPath, fileName)
505
- await execa(
506
- 'mkdir',
507
- ['-p', subTargetPath],
508
- { stdio: 'inherit' }
509
- )
510
- await recursivelyCopyFiles(filePath, subTargetPath)
511
- } else {
512
- await execa(
513
- 'cp',
514
- [filePath, targetPath],
515
- { stdio: 'inherit' }
516
- )
517
- }
518
- }
519
- }
520
-
521
- function patchPackageJson (projectPath) {
522
- const packageJSONPath = path.join(projectPath, 'package.json')
523
- const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString())
524
-
525
- delete packageJSON.scripts.test
526
- delete packageJSON.devDependencies['babel-jest']
527
- delete packageJSON.devDependencies['react-test-renderer']
528
- delete packageJSON.devDependencies.jest
529
-
530
- packageJSON.scripts = {
531
- ...packageJSON.scripts,
532
- ...SCRIPTS
533
- }
534
-
535
- packageJSON['lint-staged'] = {
536
- '*.{js,jsx}': [
537
- 'eslint --fix',
538
- 'git add'
539
- ]
540
- }
541
-
542
- packageJSON.husky = {
543
- hooks: {
544
- 'pre-commit': 'lint-staged'
545
- }
546
- }
547
-
548
- // FIXME: We can't use type=module now, because metro does not support ESM
549
- // and does not provide ability to pass .cjs config.
550
- // packageJSON.type = 'module'
551
- packageJSON.sideEffects = ['*.css', '*.styl']
552
-
553
- fs.writeFileSync(
554
- packageJSONPath,
555
- `${JSON.stringify(packageJSON, null, 2)}\n`
556
- )
557
- }
558
-
559
- function addPmScriptsToPackageJson () {
560
- const projectPath = process.cwd()
561
- const packageJSONPath = path.join(projectPath, 'package.json')
562
- const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString())
563
-
564
- packageJSON.scripts = {
565
- ...packageJSON.scripts,
566
- task: 'npx startupjs task',
567
- pr: 'npx startupjs pr'
30
+ cmd.action(action)
568
31
  }
569
32
 
570
- fs.writeFileSync(
571
- packageJSONPath,
572
- `${JSON.stringify(packageJSON, null, 2)}\n`
573
- )
33
+ program.parse(process.argv)
574
34
  }
575
35
 
576
- function appendGitignore (projectPath) {
577
- const gitignorePath = path.join(projectPath, '.gitignore')
578
- let gitignore = fs.readFileSync(gitignorePath).toString()
579
-
580
- gitignore += `
581
- # DB data
582
- /data/
583
- # Protection from accidentally commiting private npm keys to a public repo
584
- .npmrc
585
- # Mongo data when running in a docker dev container
586
- /.mongo
587
- # yarn
588
- .yarn/
589
- # sqlite
590
- sqlite.db
591
- `.replace(/\n\s+/g, '\n')
592
-
593
- fs.writeFileSync(gitignorePath, gitignore)
594
- }
595
-
596
- function updateConfigJson (projectPath, options) {
597
- const configJsonPath = path.join(projectPath, 'config.json')
598
- let configJson = fs.readFileSync(configJsonPath).toString()
599
-
600
- try {
601
- const templateFn = template(configJson)
602
- const sessionSecret = generateRandomString(32)
603
- configJson = templateFn({ ...options, sessionSecret })
604
- } catch (e) {
605
- console.log(
606
- '\x1b[31m' +
607
- 'config.json has not been updated, update it manually!' +
608
- '\x1b[0m'
609
- )
610
- }
611
-
612
- fs.writeFileSync(
613
- configJsonPath,
614
- configJson
615
- )
616
- }
617
-
618
- function generateRandomString (length = 0) {
619
- let result = ''
620
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
621
- const charactersLength = characters.length
622
-
623
- for (let i = 0; i < length; i++) {
624
- result += characters.charAt(
625
- Math.floor(
626
- Math.random() * charactersLength
627
- )
628
- )
629
- }
630
- return result
631
- }
632
-
633
- function getSuccessInstructions (projectName) {
634
- return `
635
- StartupJS installation successful!
636
-
637
- To use private packages, log in via yarn npm login.
638
-
639
- INSTRUCTIONS
640
-
641
- $ cd ${projectName}
642
-
643
- Run each command in a separate terminal tab:
644
-
645
- 1. Start server:
646
-
647
- $ yarn server
648
-
649
- 2. Start web:
650
-
651
- $ yarn web
652
-
653
- and go to http://localhost:3000
654
-
655
- 3. Start native:
656
-
657
- $ yarn metro
658
- $ yarn android
659
- $ yarn ios
660
- `
661
- }
662
-
663
- // Replace all new lines with spaces to properly handle cli-commands
664
- function oneLine (str) {
665
- return str.replace(/\s+/g, ' ')
666
- }
667
-
668
- function isExpo (rootPath = process.cwd()) {
669
- try {
670
- const packageJson = fs.readFileSync(path.resolve(rootPath, './package.json'), 'utf8')
671
- const { dependencies = {} } = JSON.parse(packageJson)
672
- return Boolean(dependencies.expo)
673
- } catch {
674
- return false
675
- }
676
- }
677
-
678
- exports.run = (options = {}) => {
679
- if (!options.templatesPath) throw Error('templatesPath not found!')
680
- templatesPath = options.templatesPath
681
- commander.parse(process.argv)
682
- }
36
+ export { run }