From ab60d7c420866e5f4048836002c852820d2373d1 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 5 Apr 2019 23:34:11 +0200 Subject: [PATCH 1/9] Commands can be paths only in RNPM config, require object --- packages/cli/src/cliEntry.js | 6 +- packages/cli/src/commands/index.js | 116 +++--------------- .../src/tools/config/readConfigFromDisk.js | 25 +++- packages/cli/src/tools/config/schema.js | 4 +- packages/cli/src/tools/config/types.flow.js | 20 ++- packages/cli/src/tools/types.flow.js | 20 +-- 6 files changed, 63 insertions(+), 128 deletions(-) diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index 9758eb849..f229e28e7 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -14,7 +14,7 @@ import path from 'path'; import type {CommandT, ContextT} from './tools/types.flow'; -import {getCommands} from './commands'; +import * as commands from './commands'; import init from './commands/init/initCompat'; import assertRequiredOptions from './tools/assertRequiredOptions'; import {logger} from '@react-native-community/cli-tools'; @@ -162,9 +162,7 @@ async function setupAndRun() { setProjectDir(ctx.root); - const commands = getCommands(ctx); - - commands.forEach(command => addCommand(command, ctx)); + [...commands, ...ctx.commands].forEach(command => addCommand(command, ctx)); commander.parse(process.argv); diff --git a/packages/cli/src/commands/index.js b/packages/cli/src/commands/index.js index 86920456c..030c08b64 100644 --- a/packages/cli/src/commands/index.js +++ b/packages/cli/src/commands/index.js @@ -2,103 +2,19 @@ * @flow */ -import path from 'path'; -import type { - CommandT, - ProjectCommandT, - LocalCommandT, -} from '../tools/types.flow'; - -import {type ContextT} from '../tools/types.flow'; -import server from './server/server'; -import runIOS from './runIOS/runIOS'; -import runAndroid from './runAndroid/runAndroid'; -import library from './library/library'; -import bundle from './bundle/bundle'; -import ramBundle from './bundle/ramBundle'; -import link from './link/link'; -import unlink from './link/unlink'; -import install from './install/install'; -import uninstall from './install/uninstall'; -import upgrade from './upgrade/upgrade'; -import logAndroid from './logAndroid/logAndroid'; -import logIOS from './logIOS/logIOS'; -import info from './info/info'; -import config from './config/config'; -import init from './init'; - -/** - * List of built-in commands - */ - -const loadLocalCommands: Array = [ - server, - runIOS, - runAndroid, - library, - bundle, - ramBundle, - link, - unlink, - install, - uninstall, - upgrade, - logAndroid, - logIOS, - info, - config, - init, -]; - -/** - * Returns an array of commands that are defined in the project. - * - * This checks all CLI plugins for presence of 3rd party packages that define commands - * and loads them - */ -const loadProjectCommands = ({ - root, - commands, -}: ContextT): Array => { - return commands.reduce((acc: Array, cmdPath: string) => { - /** - * `pathToCommand` is a path to a file where commands are defined, relative to `node_modules` - * folder. - * - * Following code gets the name of the package name out of the path, taking scope - * into consideration. - */ - const name = - cmdPath[0] === '@' - ? cmdPath - .split(path.sep) - .slice(0, 2) - .join(path.sep) - : cmdPath.split(path.sep)[0]; - - const pkg = require(path.join(root, 'node_modules', name, 'package.json')); - - const requiredCommands: - | ProjectCommandT - | Array = require(path.join( - root, - 'node_modules', - cmdPath, - )); - - if (Array.isArray(requiredCommands)) { - return acc.concat( - requiredCommands.map(requiredCommand => ({...requiredCommand, pkg})), - ); - } - - return acc.concat({...requiredCommands, pkg}); - }, []); -}; - -/** - * Loads all the commands inside a given `root` folder - */ -export function getCommands(ctx: ContextT): Array { - return [...loadLocalCommands, ...loadProjectCommands(ctx)]; -} +export {default as server} from './server/server'; +export {default as runIOS} from './runIOS/runIOS'; +export {default as runAndroid} from './runAndroid/runAndroid'; +export {default as library} from './library/library'; +export {default as bundle} from './bundle/bundle'; +export {default as ramBundle} from './bundle/ramBundle'; +export {default as link} from './link/link'; +export {default as unlink} from './link/unlink'; +export {default as install} from './install/install'; +export {default as uninstall} from './install/uninstall'; +export {default as upgrade} from './upgrade/upgrade'; +export {default as logAndroid} from './logAndroid/logAndroid'; +export {default as logIOS} from './logIOS/logIOS'; +export {default as info} from './info/info'; +export {default as config} from './config/config'; +export {default as init} from './init'; diff --git a/packages/cli/src/tools/config/readConfigFromDisk.js b/packages/cli/src/tools/config/readConfigFromDisk.js index edc86091d..a3a101b79 100644 --- a/packages/cli/src/tools/config/readConfigFromDisk.js +++ b/packages/cli/src/tools/config/readConfigFromDisk.js @@ -12,6 +12,7 @@ import {type UserDependencyConfigT, type UserConfigT} from './types.flow'; import {JoiError} from '../errors'; import * as schema from './schema'; + import {logger} from '@react-native-community/cli-tools'; /** @@ -60,6 +61,26 @@ export function readDependencyConfigFromDisk( return result.value; } +/** + * Returns an array of commands that are defined in the project. + */ +const loadProjectCommand = ({ + root, + commands, +}: ContextT): Array => { + return commands.reduce((acc: Array, cmdPath: string) => { + const requiredCommands: + | ProjectCommandT + | Array = require(path.join( + root, + 'node_modules', + cmdPath, + )); + + return acc.concat(requiredCommands); + }, []); +}; + /** * Reads a legacy configuaration from a `package.json` "rnpm" key. */ @@ -82,7 +103,9 @@ export function readLegacyDependencyConfigFromDisk( hooks: config.commands, params: config.params, }, - commands: [].concat(config.plugin || []), + commands: [] + .concat(config.plugin || []) + .map(p => loadProjectCommand(rootFolder, p)), platforms: config.platform ? require(path.join(rootFolder, config.platform)) : undefined, diff --git a/packages/cli/src/tools/config/schema.js b/packages/cli/src/tools/config/schema.js index 067395c52..29da79622 100644 --- a/packages/cli/src/tools/config/schema.js +++ b/packages/cli/src/tools/config/schema.js @@ -62,7 +62,7 @@ export const dependencyConfig = t ).default(), commands: t .array() - .items(t.string()) + .items(t.object()) .default([]), }) .default(); @@ -142,7 +142,7 @@ export const projectConfig = t .default([]), commands: t .array() - .items(t.string()) + .items(t.object()) .default([]), }) .default(); diff --git a/packages/cli/src/tools/config/types.flow.js b/packages/cli/src/tools/config/types.flow.js index 9e038d86b..76232d878 100644 --- a/packages/cli/src/tools/config/types.flow.js +++ b/packages/cli/src/tools/config/types.flow.js @@ -1,6 +1,22 @@ /** * @flow */ +export type CommandT = { + name: string, + description?: string, + usage?: string, + func: (argv: Array, ctx: ContextT, args: Object) => ?Promise, + options?: Array<{ + command: string, + description?: string, + parse?: (val: string) => any, + default?: string | boolean | number, + }>, + examples?: Array<{ + desc: string, + cmd: string, + }>, +}; /** * Opaque type that describes the Inquirer question format. Not typed, since we just @@ -122,7 +138,7 @@ export type ConfigT = {| }, // An array of commands that are present in 3rd party packages - commands: string[], + commands: CommandT[], // Haste configuration resolved based on available plugins haste: { @@ -159,7 +175,7 @@ export type UserDependencyConfigT = { }, // An array of commands that ship with the dependency - commands: string[], + commands: CommandT[], // An array of extra platforms to load platforms: { diff --git a/packages/cli/src/tools/types.flow.js b/packages/cli/src/tools/types.flow.js index 5926e655c..f9c8447e1 100644 --- a/packages/cli/src/tools/types.flow.js +++ b/packages/cli/src/tools/types.flow.js @@ -6,7 +6,7 @@ import {type ConfigT} from './config/types.flow'; export type ContextT = ConfigT; -export type LocalCommandT = { +export type CommandT = { name: string, description?: string, usage?: string, @@ -22,21 +22,3 @@ export type LocalCommandT = { cmd: string, }>, }; - -type Package = { - version: string, - name: string, -}; - -/** - * User can define command either as an object (RequiredCommandT) or - * as an array of commands (Array). - */ -export type ProjectCommandT = LocalCommandT & { - pkg: Package, -}; - -/** - * Main type. Can be either local or a project command. - */ -export type CommandT = LocalCommandT | ProjectCommandT; From 8f01d9469e7e7c9adf6c9c9dfec8fb0d22f38e3b Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 5 Apr 2019 23:46:47 +0200 Subject: [PATCH 2/9] Misc --- packages/cli/src/cliEntry.js | 6 +-- .../cli/src/commands/bundle/buildBundle.js | 4 +- packages/cli/src/commands/config/config.js | 4 +- packages/cli/src/commands/index.js | 52 +++++++++++++------ packages/cli/src/commands/info/info.js | 4 +- packages/cli/src/commands/init/init.js | 4 +- packages/cli/src/commands/install/install.js | 4 +- .../cli/src/commands/install/uninstall.js | 4 +- packages/cli/src/commands/link/link.js | 4 +- packages/cli/src/commands/link/unlink.js | 4 +- .../cli/src/commands/runAndroid/runAndroid.js | 4 +- packages/cli/src/commands/runIOS/runIOS.js | 4 +- packages/cli/src/commands/server/runServer.js | 4 +- .../cli/src/commands/upgrade/legacyUpgrade.js | 4 +- packages/cli/src/commands/upgrade/upgrade.js | 4 +- packages/cli/src/tools/config/index.js | 6 +-- .../src/tools/config/readConfigFromDisk.js | 27 ++++------ packages/cli/src/tools/config/types.flow.js | 2 +- packages/cli/src/tools/loadMetroConfig.js | 6 +-- packages/cli/src/tools/types.flow.js | 24 --------- 20 files changed, 81 insertions(+), 94 deletions(-) delete mode 100644 packages/cli/src/tools/types.flow.js diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index f229e28e7..81036907d 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -12,9 +12,9 @@ import childProcess from 'child_process'; import commander from 'commander'; import path from 'path'; -import type {CommandT, ContextT} from './tools/types.flow'; +import type {CommandT, ConfigT} from './tools/config/types.flow'; -import * as commands from './commands'; +import commands from './commands'; import init from './commands/init/initCompat'; import assertRequiredOptions from './tools/assertRequiredOptions'; import {logger} from '@react-native-community/cli-tools'; @@ -95,7 +95,7 @@ function printUnknownCommand(cmdName) { } } -const addCommand = (command: CommandT, ctx: ContextT) => { +const addCommand = (command: CommandT, ctx: ConfigT) => { const options = command.options || []; const cmd = commander diff --git a/packages/cli/src/commands/bundle/buildBundle.js b/packages/cli/src/commands/bundle/buildBundle.js index e11f7512a..89211c746 100644 --- a/packages/cli/src/commands/bundle/buildBundle.js +++ b/packages/cli/src/commands/bundle/buildBundle.js @@ -13,14 +13,14 @@ import outputBundle from 'metro/src/shared/output/bundle'; import path from 'path'; import chalk from 'chalk'; import type {CommandLineArgs} from './bundleCommandLineArgs'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import saveAssets from './saveAssets'; import loadMetroConfig from '../../tools/loadMetroConfig'; import {logger} from '@react-native-community/cli-tools'; async function buildBundle( args: CommandLineArgs, - ctx: ContextT, + ctx: ConfigT, output: typeof outputBundle = outputBundle, ) { const config = await loadMetroConfig(ctx, { diff --git a/packages/cli/src/commands/config/config.js b/packages/cli/src/commands/config/config.js index 51fd05243..83fa8bffb 100644 --- a/packages/cli/src/commands/config/config.js +++ b/packages/cli/src/commands/config/config.js @@ -1,11 +1,11 @@ /** * @flow */ -import {type ContextT} from '../../tools/types.flow'; +import {type ConfigT} from '../../tools/config/types.flow'; export default { name: 'config', description: 'Print CLI configuration', - func: async (argv: string[], ctx: ContextT) => { + func: async (argv: string[], ctx: ConfigT) => { console.log(JSON.stringify(ctx, null, 2)); }, }; diff --git a/packages/cli/src/commands/index.js b/packages/cli/src/commands/index.js index 030c08b64..b149aa830 100644 --- a/packages/cli/src/commands/index.js +++ b/packages/cli/src/commands/index.js @@ -1,20 +1,40 @@ /** * @flow */ +import {type CommandT} from '../tools/config/types.flow'; -export {default as server} from './server/server'; -export {default as runIOS} from './runIOS/runIOS'; -export {default as runAndroid} from './runAndroid/runAndroid'; -export {default as library} from './library/library'; -export {default as bundle} from './bundle/bundle'; -export {default as ramBundle} from './bundle/ramBundle'; -export {default as link} from './link/link'; -export {default as unlink} from './link/unlink'; -export {default as install} from './install/install'; -export {default as uninstall} from './install/uninstall'; -export {default as upgrade} from './upgrade/upgrade'; -export {default as logAndroid} from './logAndroid/logAndroid'; -export {default as logIOS} from './logIOS/logIOS'; -export {default as info} from './info/info'; -export {default as config} from './config/config'; -export {default as init} from './init'; +import server from './server/server'; +import runIOS from './runIOS/runIOS'; +import runAndroid from './runAndroid/runAndroid'; +import library from './library/library'; +import bundle from './bundle/bundle'; +import ramBundle from './bundle/ramBundle'; +import link from './link/link'; +import unlink from './link/unlink'; +import install from './install/install'; +import uninstall from './install/uninstall'; +import upgrade from './upgrade/upgrade'; +import logAndroid from './logAndroid/logAndroid'; +import logIOS from './logIOS/logIOS'; +import info from './info/info'; +import config from './config/config'; +import init from './init'; + +export default ([ + server, + runIOS, + runAndroid, + library, + bundle, + ramBundle, + link, + unlink, + install, + uninstall, + upgrade, + logAndroid, + logIOS, + info, + config, + init, +]: CommandT); diff --git a/packages/cli/src/commands/info/info.js b/packages/cli/src/commands/info/info.js index 4faae7860..f404c5d92 100644 --- a/packages/cli/src/commands/info/info.js +++ b/packages/cli/src/commands/info/info.js @@ -9,11 +9,11 @@ import envinfo from 'envinfo'; import {logger} from '@react-native-community/cli-tools'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; const info = async function getInfo( argv: Array, - ctx: ContextT, + ctx: ConfigT, options: {}, ) { try { diff --git a/packages/cli/src/commands/init/init.js b/packages/cli/src/commands/init/init.js index 77279d7ba..35e2811a5 100644 --- a/packages/cli/src/commands/init/init.js +++ b/packages/cli/src/commands/init/init.js @@ -2,7 +2,7 @@ import fs from 'fs-extra'; import minimist from 'minimist'; import semver from 'semver'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import {validateProjectName} from './validate'; import DirectoryAlreadyExistsError from './errors/DirectoryAlreadyExistsError'; import printRunInstructions from './printRunInstructions'; @@ -153,7 +153,7 @@ function createProject(projectName: string, options: Options, version: string) { export default (async function initialize( [projectName]: Array, - _context: ContextT, + _context: ConfigT, options: Options, ) { validateProjectName(projectName); diff --git a/packages/cli/src/commands/install/install.js b/packages/cli/src/commands/install/install.js index 4750087b5..7b6e5d6f5 100644 --- a/packages/cli/src/commands/install/install.js +++ b/packages/cli/src/commands/install/install.js @@ -7,13 +7,13 @@ * @flow */ -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import {logger} from '@react-native-community/cli-tools'; import * as PackageManager from '../../tools/packageManager'; import link from '../link/link'; import loadConfig from '../../tools/config'; -async function install(args: Array, ctx: ContextT) { +async function install(args: Array, ctx: ConfigT) { const name = args[0]; logger.info(`Installing "${name}"...`); diff --git a/packages/cli/src/commands/install/uninstall.js b/packages/cli/src/commands/install/uninstall.js index a8173d26e..85f4f4563 100644 --- a/packages/cli/src/commands/install/uninstall.js +++ b/packages/cli/src/commands/install/uninstall.js @@ -7,12 +7,12 @@ * @flow */ -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import {logger} from '@react-native-community/cli-tools'; import * as PackageManager from '../../tools/packageManager'; import link from '../link/unlink'; -async function uninstall(args: Array, ctx: ContextT) { +async function uninstall(args: Array, ctx: ConfigT) { const name = args[0]; logger.info(`Unlinking "${name}"...`); diff --git a/packages/cli/src/commands/link/link.js b/packages/cli/src/commands/link/link.js index 94f10bb2c..2be0d3f72 100644 --- a/packages/cli/src/commands/link/link.js +++ b/packages/cli/src/commands/link/link.js @@ -10,7 +10,7 @@ import {pick} from 'lodash'; import dedent from 'dedent'; -import {type ContextT} from '../../tools/types.flow'; +import {type ConfigT} from '../../tools/config/types.flow'; import {CLIError} from '../../tools/errors'; @@ -34,7 +34,7 @@ type FlagsType = { * @param args If optional argument [packageName] is provided, * only that package is processed. */ -function link([rawPackageName]: Array, ctx: ContextT, opts: FlagsType) { +function link([rawPackageName]: Array, ctx: ConfigT, opts: FlagsType) { let platforms = ctx.platforms; let project = ctx.project; diff --git a/packages/cli/src/commands/link/unlink.js b/packages/cli/src/commands/link/unlink.js index b593f21a2..3bcf48758 100644 --- a/packages/cli/src/commands/link/unlink.js +++ b/packages/cli/src/commands/link/unlink.js @@ -8,7 +8,7 @@ */ import {flatMap, values, difference} from 'lodash'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import dedent from 'dedent'; import {logger} from '@react-native-community/cli-tools'; import promiseWaterfall from './promiseWaterfall'; @@ -77,7 +77,7 @@ const unlinkDependency = ( * If optional argument [packageName] is provided, it's the only one * that's checked */ -function unlink(args: Array, ctx: ContextT) { +function unlink(args: Array, ctx: ConfigT) { const packageName = args[0]; const {[packageName]: dependency, ...otherDependencies} = ctx.dependencies; diff --git a/packages/cli/src/commands/runAndroid/runAndroid.js b/packages/cli/src/commands/runAndroid/runAndroid.js index ac5577ffa..9fc40a551 100644 --- a/packages/cli/src/commands/runAndroid/runAndroid.js +++ b/packages/cli/src/commands/runAndroid/runAndroid.js @@ -13,7 +13,7 @@ import fs from 'fs'; import isString from 'lodash/isString'; import isPackagerRunning from '../../tools/isPackagerRunning'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import adb from './adb'; import runOnAllDevices from './runOnAllDevices'; @@ -30,7 +30,7 @@ function checkAndroid(root) { /** * Starts the app on a connected Android emulator or device. */ -function runAndroid(argv: Array, ctx: ContextT, args: Object) { +function runAndroid(argv: Array, ctx: ConfigT, args: Object) { if (!checkAndroid(args.root)) { logger.error( 'Android project not found. Are you sure this is a React Native project?', diff --git a/packages/cli/src/commands/runIOS/runIOS.js b/packages/cli/src/commands/runIOS/runIOS.js index 20e968e1a..898b6697e 100644 --- a/packages/cli/src/commands/runIOS/runIOS.js +++ b/packages/cli/src/commands/runIOS/runIOS.js @@ -11,7 +11,7 @@ import child_process from 'child_process'; import fs from 'fs'; import path from 'path'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import findXcodeProject from './findXcodeProject'; import parseIOSDevicesList from './parseIOSDevicesList'; import findMatchingSimulator from './findMatchingSimulator'; @@ -30,7 +30,7 @@ type FlagsT = { port: number, }; -function runIOS(_: Array, ctx: ContextT, args: FlagsT) { +function runIOS(_: Array, ctx: ConfigT, args: FlagsT) { if (!fs.existsSync(args.projectPath)) { throw new Error( 'iOS project folder not found. Are you sure this is a React Native project?', diff --git a/packages/cli/src/commands/server/runServer.js b/packages/cli/src/commands/server/runServer.js index 8b20376c1..586fb4274 100644 --- a/packages/cli/src/commands/server/runServer.js +++ b/packages/cli/src/commands/server/runServer.js @@ -13,7 +13,7 @@ import {Terminal} from 'metro-core'; import morgan from 'morgan'; import path from 'path'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import messageSocket from './messageSocket'; import webSocketProxy from './webSocketProxy'; import MiddlewareManager from './middleware/MiddlewareManager'; @@ -40,7 +40,7 @@ export type Args = {| config?: string, |}; -async function runServer(argv: Array, ctx: ContextT, args: Args) { +async function runServer(argv: Array, ctx: ConfigT, args: Args) { const terminal = new Terminal(process.stdout); const ReporterImpl = getReporterImpl(args.customLogReporterPath || null); const reporter = new ReporterImpl(terminal); diff --git a/packages/cli/src/commands/upgrade/legacyUpgrade.js b/packages/cli/src/commands/upgrade/legacyUpgrade.js index ccb93eef7..a416d5098 100644 --- a/packages/cli/src/commands/upgrade/legacyUpgrade.js +++ b/packages/cli/src/commands/upgrade/legacyUpgrade.js @@ -11,7 +11,7 @@ import fs from 'fs'; import path from 'path'; import semver from 'semver'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import {logger} from '@react-native-community/cli-tools'; import copyProjectTemplateAndReplace from '../../tools/generator/copyProjectTemplateAndReplace'; @@ -19,7 +19,7 @@ import copyProjectTemplateAndReplace from '../../tools/generator/copyProjectTemp * Migrate application to a new version of React Native. * See http://facebook.github.io/react-native/docs/upgrading.html */ -function validateAndUpgrade(argv: Array, ctx: ContextT) { +function validateAndUpgrade(argv: Array, ctx: ConfigT) { const projectDir = ctx.root; const packageJSON = JSON.parse( diff --git a/packages/cli/src/commands/upgrade/upgrade.js b/packages/cli/src/commands/upgrade/upgrade.js index 816e6cdd0..f7c4f9056 100644 --- a/packages/cli/src/commands/upgrade/upgrade.js +++ b/packages/cli/src/commands/upgrade/upgrade.js @@ -4,7 +4,7 @@ import fs from 'fs'; import chalk from 'chalk'; import semver from 'semver'; import execa from 'execa'; -import type {ContextT} from '../../tools/types.flow'; +import type {ConfigT} from '../../tools/config/types.flow'; import {logger} from '@react-native-community/cli-tools'; import * as PackageManager from '../../tools/packageManager'; import {fetch} from '../../tools/fetch'; @@ -176,7 +176,7 @@ const applyPatch = async ( /** * Upgrade application to a new version of React Native. */ -async function upgrade(argv: Array, ctx: ContextT, args: FlagsT) { +async function upgrade(argv: Array, ctx: ConfigT, args: FlagsT) { if (args.legacy) { return legacyUpgrade.func(argv, ctx); } diff --git a/packages/cli/src/tools/config/index.js b/packages/cli/src/tools/config/index.js index 03df4add4..aa903cea7 100644 --- a/packages/cli/src/tools/config/index.js +++ b/packages/cli/src/tools/config/index.js @@ -83,11 +83,7 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT { ); }, }), - commands: acc.commands.concat( - config.commands.map(pathToCommand => - path.join(dependencyName, pathToCommand), - ), - ), + commands: [...acc.commands, ...config.commands], platforms: { ...acc.platforms, ...config.platforms, diff --git a/packages/cli/src/tools/config/readConfigFromDisk.js b/packages/cli/src/tools/config/readConfigFromDisk.js index a3a101b79..253edd00b 100644 --- a/packages/cli/src/tools/config/readConfigFromDisk.js +++ b/packages/cli/src/tools/config/readConfigFromDisk.js @@ -7,7 +7,11 @@ import Joi from 'joi'; import cosmiconfig from 'cosmiconfig'; import path from 'path'; -import {type UserDependencyConfigT, type UserConfigT} from './types.flow'; +import { + type UserDependencyConfigT, + type UserConfigT, + type CommandT, +} from './types.flow'; import {JoiError} from '../errors'; @@ -64,21 +68,12 @@ export function readDependencyConfigFromDisk( /** * Returns an array of commands that are defined in the project. */ -const loadProjectCommand = ({ - root, - commands, -}: ContextT): Array => { - return commands.reduce((acc: Array, cmdPath: string) => { - const requiredCommands: - | ProjectCommandT - | Array = require(path.join( - root, - 'node_modules', - cmdPath, - )); - - return acc.concat(requiredCommands); - }, []); +const loadProjectCommand = (root, commands): Array => { + return commands.reduce( + (acc: Array, cmdPath: string) => + acc.concat(require(path.join(root, 'node_modules', cmdPath))), + [], + ); }; /** diff --git a/packages/cli/src/tools/config/types.flow.js b/packages/cli/src/tools/config/types.flow.js index 76232d878..93d6725c7 100644 --- a/packages/cli/src/tools/config/types.flow.js +++ b/packages/cli/src/tools/config/types.flow.js @@ -5,7 +5,7 @@ export type CommandT = { name: string, description?: string, usage?: string, - func: (argv: Array, ctx: ContextT, args: Object) => ?Promise, + func: (argv: Array, ctx: ConfigT, args: Object) => ?Promise, options?: Array<{ command: string, description?: string, diff --git a/packages/cli/src/tools/loadMetroConfig.js b/packages/cli/src/tools/loadMetroConfig.js index 8a380f0d9..14c4c5b18 100644 --- a/packages/cli/src/tools/loadMetroConfig.js +++ b/packages/cli/src/tools/loadMetroConfig.js @@ -5,7 +5,7 @@ import path from 'path'; import {createBlacklist} from 'metro'; import {loadConfig} from 'metro-config'; -import {type ContextT} from './types.flow'; +import {type ConfigT} from './config/types.flow'; import findSymlinkedModules from './findSymlinkedModules'; const resolveSymlinksForRoots = roots => @@ -30,7 +30,7 @@ const getBlacklistRE = () => createBlacklist([/.*\/__fixtures__\/.*/]); * @todo(grabbou): As a separate PR, haste.platforms should be added before "native". * Otherwise, a.native.js will not load on Windows or other platforms */ -export const getDefaultConfig = (ctx: ContextT) => { +export const getDefaultConfig = (ctx: ConfigT) => { return { resolver: { resolverMainFields: ['react-native', 'browser', 'main'], @@ -80,7 +80,7 @@ export type ConfigOptionsT = {| * * This allows the CLI to always overwrite the file settings. */ -export default function load(ctx: ContextT, options?: ConfigOptionsT) { +export default function load(ctx: ConfigT, options?: ConfigOptionsT) { const defaultConfig = getDefaultConfig(ctx); return loadConfig({cwd: ctx.root, ...options}, defaultConfig); diff --git a/packages/cli/src/tools/types.flow.js b/packages/cli/src/tools/types.flow.js deleted file mode 100644 index f9c8447e1..000000000 --- a/packages/cli/src/tools/types.flow.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @flow - */ - -import {type ConfigT} from './config/types.flow'; - -export type ContextT = ConfigT; - -export type CommandT = { - name: string, - description?: string, - usage?: string, - func: (argv: Array, ctx: ContextT, args: Object) => ?Promise, - options?: Array<{ - command: string, - description?: string, - parse?: (val: string) => any, - default?: string | boolean | number, - }>, - examples?: Array<{ - desc: string, - cmd: string, - }>, -}; From 1f2d081b406adb0807652265344b8fe649695fa2 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 11:26:06 +0200 Subject: [PATCH 3/9] Fix tests --- .../src/tools/config/readConfigFromDisk.js | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/tools/config/readConfigFromDisk.js b/packages/cli/src/tools/config/readConfigFromDisk.js index 253edd00b..819333980 100644 --- a/packages/cli/src/tools/config/readConfigFromDisk.js +++ b/packages/cli/src/tools/config/readConfigFromDisk.js @@ -67,13 +67,18 @@ export function readDependencyConfigFromDisk( /** * Returns an array of commands that are defined in the project. + * + * `config.project` can be either an array of paths or a single string. + * Each of the files can export a commands (object) or an array of commands */ -const loadProjectCommand = (root, commands): Array => { - return commands.reduce( - (acc: Array, cmdPath: string) => - acc.concat(require(path.join(root, 'node_modules', cmdPath))), - [], - ); +const loadProjectCommands = ( + root, + commands: Array | string, +): Array => { + return [].concat(commands).reduce((acc: Array, cmdPath: string) => { + const cmds: Array | CommandT = require(path.join(root, cmdPath)); + return acc.concat(cmds); + }, []); }; /** @@ -98,9 +103,7 @@ export function readLegacyDependencyConfigFromDisk( hooks: config.commands, params: config.params, }, - commands: [] - .concat(config.plugin || []) - .map(p => loadProjectCommand(rootFolder, p)), + commands: loadProjectCommands(rootFolder, config.plugin), platforms: config.platform ? require(path.join(rootFolder, config.platform)) : undefined, From e0fd50fd353d3e9d0a17d74869defe0e15ce1101 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 11:27:12 +0200 Subject: [PATCH 4/9] Fix flow --- packages/cli/src/commands/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/index.js b/packages/cli/src/commands/index.js index b149aa830..97e20dc6b 100644 --- a/packages/cli/src/commands/index.js +++ b/packages/cli/src/commands/index.js @@ -37,4 +37,4 @@ export default ([ info, config, init, -]: CommandT); +]: CommandT[]); From 561c233fcd68994a63db48c513546eb673f014eb Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 12:25:36 +0200 Subject: [PATCH 5/9] Update tests and remove reactNativePath when not needed --- .../__snapshots__/index-test.js.snap | 106 +++++++++--------- .../src/tools/config/__tests__/index-test.js | 49 ++++---- .../src/tools/config/readConfigFromDisk.js | 15 ++- 3 files changed, 84 insertions(+), 86 deletions(-) diff --git a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap index 3fc391a4b..aed7baaa7 100644 --- a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap +++ b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap @@ -1,5 +1,60 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`should automatically put "react-native" into haste config 1`] = ` +Object { + "platforms": Array [ + "ios", + "android", + ], + "providesModuleNodeModules": Array [ + "react-native", + ], +} +`; + +exports[`should have a valid structure by default 1`] = ` +Object { + "assets": Array [], + "commands": Array [], + "dependencies": Object {}, + "haste": Object { + "platforms": Array [], + "providesModuleNodeModules": Array [], + }, + "platforms": Object {}, + "project": Object {}, + "reactNativePath": ".", + "root": "<>", +} +`; + +exports[`should load an out-of-tree "windows" platform that ships with a dependency 1`] = ` +Object { + "haste": Object { + "platforms": Array [ + "windows", + ], + "providesModuleNodeModules": Array [ + "react-native-windows", + ], + }, + "platforms": Object { + "windows": Object {}, + }, +} +`; + +exports[`should load commands from "react-native-foo" and "react-native-bar" packages 1`] = ` +Array [ + Object { + "name": "foo-command", + }, + Object { + "name": "bar-command", + }, +] +`; + exports[`should merge project configuration with default values 1`] = ` Object { "assets": Array [], @@ -61,45 +116,6 @@ Object { } `; -exports[`should have a valid structure by default 1`] = ` -Object { - "assets": Array [], - "commands": Array [], - "dependencies": Object {}, - "haste": Object { - "platforms": Array [], - "providesModuleNodeModules": Array [], - }, - "platforms": Object {}, - "project": Object {}, - "reactNativePath": ".", - "root": "<>", -} -`; - -exports[`should load an out-of-tree "windows" platform that ships with a dependency 1`] = ` -Object { - "haste": Object { - "platforms": Array [ - "windows", - ], - "providesModuleNodeModules": Array [ - "react-native-windows", - ], - }, - "platforms": Object { - "windows": Object {}, - }, -} -`; - -exports[`should load commands from "react-native-foo" and "react-native-bar" packages 1`] = ` -Array [ - "react-native-foo/command-foo.js", - "react-native-bar/command-bar.js", -] -`; - exports[`should read \`rnpm\` config from a dependency and transform it to a new format 1`] = ` Object { "assets": Array [], @@ -183,15 +199,3 @@ Object { }, } `; - -exports[`should automatically put "react-native" into haste config 1`] = ` -Object { - "platforms": Array [ - "ios", - "android", - ], - "providesModuleNodeModules": Array [ - "react-native", - ], -} -`; diff --git a/packages/cli/src/tools/config/__tests__/index-test.js b/packages/cli/src/tools/config/__tests__/index-test.js index a12f6464e..b738eb6d2 100644 --- a/packages/cli/src/tools/config/__tests__/index-test.js +++ b/packages/cli/src/tools/config/__tests__/index-test.js @@ -47,9 +47,6 @@ test('should return dependencies from package.json', () => { "dependencies": { "react-native": "0.0.1", "react-native-test": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); @@ -75,9 +72,6 @@ test('should read a config of a dependency and use it to load other settings', ( "dependencies": { "react-native": "0.0.1", "react-native-test": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); @@ -138,9 +132,6 @@ test('should read `rnpm` config from a dependency and transform it to a new form "dependencies": { "react-native": "0.0.1", "react-native-foo": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); @@ -150,27 +141,28 @@ test('should read `rnpm` config from a dependency and transform it to a new form test('should load commands from "react-native-foo" and "react-native-bar" packages', () => { writeFiles(DIR, { - 'node_modules/react-native-foo/package.json': `{ - "react-native": { - "commands": [ - "./command-foo.js" - ] - } + 'node_modules/react-native-foo/package.json': '{}', + 'node_modules/react-native-foo/react-native.config.js': `module.exports = { + commands: [ + { + name: 'foo-command', + func: () => console.log('foo') + } + ] }`, - 'node_modules/react-native-bar/package.json': `{ - "react-native": { - "commands": [ - "./command-bar.js" - ] - } + 'node_modules/react-native-bar/package.json': '{}', + 'node_modules/react-native-bar/react-native.config.js': `module.exports = { + commands: [ + { + name: 'bar-command', + func: () => console.log('foo') + } + ] }`, 'package.json': `{ "dependencies": { "react-native-foo": "0.0.1", "react-native-bar": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); @@ -183,6 +175,9 @@ test('should load an out-of-tree "windows" platform that ships with a dependency 'node_modules/react-native-windows/platform.js': ` module.exports = {"windows": {}}; `, + 'node_modules/react-native-windows/plugin.js': ` + module.exports = []; + `, 'node_modules/react-native-windows/package.json': `{ "name": "react-native-windows", "rnpm": { @@ -201,9 +196,6 @@ test('should load an out-of-tree "windows" platform that ships with a dependency 'package.json': `{ "dependencies": { "react-native-windows": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); @@ -217,9 +209,6 @@ test('should automatically put "react-native" into haste config', () => { 'package.json': `{ "dependencies": { "react-native": "0.0.1" - }, - "react-native": { - "reactNativePath": "." } }`, }); diff --git a/packages/cli/src/tools/config/readConfigFromDisk.js b/packages/cli/src/tools/config/readConfigFromDisk.js index 819333980..fda58d138 100644 --- a/packages/cli/src/tools/config/readConfigFromDisk.js +++ b/packages/cli/src/tools/config/readConfigFromDisk.js @@ -73,12 +73,17 @@ export function readDependencyConfigFromDisk( */ const loadProjectCommands = ( root, - commands: Array | string, + commands: ?(Array | string), ): Array => { - return [].concat(commands).reduce((acc: Array, cmdPath: string) => { - const cmds: Array | CommandT = require(path.join(root, cmdPath)); - return acc.concat(cmds); - }, []); + return [] + .concat(commands || []) + .reduce((acc: Array, cmdPath: string) => { + const cmds: Array | CommandT = require(path.join( + root, + cmdPath, + )); + return acc.concat(cmds); + }, []); }; /** From 20085c401b02d10eb1bc1466eb6d9d8af6e07be1 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 12:35:58 +0200 Subject: [PATCH 6/9] Better validate commands --- packages/cli/src/tools/config/schema.js | 28 +++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/tools/config/schema.js b/packages/cli/src/tools/config/schema.js index 29da79622..094c4e335 100644 --- a/packages/cli/src/tools/config/schema.js +++ b/packages/cli/src/tools/config/schema.js @@ -9,6 +9,30 @@ const map = (key, value) => .unknown(true) .pattern(key, value); +/** + * Schema for CommandT + */ +const command = t.object({ + name: t.string().required(), + description: t.string(), + usage: t.string(), + func: t.func().required(), + options: t.array().items( + t.object({ + command: t.string().required(), + description: t.string(), + parse: t.func(), + default: t.alternatives().try([t.bool(), t.number(), t.string()]), + }), + ), + examples: t.array().items( + t.object({ + desc: t.string().required(), + cmd: t.string().required(), + }), + ), +}); + /** * Schema for UserDependencyConfigT */ @@ -62,7 +86,7 @@ export const dependencyConfig = t ).default(), commands: t .array() - .items(t.object()) + .items(command) .default([]), }) .default(); @@ -142,7 +166,7 @@ export const projectConfig = t .default([]), commands: t .array() - .items(t.object()) + .items(command) .default([]), }) .default(); From eb7937609550260b6adbee5a671606cc2a2b0ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 9 Apr 2019 12:54:20 +0200 Subject: [PATCH 7/9] Update packages/cli/src/tools/config/__tests__/index-test.js Co-Authored-By: grabbou --- packages/cli/src/tools/config/__tests__/index-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/tools/config/__tests__/index-test.js b/packages/cli/src/tools/config/__tests__/index-test.js index b738eb6d2..3f549fcdf 100644 --- a/packages/cli/src/tools/config/__tests__/index-test.js +++ b/packages/cli/src/tools/config/__tests__/index-test.js @@ -155,7 +155,7 @@ test('should load commands from "react-native-foo" and "react-native-bar" packag commands: [ { name: 'bar-command', - func: () => console.log('foo') + func: () => console.log('bar') } ] }`, From d0da5ec78390d3a96462b3321c6417d4ff014e51 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 13:14:02 +0200 Subject: [PATCH 8/9] Update test --- .../src/tools/config/__tests__/__snapshots__/index-test.js.snap | 2 ++ packages/cli/src/tools/config/__tests__/index-test.js | 2 +- packages/cli/src/tools/config/index.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap index aed7baaa7..e2389afcb 100644 --- a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap +++ b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap @@ -47,9 +47,11 @@ Object { exports[`should load commands from "react-native-foo" and "react-native-bar" packages 1`] = ` Array [ Object { + "func": [Function], "name": "foo-command", }, Object { + "func": [Function], "name": "bar-command", }, ] diff --git a/packages/cli/src/tools/config/__tests__/index-test.js b/packages/cli/src/tools/config/__tests__/index-test.js index b738eb6d2..3c4a50198 100644 --- a/packages/cli/src/tools/config/__tests__/index-test.js +++ b/packages/cli/src/tools/config/__tests__/index-test.js @@ -167,7 +167,7 @@ test('should load commands from "react-native-foo" and "react-native-bar" packag }`, }); const {commands} = loadConfig(DIR); - expect(removeString(commands, DIR)).toMatchSnapshot(); + expect(commands).toMatchSnapshot(); }); test('should load an out-of-tree "windows" platform that ships with a dependency', () => { diff --git a/packages/cli/src/tools/config/index.js b/packages/cli/src/tools/config/index.js index aa903cea7..dcbd7ef6a 100644 --- a/packages/cli/src/tools/config/index.js +++ b/packages/cli/src/tools/config/index.js @@ -125,7 +125,7 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT { }, }: ConfigT), ); - + console.log(finalConfig.commands); return finalConfig; } From 0b0e5b8ef7a9ad350bac5ad0d1e41355aef7f5d6 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Tue, 9 Apr 2019 14:53:24 +0200 Subject: [PATCH 9/9] Need a linter against console.log --- packages/cli/src/tools/config/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/tools/config/index.js b/packages/cli/src/tools/config/index.js index dcbd7ef6a..aa903cea7 100644 --- a/packages/cli/src/tools/config/index.js +++ b/packages/cli/src/tools/config/index.js @@ -125,7 +125,7 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT { }, }: ConfigT), ); - console.log(finalConfig.commands); + return finalConfig; }