/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ 'use strict'; const bundle = require('./bundle/bundle'); const childProcess = require('child_process'); const Config = require('./util/Config'); const defaultConfig = require('./default.config'); const dependencies = require('./dependencies/dependencies'); const generate = require('./generate/generate'); const library = require('./library/library'); const link = require('./rnpm/link/src/link'); const path = require('path'); const Promise = require('promise'); const runAndroid = require('./runAndroid/runAndroid'); const runIOS = require('./runIOS/runIOS'); const server = require('./server/server'); const TerminalAdapter = require('yeoman-environment/lib/adapter.js'); const yeoman = require('yeoman-environment'); const unbundle = require('./bundle/unbundle'); const upgrade = require('./upgrade/upgrade'); const version = require('./version/version'); const fs = require('fs'); const gracefulFs = require('graceful-fs'); // Just a helper to proxy 'react-native link' to rnpm const linkWrapper = (args, config) => { const rnpmConfig = require('./rnpm/core/src/config'); return new Promise((resolve, reject) => { link(rnpmConfig, args.slice(1)).then(resolve, reject); }); } // graceful-fs helps on getting an error when we run out of file // descriptors. When that happens it will enqueue the operation and retry it. gracefulFs.gracefulify(fs); const documentedCommands = { 'start': [server, 'starts the webserver'], 'bundle': [bundle, 'builds the javascript bundle for offline use'], 'unbundle': [unbundle, 'builds javascript as "unbundle" for offline use'], 'new-library': [library, 'generates a native library bridge'], 'android': [generateWrapper, 'generates an Android project for your app'], 'run-android': [runAndroid, 'builds your app and starts it on a connected Android emulator or device'], 'run-ios': [runIOS, 'builds your app and starts it on iOS simulator'], 'upgrade': [upgrade, 'upgrade your app\'s template files to the latest version; run this after ' + 'updating the react-native version in your package.json and running npm install'], 'link': [linkWrapper, 'link a library'], }; const exportedCommands = {dependencies: dependencies}; Object.keys(documentedCommands).forEach(function(command) { exportedCommands[command] = documentedCommands[command][0]; }); const undocumentedCommands = { '--version': [version, ''], 'init': [printInitWarning, ''], }; const commands = Object.assign({}, documentedCommands, undocumentedCommands); /** * Parses the command line and runs a command of the CLI. */ function run() { const args = process.argv.slice(2); if (args.length === 0) { printUsage(); } const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; childProcess.execFileSync(path.join(__dirname, setupEnvScript)); const command = commands[args[0]]; if (!command) { console.error('Command `%s` unrecognized', args[0]); printUsage(); return; } command[0](args, Config.get(__dirname, defaultConfig)).done(); } function generateWrapper(args, config) { return generate([ '--platform', 'android', '--project-path', process.cwd(), '--project-name', JSON.parse( fs.readFileSync('package.json', 'utf8') ).name ], config); } function printUsage() { console.log([ 'Usage: react-native ', '', 'Commands:' ].concat(Object.keys(documentedCommands).map(function(name) { return ' - ' + name + ': ' + documentedCommands[name][1]; })).join('\n')); process.exit(1); } // The user should never get here because projects are inited by // using `react-native-cli` from outside a project directory. function printInitWarning() { return Promise.resolve().then(function() { console.log([ 'Looks like React Native project already exists in the current', 'folder. Run this command from a different folder or remove node_modules/react-native' ].join('\n')); process.exit(1); }); } class CreateSuppressingTerminalAdapter extends TerminalAdapter { constructor() { super(); // suppress 'create' output generated by yeoman this.log.create = function() {}; } } /** * Creates the template for a React Native project given the provided * parameters: * - projectDir: templates will be copied here. * - argsOrName: project name or full list of custom arguments to pass to the * generator. */ function init(projectDir, argsOrName) { console.log('Setting up new React Native app in ' + projectDir); const env = yeoman.createEnv( undefined, undefined, new CreateSuppressingTerminalAdapter() ); env.register( require.resolve(path.join(__dirname, 'generator')), 'react:app' ); // argv is for instance // ['node', 'react-native', 'init', 'AwesomeApp', '--verbose'] // args should be ['AwesomeApp', '--verbose'] const args = Array.isArray(argsOrName) ? argsOrName : [argsOrName].concat(process.argv.slice(4)); const generator = env.create('react:app', {args: args}); generator.destinationRoot(projectDir); generator.run(); } module.exports = { run: run, init: init, commands: exportedCommands };