@startupjs/cli 0.56.0-alpha.1 → 0.56.0-alpha.14

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