@startupjs/cli 0.56.0-alpha.5 → 0.56.0-alpha.58

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