diff --git a/.circleci/config.yml b/.circleci/config.yml index 84e4ac74e9..54793168f4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,56 +1,123 @@ -version: 2 +version: 2.1 defaults: &defaults - docker: - - image: circleci/node:8 working_directory: ~/react-native-cli -jobs: - install-dependencies: +executors: + node8: + <<: *defaults + docker: + - image: circleci/node:8 + nodelts: + <<: *defaults + docker: + - image: circleci/node:lts + noderuby: <<: *defaults + docker: + - image: circleci/ruby:2.4-node + +commands: + install-dependencies: steps: - checkout - attach_workspace: at: ~/react-native-cli - restore_cache: keys: - - dependencies-{{ checksum "package.json" }} - - dependencies- - - run: yarn install + - v2-dependencies-{{ checksum "package.json" }} + - v2-dependencies- + - run: yarn --frozen-lockfile - save_cache: - key: dependencies-{{ checksum "package.json" }} + key: v2-dependencies-{{ checksum "package.json" }} paths: - node_modules - persist_to_workspace: root: . paths: - . - lint-and-flow: - <<: *defaults + run-lint: steps: - attach_workspace: at: ~/react-native-cli - - run: | - yarn lint - yarn flow-check - tests: - <<: *defaults + - run: yarn lint + run-typecheck: steps: - attach_workspace: at: ~/react-native-cli - - run: yarn test + - run: yarn flow-check + run-cocoa-pods-tests: + steps: + - attach_workspace: + at: ~/react-native-cli + - run: yarn test:ci:cocoapods + run-unit-tests: + steps: + - attach_workspace: + at: ~/react-native-cli + - run: yarn test:ci:unit - store_artifacts: path: coverage destination: coverage + run-e2e-tests: + steps: + - attach_workspace: + at: ~/react-native-cli + - run: yarn test:ci:e2e + +jobs: + setup: + executor: node8 + steps: + - install-dependencies + lint: + executor: node8 + steps: + - run-lint + typecheck: + executor: node8 + steps: + - run-typecheck + cocoa-pods: + executor: noderuby + steps: + - run-cocoa-pods-tests + unit-tests: + executor: node8 + steps: + - run-unit-tests + e2e-tests: + executor: node8 + steps: + - run-e2e-tests + lts-tests: + executor: nodelts + steps: + - install-dependencies + - run-lint + - run-typecheck + - run-unit-tests + # TODO: figure out why e2e tests fail even though not interfering with + # other tests + # - run-e2e-tests workflows: - version: 2 build-and-test: jobs: - - install-dependencies - - lint-and-flow: + - setup + - lint: + requires: + - setup + - typecheck: + requires: + - setup + - unit-tests: + requires: + - setup + - e2e-tests: requires: - - install-dependencies - - tests: + - setup + - cocoa-pods: requires: - - install-dependencies + - setup + - lts-tests diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..494825ac6e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,36 @@ +module.exports = { + extends: ['@react-native-community', 'plugin:import/errors'], + env: { + node: true, + }, + rules: { + 'prettier/prettier': [2, 'fb'], + }, + // @todo: remove once we cover whole codebase with types + plugins: ['import'], + settings: { + react: { + version: 'latest', + }, + 'import/resolver': { + alias: { + map: [['types', './types/index.js']], + }, + // Use /tsconfig.json for typescript resolution + typescript: {}, + }, + }, + overrides: [ + { + files: [ + '**/__mocks__/**', + '**/__fixtures__/**', + '**/__e2e__/**', + 'jest/**', + ], + env: { + jest: true, + }, + }, + ], +}; diff --git a/.flowconfig b/.flowconfig index c825f0b865..0563c1419b 100644 --- a/.flowconfig +++ b/.flowconfig @@ -23,9 +23,11 @@ flow-typed [options] emoji=true +esproposal.export_star_as=enable esproposal.optional_chaining=enable esproposal.nullish_coalescing=enable module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='types' -> '/types/index.js' suppress_type=$FlowIssue suppress_type=$FlowFixMe @@ -43,6 +45,7 @@ module.ignore_non_literal_requires=true all=warn unnecessary-optional-chain=off dynamic-export=off +unsafe-getters-setters=off # There is an ESLint rule for this unclear-type=off @@ -63,6 +66,3 @@ unclear-type unsafe-getters-setters untyped-import untyped-type-import - -[version] -^0.94.0 diff --git a/.gitignore b/.gitignore index 47b59865f5..71440e6efb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ package-lock.json *.log build/ .eslintcache +!packages/cli/src/commands/init/__fixtures__/editTemplate/node_modules +*.tsbuildinfo diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000..78d515160e --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,6 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', + bracketSpacing: false, + jsxBracketSameLine: true, +}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..961c024826 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "dbaeumer.vscode-eslint", + "redhat.vscode-yaml", + "flowtype.flow-for-vscode", + "esbenp.prettier-vscode" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..029ba75979 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,24 @@ +{ + "editor.rulers": [80], + "files.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/build": true + }, + "editor.formatOnSave": true, + "flow.useNPMPackagedFlow": true, + "javascript.validate.enable": false, + "prettier.eslintIntegration": true, + "eslint.validate": [ + "javascript", + "javascriptreact", + { + "language": "typescript", + "autoFix": true + }, + { + "language": "typescriptreact", + "autoFix": true + } + ] +} diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..9f2d69ff51 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @grabbou @thymikee @esemesek diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4367688131..8b701f3bc6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ Repository is splitted into two packages: You can test your changes by calling `cli.js` directly from the cloned repository. You need to make sure the version of React Native matches the one present in devDependencies of the CLI. Otherwise, you may get unexpected errors. ```sh -node /path/to/cloned/project/packages/cli/index.js +node /path/to/cloned/project/packages/cli/build/index.js ``` ## Testing `init` command @@ -35,13 +35,13 @@ yarn global add verdaccio ``` * Run verdaccio ```sh -yarn verdaccio +verdaccio ``` * Set npm registry to `verdaccio` proxy server ```sh npm set registry http://localhost:4873/ ``` -* Clone `react-native` and `@react-native-commiunity/cli` +* Clone `react-native` and `@react-native-community/cli` * Release new version of `@react-native-community/cli` to local npm proxy. If you have any issues, head over to [verdaccio](https://github.com/verdaccio/verdaccio) and check out the docs. ``` cd /path/to/cli/packages/cli && npm publish @@ -61,6 +61,25 @@ react-native init --version ${RN_VERSION} npm config set registry https://registry.npmjs.org/ ``` +## Running `start` command + +In order for symlinks to work correctly when running `start` locally, set REACT_NATIVE_APP_ROOT as the root folder of your cli project: + +``` +REACT_NATIVE_APP_ROOT=path/to/cli node path/to/cli/packages/cli/build/index.js start +``` + +## Running CLI with React Native from the source + +First make sure you have RN repo checked out and CLI repo checked out and built. Then you can start a new RN project with local version of CLI and RN without publishing or proxy: + +1. Check out `react-native` repo. Then update template in local `react-native/template/package.json`, replacing dependency version of `react-native` with the absolute path of the react native repo, for example: "react-native": "file:///Users/username/react-native" (you can find the absolute path using `pwd` command) + +1. Go back up and create a new RN project: `node ./cli/packages/cli/build/index.js init --template=file:///path/to/local/react-native RNTestProject` + +1. To work with android, update gradle config in the newly created project following the second part of [Christoph's instructions](https://gist.github.com/cpojer/38a91f90614f35769e88410e3a387b48) + +1. Run start (as described above) and compile your app eg `node ../cli/packages/cli/build/index.js run-android` (make sure you definitely have NDK r17c installed before building android) ## Typechecking, linting and testing diff --git a/README.md b/README.md index adef7f5bd4..50b1aa434b 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,79 @@ # React Native CLI -Command Line Interface for React Native. +Command line tools that ship with [`react-native`](https://github.com/facebook/react-native) in form of the `@react-native-community/cli` package. + +> It exposes `react-native` binary, so your can call `yarn react-native` or `npx react-native` directly from your project. [![Build Status][build-badge]][build] [![Version][version-badge]][package] [![MIT License][license-badge]][license] [![PRs Welcome][prs-welcome-badge]][prs-welcome] _Note: CLI has been extracted from core `react-native` as a part of "[Lean Core](https://github.com/facebook/react-native/issues/23313)" effort. Please read [this blog post](https://blog.callstack.io/the-react-native-cli-has-a-new-home-79b63838f0e6) for more details._ +## Contents + +- [Compatibility](#compatibility) +- [Documentation](#documentation) +- [About](#about) +- [Creating a new React Native project](#creating-a-new-react-native-project) + - [Using `npx` (_recommended_)](#using-npx-recommended) + - [Using global CLI (_legacy_)](#using-global-cli-legacy) +- [Usage in an existing React Native project](#usage-in-an-existing-react-native-project) +- [Updating the CLI](#updating-the-cli) +- [Maintainers](#maintainers) +- [License](#license) + +## Compatibility + +Our release cycle is independent of `react-native`. We follow semver and here is the compatibility table: + +| `@react-native-community/cli` | `react-native` | +| ----------------------------- | -------------- | +| ^2.0.0 | ^0.60.0 | +| [^1.0.0](tree/1.x) | ^0.59.0 | + +## Documentation + +- [configuration](./docs/configuration.md) +- [commands](./docs/commands.md) +- [plugins](./docs/plugins.md) +- [init](./docs/init.md) +- [autolinking](./docs/autolinking.md) + ## About -This repository contains tools and helpers for React Native projects in form of a CLI. We want to make a couple of things clear for you first: +This repository contains tools and helpers for React Native projects in form of a command line tool. There's been quite some confusion around that since the extraction from React Native core. Let's clear them up: -- this is a monorepo; -- there are currently two CLIs: the actual one called [`@react-native-community/cli`](./packages/cli) that does all the job and global `react-native-cli` which is used as its proxy; +- There are currently two CLIs: + - [`@react-native-community/cli`](./packages/cli) – **the one used directly by `react-native`**. That makes it a transitive dependency of your project. + - [`react-native-cli`](./packages/global-cli) – an optional global convenience package, which is a proxy to [`@react-native-community/cli`](./packages/cli) and global installation helper. **Please consider it legacy, because it's not necessary anymore**. +- When we say "the CLI" we mean `@react-native-community/cli`. +- We update the CLI independently of React Native itself. Please see [how to use the latest version](#updating-the-cli). +- This is a monorepo to keep stuff organized. -We know it's confusing, but we're actively working to make this indirection gone. +We're actively working to make any indirections gone. ## Creating a new React Native project -To start a new React Native project, you'll need to install a global module [`react-native-cli`](./packages/global-cli) and follow instructions there. +There are two ways to start a React Native project. + +### Using `npx` (_recommended_) -We strongly encourage you to **only use global `react-native-cli` for bootstrapping new projects**. Use local version for everything else. +> Available since `react-native@0.60` -## Usage in existing React Native project +This method is preferred if you don't want to install global packages. + +```sh +npx react-native init MyApp +``` + +### Using global CLI (_legacy_) + +You'll need to install a global module [`react-native-cli`](./packages/global-cli) and follow instructions there. + +> We strongly encourage you to **only use global `react-native-cli` for bootstrapping new projects**. Use local version for everything else. + +You can find out more about init command from the [documentation](./docs/init.md) + +## Usage in an existing React Native project Once you're inside an existing project, a local `react-native` binary will be available for you to use. Feel free to use Yarn to call it directly. @@ -29,7 +81,9 @@ Example running `start` command in terminal: ```sh yarn react-native start -# or if you don't use Yarn: +# or: +npx react-native start +# or node ./node_modules/.bin/react-native start ``` @@ -43,16 +97,32 @@ You can also add npm scripts to call it with whichever package manager you use: } ``` +## Updating the CLI + +Because we release independently of `react-native`, it happens that you may be locked on a version without fixes for bugs that affect you. Here's how to get it sorted: + +1. If you use lock files (`yarn.lock` or `package-lock.json`) - find the `@react-native-community/cli` entry, remove it, run `yarn install` / `npm install` once again. +2. If you don't use lock files – remove `node_modules` and run `yarn install` / `npm install` again. +3. Run `yarn list @react-native-community/cli` or `npm list @react-native-community/cli` and verify you're on the latest version. + +After performing these steps you should be on the latest CLI version. Feel free to do it once in a while, because we release often. + +## Maintainers + +- Michał Pierzchała ([**@thymikee**](https://github.com/thymikee)) - [Callstack](https://callstack.com) +- Mike Grabowski ([**@grabbou**](https://github.com/grabbou)) - [Callstack](https://callstack.com) +- Kacper Wiszczuk ([**@esemesek**](https://github.com/esemesek)) - [Callstack](https://callstack.com) + ## License Everything inside this repository is [MIT licensed](./LICENSE). -[build-badge]: https://img.shields.io/circleci/project/github/react-native-community/react-native-cli/master.svg?style=flat-square -[build]: https://circleci.com/gh/react-native-community/react-native-cli/tree/master +[build-badge]: https://img.shields.io/circleci/project/github/react-native-community/cli/master.svg?style=flat-square +[build]: https://circleci.com/gh/react-native-community/cli/tree/master [version-badge]: https://img.shields.io/npm/v/@react-native-community/cli.svg?style=flat-square -[package]: https://www.npmjs.com/package/@react-native-community/cli.svg +[package]: https://www.npmjs.com/package/@react-native-community/cli [license-badge]: https://img.shields.io/npm/l/@react-native-community/cli.svg?style=flat-square [license]: https://opensource.org/licenses/MIT [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square diff --git a/__e2e__/__snapshots__/init.test.js.snap b/__e2e__/__snapshots__/init.test.js.snap new file mode 100644 index 0000000000..138ac62140 --- /dev/null +++ b/__e2e__/__snapshots__/init.test.js.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`init --template: package.json contains necessary configuration 1`] = ` +Object { + "dependencies": Object { + "react": "16.8.1", + "react-native": "0.59.0-rc.1", + }, + "devDependencies": Object { + "@babel/core": "^7.3.3", + "@babel/runtime": "^7.3.1", + "@react-native-community/eslint-config": "^0.0.3", + "babel-jest": "^24.1.0", + "jest": "^24.1.0", + "metro-react-native-babel-preset": "^0.51.1", + "react-test-renderer": "16.8.1", + }, + "jest": Object { + "preset": "react-native", + }, + "name": "TestInit", + "private": true, + "scripts": Object { + "start": "node node_modules/react-native/local-cli/cli.js start", + "test": "jest", + }, + "version": "0.0.1", +} +`; diff --git a/__e2e__/init.test.js b/__e2e__/init.test.js new file mode 100644 index 0000000000..747166aa2a --- /dev/null +++ b/__e2e__/init.test.js @@ -0,0 +1,104 @@ +// @flow +import fs from 'fs'; +import path from 'path'; +import {run, getTempDirectory, cleanup, writeFiles} from '../jest/helpers'; + +const DIR = getTempDirectory('command-init'); + +beforeEach(() => { + cleanup(DIR); + writeFiles(DIR, {}); +}); +afterEach(() => { + cleanup(DIR); +}); + +test('init --template fails without package name', () => { + const {stderr} = run( + DIR, + ['init', '--template', 'react-native-new-template'], + {expectedFailure: true}, + ); + expect(stderr).toContain('missing required argument'); +}); + +const templateFiles = [ + '.buckconfig', + '.eslintrc.js', + '.flowconfig', + '.gitattributes', + // should be here, but it's not published yet + // '.gitignore', + '.watchmanconfig', + 'App.js', + '__tests__', + 'android', + 'babel.config.js', + 'index.js', + 'ios', + 'metro.config.js', + 'node_modules', + 'package.json', + 'yarn.lock', +]; + +test('init --template', () => { + const {stdout} = run(DIR, [ + 'init', + '--template', + 'react-native-new-template', + 'TestInit', + ]); + + expect(stdout).toContain('Welcome to React Native!'); + expect(stdout).toContain('Run instructions'); + + // make sure we don't leave garbage + expect(fs.readdirSync(DIR)).toEqual(['TestInit']); + expect(fs.readdirSync(path.join(DIR, 'TestInit'))).toEqual(templateFiles); + + const pkgJson = require(path.join(DIR, 'TestInit', 'package.json')); + expect(pkgJson).toMatchSnapshot( + 'package.json contains necessary configuration', + ); +}); + +test('init --template file:/tmp/custom/template', () => { + writeFiles(DIR, { + 'custom/template/template.config.js': `module.exports = { + placeholderName: 'HelloWorld', + templateDir: './template-dir', + };`, + 'custom/template/package.json': + '{ "name": "template", "version": "0.0.1" }', + 'custom/template/template-dir/package.json': '{}', + 'custom/template/template-dir/empty': '', + }); + + const {stdout} = run(DIR, [ + 'init', + '--template', + `file://${path.resolve(DIR, 'custom', 'template')}`, + 'TestInit', + ]); + + expect(stdout).toContain('Run instructions'); +}); + +test('init --template with custom project path', () => { + const projectName = 'TestInit'; + const customPath = 'custom-path'; + + run(DIR, [ + 'init', + '--template', + 'react-native-new-template', + projectName, + '--directory', + 'custom-path', + ]); + + // make sure we don't leave garbage + expect(fs.readdirSync(DIR)).toEqual([customPath]); + expect(fs.readdirSync(path.join(DIR, customPath))).toEqual(templateFiles); +}); diff --git a/__e2e__/install.test.js b/__e2e__/install.test.js new file mode 100644 index 0000000000..5f8c1f63ca --- /dev/null +++ b/__e2e__/install.test.js @@ -0,0 +1,34 @@ +// @flow +import path from 'path'; +import {run, getTempDirectory, cleanup, writeFiles} from '../jest/helpers'; + +const DIR = getTempDirectory('command-install-test'); +const pkg = 'react-native-config'; + +beforeEach(() => { + cleanup(DIR); + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'package.json': '{}', + }); +}); +afterEach(() => cleanup(DIR)); + +test.each(['yarn', 'npm'])('install module with %s', pm => { + if (pm === 'yarn') { + writeFiles(DIR, {'yarn.lock': ''}); + } + const {stdout, code} = run(DIR, ['install', pkg]); + + expect(stdout).toContain(`Installing "${pkg}"`); + expect(stdout).toContain(`Linking "${pkg}"`); + // TODO – this behavior is a bug, linking should fail/warn without native deps + // to link. Not a high priority since we're changing how link works + expect(stdout).toContain(`Successfully installed and linked "${pkg}"`); + expect(require(path.join(DIR, 'package.json'))).toMatchObject({ + dependencies: { + [pkg]: expect.any(String), + }, + }); + expect(code).toBe(0); +}); diff --git a/__e2e__/legacyInit.test.js b/__e2e__/legacyInit.test.js new file mode 100644 index 0000000000..4e7df62281 --- /dev/null +++ b/__e2e__/legacyInit.test.js @@ -0,0 +1,72 @@ +// @flow +import fs from 'fs'; +import path from 'path'; +import execa from 'execa'; +import {getTempDirectory, cleanup, writeFiles} from '../jest/helpers'; + +const DIR = getTempDirectory('command-legacy-init'); + +beforeEach(() => { + cleanup(DIR); + writeFiles(DIR, {}); +}); +afterEach(() => { + cleanup(DIR); +}); + +test('legacy init through react-native-cli', () => { + const templateFiles = [ + '.buckconfig', + '.eslintrc.js', + '.flowconfig', + '.gitattributes', + '.gitignore', + '.watchmanconfig', + 'App.js', + '__tests__', + 'android', + 'app.json', + 'babel.config.js', + 'index.js', + 'ios', + 'metro.config.js', + 'node_modules', + 'package.json', + 'yarn.lock', + ]; + + const {stdout} = execa.sync('npx', ['react-native-cli', 'init', 'TestApp'], { + cwd: DIR, + }); + + expect(stdout).toContain('Run instructions'); + + // make sure we don't leave garbage + expect(fs.readdirSync(DIR)).toEqual(['TestApp']); + expect(fs.readdirSync(path.join(DIR, 'TestApp'))).toEqual(templateFiles); + + const pkgJson = require(path.join(DIR, 'TestApp', 'package.json')); + expect(pkgJson).toMatchObject({ + dependencies: { + react: expect.any(String), + 'react-native': expect.any(String), + }, + devDependencies: { + '@babel/core': expect.any(String), + '@babel/runtime': expect.any(String), + 'babel-jest': expect.any(String), + jest: expect.any(String), + 'metro-react-native-babel-preset': expect.any(String), + 'react-test-renderer': expect.any(String), + }, + jest: { + preset: 'react-native', + }, + name: 'TestApp', + private: true, + scripts: { + start: 'react-native start', + test: 'jest', + }, + }); +}); diff --git a/__e2e__/uninstall.test.js b/__e2e__/uninstall.test.js new file mode 100644 index 0000000000..5103aeedec --- /dev/null +++ b/__e2e__/uninstall.test.js @@ -0,0 +1,55 @@ +// @flow +import {run, getTempDirectory, cleanup, writeFiles} from '../jest/helpers'; + +const DIR = getTempDirectory('command-uninstall-test'); +const pkg = 'react-native-config'; + +beforeEach(() => { + cleanup(DIR); + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native-config/package.json': '{}', + 'package.json': `{ + "dependencies": { + "react-native-config": "*" + } + }`, + }); +}); +afterEach(() => cleanup(DIR)); + +test('uninstall fails when package is not defined', () => { + writeFiles(DIR, { + 'package.json': `{ + "dependencies": {} + }`, + }); + const {stderr, code} = run(DIR, ['uninstall'], {expectedFailure: true}); + + expect(stderr).toContain('missing required argument'); + expect(code).toBe(1); +}); + +test('uninstall fails when package is not installed', () => { + writeFiles(DIR, { + 'package.json': `{ + "dependencies": {} + }`, + }); + const {stderr, code} = run(DIR, ['uninstall', pkg], {expectedFailure: true}); + + expect(stderr).toContain(`Failed to unlink "${pkg}".`); + expect(code).toBe(1); +}); + +test.each(['yarn', 'npm'])('uninstall module with %s', pm => { + if (pm === 'yarn') { + writeFiles(DIR, {'yarn.lock': ''}); + } + const {stdout, code} = run(DIR, ['uninstall', pkg]); + + expect(stdout).toContain(`Unlinking "${pkg}"`); + expect(stdout).toContain(`Uninstalling "${pkg}"`); + expect(stdout).toContain(`Successfully uninstalled and unlinked "${pkg}"`); + expect(code).toBe(0); +}); diff --git a/packages/cli/src/__mocks__/fs.js b/__mocks__/fs.js similarity index 85% rename from packages/cli/src/__mocks__/fs.js rename to __mocks__/fs.js index f6cde8d67f..2220206cf8 100644 --- a/packages/cli/src/__mocks__/fs.js +++ b/__mocks__/fs.js @@ -14,7 +14,7 @@ let fs; function setMockFilesystem(object, platform) { reset(platform); const root = platform === 'win32' ? 'c:\\' : '/'; - mockDir(root, { ...object }); + mockDir(root, {...object}); return root; } @@ -24,14 +24,14 @@ function mockDir(dirPath, desc) { const entPath = path.join(dirPath, entName); if (typeof ent === 'string' || ent instanceof Buffer) { fs.writeFileSync(entPath, ent); - continue; // eslint-disable-line no-continue + continue; } if (typeof ent !== 'object') { throw new Error(util.format('invalid entity:', ent)); } if (ent.SYMLINK != null) { fs.symlinkSync(ent.SYMLINK, entPath); - continue; // eslint-disable-line no-continue + continue; } fs.mkdirSync(entPath); mockDir(entPath, ent); @@ -41,18 +41,18 @@ function mockDir(dirPath, desc) { function reset(platform) { if (path.mock == null) { throw new Error( - 'to use this "fs" module mock, you must also mock the "path" module' + 'to use this "fs" module mock, you must also mock the "path" module', ); } path.mock.reset(platform); const cwd = () => (platform === 'win32' ? 'c:\\' : '/'); - fs = new MemoryFS({ platform, cwd }); + fs = new MemoryFS({platform, cwd}); Object.assign(mockFs, fs); } const mockFs = {}; mockFs.__setMockFilesystem = setMockFilesystem; -mockFs.mock = { clear: reset }; +mockFs.mock = {clear: reset}; reset('posix'); diff --git a/packages/cli/src/__mocks__/path.js b/__mocks__/path.js similarity index 93% rename from packages/cli/src/__mocks__/path.js rename to __mocks__/path.js index 884f26590e..b19d3d3b45 100644 --- a/packages/cli/src/__mocks__/path.js +++ b/__mocks__/path.js @@ -13,7 +13,7 @@ function reset(platform) { Object.assign(mockPath, jest.requireActual('path')[platform]); } -mockPath.mock = { reset }; +mockPath.mock = {reset}; reset('posix'); diff --git a/babel.config.js b/babel.config.js index 2621b5d720..f7a77eb480 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,20 +1,34 @@ module.exports = { babelrcRoots: ['packages/*'], + overrides: [ + { + presets: ['@babel/preset-flow'], + test: '**/*.js', + }, + { + presets: ['@babel/preset-typescript'], + test: '**/*.ts', + }, + ], presets: [ [ require.resolve('@babel/preset-env'), { - targets: { node: 8 }, + targets: {node: 8}, useBuiltIns: 'entry', }, ], - require.resolve('@babel/preset-flow'), ], plugins: [ require.resolve('@babel/plugin-transform-strict-mode'), + [require.resolve('@babel/plugin-transform-modules-commonjs'), {lazy: true}], [ - require.resolve('@babel/plugin-transform-modules-commonjs'), - { lazy: true }, + require.resolve('babel-plugin-module-resolver', { + root: ['.'], + alias: { + types: './types', + }, + }), ], ], }; diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 84dcb122af..0000000000 --- a/commitlint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional'], -}; diff --git a/docs/autolinking.md b/docs/autolinking.md new file mode 100644 index 0000000000..67520b3370 --- /dev/null +++ b/docs/autolinking.md @@ -0,0 +1,141 @@ +# Autolinking + +React Native libraries often come with platform-specific (native) code. Autolinking is a mechanism that allows your project to discover and use this code. + +Add a library using your favorite package manager and run the build: + +```sh +# install +yarn add react-native-webview +cd ios && pod install && cd .. # CocoaPods on iOS needs this extra step +# run +yarn react-native run-ios +yarn react-native run-android +``` + +That's it. No more editing build config files to use native code. + +> Autolinking is a replacement for [`react-native link`](./linking.md). If you have been using React Native before version 0.60, please `unlink` native dependencies if you have any from a previous install. + +## How does it work + +Each platform defines its own [`platforms`](./platforms.md) configuration. It instructs the CLI on how to find information about native dependencies. This information is exposed through the [`config`](./commands.md#config) command in a JSON format. It's then used by the scripts run by the platform's build tools. Each script applies the logic to link native dependencies specific to its platform. + +## Platform iOS + +The [native_modules.rb](https://github.com/react-native-community/cli/blob/master/packages/platform-ios/native_modules.rb) script required by `Podfile` gets the package metadata from `react-native config` during install phase and: + +1. Adds dependencies via CocoaPods dev pods (using files from a local path). +1. Adds build phase scripts to the App project’s build phase. (see examples below) + +This means that all libraries need to ship a Podspec either in the root of their folder or where the Xcode project is. Podspec references the native code that your library depends on. + +The implementation ensures that a library is imported only once. If you need to have a custom `pod` directive then include it above the `use_native_modules!` function. + +### Example + +See example usage in React Native template's [Podfile](https://github.com/facebook/react-native/blob/0.60-stable/template/ios/Podfile). + +### Custom root (monorepos) + +The project root is where `node_modules` with `react-native` is. Autolinking script assume your project root to be `".."`, relative to `ios` directory. If you're in a project with custom structure, like this: + +``` +root/ + node_modules + example/ + ios/ +``` + +you'll need to set a custom root. Pass it as an argument to `use_native_modules!` and adjust the `native_modules` path accordingly: + +```rb +# example/ios/Podfile +require_relative '../../node_modules/@react-native-community/cli-platform-ios/native_modules' +# ... +use_native_modules!("../..") +``` + +## Platform Android + +The [native_modules.gradle](https://github.com/react-native-community/cli/blob/master/packages/platform-android/native_modules.gradle) script is included in your project's `settings.gradle` and `app/build.gradle` files and: + +1. At build time, before the build script is run: + 1. A first Gradle plugin (in `settings.gradle`) runs `applyNativeModulesSettingsGradle` method. It uses the package metadata from `react-native config` to add Android projects. + 1. A second Gradle plugin (in `app/build.gradle`) runs `applyNativeModulesAppBuildGradle` method. It creates a list of React Native packages to include in the generated `/android/build/generated/rn/src/main/java/com/facebook/react/PackageList.java` file. +1. At runtime, the list of React Native packages generated in step 1.2 is registered by `getPackages` method of `ReactNativeHost` in `MainApplication.java`. + +### Example + +See example usage in React Native template: + +- [settings.gradle](https://github.com/facebook/react-native/blob/0.60-stable/template/android/settings.gradle) +- [app/build.gradle](https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle#L185) +- [MainApplication.java](https://github.com/facebook/react-native/blob/769e35ba5f4c31ef913035a5cc8bc0e88546ca55/template/android/app/src/main/java/com/helloworld/MainApplication.java#L22-L28) + +### Custom root (monorepos) + +The project root is where `node_modules` with `react-native` is. Autolinking scripts assume your project root to be `".."`, relative to `android` directory. If you're in a project with custom structure, like this: + +``` +root/ + node_modules + example/ + android/ +``` + +you'll need to set a custom root. Pass it as a second argument to `applyNativeModulesSettingsGradle` and `applyNativeModulesAppBuildGradle` methods and adjust the `native_modules.gradle` path accordingly: + +```groovy +// example/android/settings.gradle +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); +applyNativeModulesSettingsGradle(settings, "../..") +``` + +```groovy +// example/android/app/build.gradle +apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); +applyNativeModulesAppBuildGradle(project, "../..") +``` + +## What do I need to have in my package to make it work? + +You’re already using Gradle, so Android support will work by default. + +On the iOS side, you will need to ensure you have a Podspec to the root of your repo. The `react-native-webview` Podspec is a good example of a [`package.json`](https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec)-driven Podspec. Note that CocoaPods does not support having `/`s in the name of a dependency, so if you are using scoped packages - you may need to change the name for the Podspec. + +## How can I customize how autolinking works for my package? + +A library can add a `react-native.config.js` configuration file, which will customize the defaults. + +## How can I disable autolinking for unsupported library? + +During the transition period some packages may not support autolinking on certain platforms. To disable autolinking for a package, update your `react-native.config.js`'s `dependencies` entry to look like this: + +```js +// react-native.config.js +module.exports = { + dependencies: { + 'some-unsupported-package': { + platforms: { + android: null, // disable Android platform, other platforms will still autolink if provided + }, + }, + }, +}; +``` + +## How can I autolink a local library? + +We can leverage CLI configuration to make it "see" React Native libraries that are not part of our 3rd party dependencies. To do so, update your `react-native.config.js`'s `dependencies` entry to look like this: + +```js +// react-native.config.js +module.exports = { + dependencies: { + 'local-rn-library': { + root: '/root/libraries', + }, + }, +}; +``` diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 0000000000..b7b7519653 --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,501 @@ +# Commands + +React Native CLI comes with following commands: + +- [`bundle`](#bundle) +- [`config`](#config) +- [`init`](#init) +- [`info`](#info) +- [`install`](#install) +- [`link`](#link) +- [`log-android`](#log-android) +- [`log-ios`](#log-ios) +- [`ram-bundle`](#ram-bundle) +- [`run-android`](#run-android) +- [`run-ios`](#run-ios) +- [`start`](#start) +- [`uninstall`](#uninstall) +- [`unlink`](#unlink) +- [`upgrade`](#upgrade) + +### `bundle` + +Usage: + +```sh +react-native bundle +``` + +Builds the JavaScript bundle for offline use. + +#### `--entry-file ` + +Path to the root JS file, either absolute or relative to JS root. + +#### `--platform [string]` + +> default: ios + +Either "ios" or "android". + +#### `--transformer [string]` + +Specify a custom transformer to be used. + +#### `--dev [boolean]` + +> default: true + +If false, warnings are disabled and the bundle is minified. + +#### `--minify [boolean]` + +Allows overriding whether bundle is minified. This defaults to false if dev is true, and true if dev is false. Disabling minification can be useful for speeding up production builds for testing purposes. + +#### `--bundle-output ` + +File name where to store the resulting bundle, ex. `/tmp/groups.bundle`. + +#### `--bundle-encoding [string]` + +> default: utf8 + +Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer). + +#### `--max-workers [number]` + +Specifies the maximum number of workers the worker-pool will spawn for transforming files. This defaults to the number of the cores available on your machine. + +#### `--sourcemap-output [string]` + +File name where to store the sourcemap file for resulting bundle, ex. `/tmp/groups.map`. + +#### `--sourcemap-sources-root [string]` + +Path to make sourcemaps sources entries relative to, ex. `/root/dir`. + +#### `--sourcemap-use-absolute-path` + +> default: false + +Report SourceMapURL using its full path. + +#### `--assets-dest [string]` + +Directory name where to store assets referenced in the bundle. + +#### `--reset-cache` + +> default: false + +Removes cached files. + +#### `--read-global-cache` + +> default: false + +Try to fetch transformed JS code from the global cache, if configured. + +#### `--config [string]` + +Path to the CLI configuration file. + +### `config` + +Usage: + +```sh +react-native config +``` + +Output project and dependencies configuration in JSON format to stdout. Used by [autolinking](./autolinking.md). + +### `init` + +> Available since 0.60.0 + +> **IMPORTANT**: Please note that this command is not available through `react-native-cli`, hence you need to either invoke it directly from `@react-native-community/cli` or `react-native` package which proxies binary to this CLI since 0.60.0, so it's possible to use it with e.g. `npx`. + +Usage (with `npx`): + +```sh +npx react-native init [options] +``` + +Initialize a new React Native project named in a directory of the same name. You can find out more use cases in [init docs](./init.md). + +#### Options + +#### `--version [string]` + +Uses a valid semver version of React Native as a template. + +#### `--directory [string]` + +Uses a custom directory instead of ``. + +#### `--template [string]` + +Uses a custom template. Accepts following template sources: + +- an npm package name +- an absolute path to a local directory +- an absolute path to a tarball created using `npm pack` + +Example: + +```sh +npx react-native init MyApp --template react-native-custom-template +npx react-native init MyApp --template typescript +npx react-native init MyApp --template file:///Users/name/template-path +npx react-native init MyApp --template file:///Users/name/template-name-1.0.0.tgz +``` + +A template is any directory or npm package that contains a `template.config.js` file in the root with following of the following type: + +```ts +type Template = { + // Placeholder used to rename and replace in files + // package.json, index.json, android/, ios/ + placeholderName: string; + // Directory with template + templateDir: string; + // Path to script, which will be executed after init + postInitScript?: string; +}; +``` + +Example `template.config.js`: + +```js +module.exports = { + placeholderName: 'ProjectName', + templateDir: './template', + postInitScript: './script.js', +}; +``` + +#### `--npm` + +Force use of npm during initialization + +### `info` + +Usage: + +```sh +react-native info +``` + +Get relevant version info about OS, toolchain and libraries. Useful when sending bug reports. + +### `install` + +Usage: + +```sh +react-native install +``` + +Installs single package from npm and then links native dependencies. If `install` detects `yarn.lock` in your project, it will use Yarn as package manager. Otherwise `npm` will be used. + +### `link` + +> Will be replaced by [autolinking](./autolinking.md) soon. + +Usage: + +```sh +react-native link [packageName] +``` + +Links assets and optionally native modules. + +#### Options + +#### `--all` + +Link all native modules and assets. + +#### `--platforms [list]` + +Pass comma-separated list of platforms to scope `link` to. + +### `log-android` + +Usage: + +```sh +react-native log-android +``` + +Starts [`logkitty`](https://github.com/zamotany/logkitty) displaying pretty Android logs. + +### `log-ios` + +Usage: + +```sh +react-native log-ios +``` + +Starts iOS device syslog tail. + +### `ram-bundle` + +Usage: + +```sh +react-native ram-bundle [options] +``` + +Builds JavaScript as a "Random Access Module" bundle for offline use. + +#### Options + +Accepts all of [bundle commands](#bundle) and following: + +#### `--indexed-ram-bundle` + +Force the "Indexed RAM" bundle file format, even when building for Android. + +### `run-android` + +Usage: + +```sh +react-native run-android [options] +``` + +Builds your app and starts it on a connected Android emulator or device. + +#### Options + +#### `--root [string]` + +Override the root directory for the Android build (which contains the android directory)'. + +#### `--variant [string]` + +> default: 'debug' + +Specify your app's build variant. + +#### `--appFolder [string]` + +> default: 'app' + +Specify a different application folder name for the Android source. If not, we assume is "app". + +#### `--appId [string]` + +Specify an `applicationId` to launch after build. + +#### `--appIdSuffix [string]` + +Specify an `applicationIdSuffix` to launch after build. + +#### `--main-activity [string]` + +> default: 'MainActivity' + +Name of the activity to start. + +#### `--deviceId [string]` + +builds your app and starts it on a specific device/simulator with the given device id (listed by running "adb devices" on the command line). + +#### `--no-packager` + +Do not launch packager while building. + +#### `--port [number]` + +> default: process.env.RCT_METRO_PORT || 8081 + +#### `--terminal [string]` + +> default: process.env.REACT_TERMINAL || process.env.TERM_PROGRAM + +Launches the Metro Bundler in a new window using the specified terminal path. + +#### `--tasks [list]` + +> default: 'installDebug' + +Run custom gradle tasks. If this argument is provided, then `--variant` option is ignored. +Example: `yarn react-native run-android --tasks clean,installDebug`. + +### `run-ios` + +Usage: + +```sh +react-native run-ios [options] +``` + +Builds your app and starts it on iOS simulator. + +#### Options + +#### `--simulator [simulator_name]` + +Explicitly set the simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version, e.g. `"iPhone 6 (10.0)"`. + +Default: `"iPhone X"` + +Notes: `simulator_name` must be a valid iOS simulator name. If in doubt, open your AwesomeApp/ios/AwesomeApp.xcodeproj folder on XCode and unroll the dropdown menu containing the simulator list. The dropdown menu is situated on the right hand side of the play button (top left corner). + +Example: this will launch your projet directly onto the iPhone XS Max simulator: + +```sh +react-native run-ios --simulator "iPhone XS Max" +``` + +#### `--configuration [string]` + +Explicitly set the scheme configuration to use default: 'Debug'. + +#### `--scheme [string]` + +Explicitly set Xcode scheme to use. + +#### `--project-path [string]` + +Path relative to project root where the Xcode project (.xcodeproj) lives. default: 'ios'. + +#### `--device [string]` + +Explicitly set device to use by name. The value is not required if you have a single device connected. + +#### `--udid [string]` + +Explicitly set device to use by udid. + +#### `--no-packager` + +Do not launch packager while building. + +#### `--verbose` + +Do not use `xcpretty` even if installed. + +#### `--port [number]` + +Runs packager on specified port + +Default: `process.env.RCT_METRO_PORT || 8081` + +### `start` + +Usage: + +``` +react-native start [option] +``` + +Starts the server that communicates with connected devices + +#### Options + +#### `--port [number]` + +Specify port to listen on + +#### `--watchFolders [list]` + +Specify any additional folders to be added to the watch list + +#### `--assetExts [list]` + +Specify any additional asset extensions to be used by the packager + +#### `--sourceExts [list]` + +Specify any additional source extensions to be used by the packager + +#### `--platforms [list]` + +Specify any additional platforms to be used by the packager + +#### `--providesModuleNodeModules [list]` + +Specify any npm packages that import dependencies with providesModule + +#### `--max-workers [number]` + +Specifies the maximum number of workers the worker-pool will spawn for transforming files. This defaults to the number of the cores available on your machine + +#### `--transformer [string]` + +Specify a custom transformer to be used + +#### `--reset-cache, --resetCache` + +Removes cached files + +#### `--custom-log-reporter-path, --customLogReporterPath [string]` + +Path to a JavaScript file that exports a log reporter as a replacement for TerminalReporter + +#### `--verbose` + +Enables logging + +#### `--https` + +Enables https connections to the server + +#### `--key [path]` + +Path to custom SSL key + +#### `--cert [path]` + +Path to custom SSL cert + +#### `--config [string]` + +Path to the CLI configuration file + +### `uninstall` + +Usage: + +```sh +react-native uninstall +``` + +Unlinks single package native dependencies and then uninstalls it from `package.json`. If `uninstall` detects `yarn.lock` in your project, it will use Yarn as package manager. Otherwise `npm` will be used. + +### `unlink` + +> Will be replaced by [autolinking](./autolinking.md) soon. + +Usage: + +``` +react-native unlink [options] +``` + +Unlink native dependency linked with the `link` command. + +#### Options + +#### `--platforms [list]` + +Scope unlinking to specified platforms + +### `upgrade` + +Usage: + +```sh +react-native upgrade [npm-version] +``` + +Upgrade your app's template files to the specified or latest npm version using [rn-diff-purge](https://github.com/react-native-community/rn-diff-purge) project. Only valid semver versions are allowed. + +Using this command is a recommended way of upgrading relatively simple React Native apps with not too many native libraries linked. The more iOS and Android build files are modified, the higher chance for a conflicts. The command will guide you on how to continue upgrade process manually in case of failure. + +_Note: If you'd like to upgrade using this method from React Native version lower than 0.59.0, you may use a standalone version of this CLI: `npx @react-native-community/cli upgrade`._ diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000000..24aeb533e8 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,120 @@ +# Configuration + +React Native CLI has a configuration mechanism that allows changing its behavior and providing additional features. + +> Note: Configuring CLI used to be possible via `rn-cli.config.js` (that has been renamed to `metro.config.js`) and never documented `rnpm` entry on the `package.json`. We have provided migration guides where possible. + +React Native CLI can be configured by creating a `react-native.config.js` at the root of the project. Depending on the type of a package, the set of valid properties is different. + +Check the documentation for + +- [projects](./projects.md) +- [dependencies](./dependencies.md) +- [platforms](./platforms.md) +- [plugins](./plugins.md) + +to learn more about different types of configuration and features available. + +## Migration guide + +`"rnpm"` is deprecated and support for it will be removed in next major version of the CLI. + +> **Important**: Proceed further only if your project uses `"rnpm"` in `package.json`. + +There are different kinds of React Native projects, including apps, libraries and platforms. For each we prepared a brief "before & after" of the configuration shape with legacy `"rnpm"` and current `react-native.config.js`. Please mind that all configuration entries are optional. + +### Apps + +`package.json` entry: + +```json +{ + "rnpm": { + "ios": {}, + "android": {}, + "assets": ["./path-to-assets"], + "plugin": "./path-to-commands.js" + } +} +``` + +becomes `react-native.config.js` + +```js +module.exports = { + project: { + ios: {}, + android: {}, // grouped into "project" + }, + assets: ['./path-to-assets'], // stays the same + commands: require('./path-to-commands.js'), // formerly "plugin", returns an array of commands +}; +``` + +### Libraries + +`package.json` entry: + +```json +{ + "rnpm": { + "ios": {}, + "android": {}, + "assets": ["./path-to-assets"], + "hooks": { + "prelink": "./path-to-a-prelink-hook" + } + } +} +``` + +becomes `react-native.config.js`: + +```js +module.exports = { + // config for a library is scoped under "dependency" key + dependency: { + platforms: { + ios: {}, + android: {}, // projects are grouped into "platforms" + }, + assets: ['./path-to-assets'], // stays the same + // hooks are considered anti-pattern, please avoid them + hooks: { + prelink: './path-to-a-prelink-hook', + }, + }, +}; +``` + +You'll find more details in [dependencies](./dependencies.md) docs. + +### Out-of-tree platforms + +`package.json` entry: + +```json +{ + "rnpm": { + "haste": { + "platforms": ["windows"], + "providesModuleNodeModules": ["react-native-windows"] + }, + "platform": "./local-cli/platform.js" + } +} +``` + +becomes `react-native.config.js` + +```js +module.exports = { + platforms: { + // grouped under "platforms" entry + windows: require('./local-cli/platform.js').windows, + }, + // "haste" is no longer needed +}; +``` + +You'll find more details in [platforms](./platforms.md) docs. diff --git a/docs/dependencies.md b/docs/dependencies.md new file mode 100644 index 0000000000..6ce468e7d4 --- /dev/null +++ b/docs/dependencies.md @@ -0,0 +1,159 @@ +# Dependency + +A dependency is a JavaScript package that is listed under dependencies present in the project's `package.json`. It can also contain native, platform-specific files that should be linked. + +For example, `lodash` is a dependency that doesn't have any native code to link. On the other hand, `react-native-vector-icons` is a dependency that contains not only native code, but also font assets that the CLI should link. + +By default, CLI analyses the folder structure inside the dependency and looks for assets and native files to link. This simple heuristic works in most of the cases. + +At the same time, a dependency can explicitly set its configuration in case CLI cannot infer it properly. A dependency can also define additional settings, such as a script to run after linking, in order to support some advanced use-cases. + +## How does it work? + +A dependency can define the following `react-native.config.js` at the root: + +```js +module.exports = { + dependency: { + platforms: { + ios: { + project: './Custom.xcodeproj' + } + } + assets: ['./assets'] + } +}; +``` + +> The above configuration informs CLI of the additional assets to link and about a custom project location. + +## Dependency interface + +The following type describes the configuration of a dependency that can be set under `dependency` key inside `react-native.config.js`. + +```ts +type DependencyConfigT = { + platforms: { + [key: string]: any; + }; + assets: string[]; + hooks: { + [key: string]: string; + }; +}; +``` + +> Note: This interface is subject to breaking changes. We may consider renaming some keys to simplify the configuration further. If you are going to use it, be prepared to update before we ship a stable 0.60.0 release. + +### platforms + +A map of specific settings that can be set per platform. The exact shape is always defined by the package that provides given platform. + +In most cases, as a library author, you should not need to define any of these. + +The following settings are available on iOS and Android: + +```ts +type DependencyParamsIOST = { + project?: string; + podspecPath?: string; + sharedLibraries?: string[]; +}; + +type DependencyParamsAndroidT = { + sourceDir?: string; + manifestPath?: string; + packageImportPath?: string; + packageInstance?: string; +}; +``` + +#### platforms.ios.project + +Custom path to `.xcodeproj`. + +#### platforms.ios.podspecPath + +Custom path to `.podspec` file to use when auto-linking. Example: `node_modules/react-native-module/ios/module.podspec`. + +#### platforms.ios.sharedLibraries + +An array of shared iOS libraries to link with the dependency. E.g. `libc++`. This is mostly a requirement of the native code that a dependency ships with. + +#### platforms.android.sourceDir + +Path to a folder with source files. + +#### platforms.android.manifestPath + +Path to a custom `AndroidManifest.xml` + +#### platforms.android.packageImportPath + +Custom package import. For example: `import com.acme.AwesomePackage;`. + +#### platforms.android.packageInstance + +Custom syntax to instantiate a package. By default, it's a `new AwesomePackage()`. It can be useful when your package requires additional arguments while initializing. + +For settings applicable on other platforms, please consult their respective documentation. + +### assets + +An array of assets folders to glob for files to link. + +### hooks + +A map where key is the name of a hook and value is the path to a file to execute. + +For example, `link` command supports `prelink` and `postlink` hooks to run before and after linking is done. + +These are the only ones supported by CLI at the moment. Depending on the packages used in your project, you may find other hooks supported to. + +> Note: This has nothing to do with React Hooks. + +## Migrating from `rnpm` configuration + +The changes are mostly cosmetic so the migration should be pretty straight-forward. + +> Note: We read `rnpm` configuration to remain backwards-compatible. Dependency maintainers should update their configuration in the nearest future. + +### Changing the configuration + +Properties were renamed. Look at the following example for the differences. + +```json +{ + "rnpm": { + "ios": {}, + "android": {}, + "assets": ["./path-to-assets"], + "hooks": { + "prelink": "./path-to-a-prelink-hook" + } + } +} +``` + +to a `react-native.config.js` + +```js +module.exports = { + dependency: { + platforms: { + ios: {}, + android: {}, + }, + assets: ['./path-to-assets'], + hooks: { + prelink: './path-to-a-prelink-hook', + }, + }, +}; +``` + +### Asking for params while linking has been removed + +If your library needs it, do not upgrade over to the new config format. + +If you want to ask users for additional settings, consider setting a custom `postlink` hook, just like [`react-native-code-push`](https://github.com/Microsoft/react-native-code-push/blob/master/package.json#L53). diff --git a/docs/init.md b/docs/init.md new file mode 100644 index 0000000000..74971ac580 --- /dev/null +++ b/docs/init.md @@ -0,0 +1,83 @@ +# Initializing new project + +There are couple of ways to initialize new React Native projects. + +### For `react-native@0.60.0` or greater + +#### Using `npx` utility: + +```sh +npx react-native init ProjectName +``` + +> Note: If you have both `yarn` and `npm` installed on your machine, React Native CLI will always try to use `yarn`, so even if you use `npx` utility, only `react-native` executable will be installed using `npm` and the rest of the work will be delegated to `yarn`. You can force usage of `npm` adding `--npm` flag to the command. + +> Note: for Yarn users, `yarn dlx` command similar to `npx` will be featured in Yarn 2.0: https://github.com/yarnpkg/berry/pull/40 so we’ll be able to use it in a similar fashion. + +#### Installing `react-native` and invoking `init` command: + +```sh +yarn init && yarn add react-native && yarn react-native init ProjectName +``` + +#### Initializing project with custom version of `react-native`: + +```sh +# This will use the latest init command but will install react-native@VERSION and use its template +npx react-native init ProjectName --version ${VERSION} + +# This will use init command from react-native@VERSION +npx react-native@${VERSION} init ProjectName +``` + +#### Initializing project with custom template. + +In following examples `TEMPLATE_NAME` can be either: + +- Full package name, eg. `react-native-template-typescript`. +- Absolute path to directory containing template, eg. `file:///Users/username/project/some-template`. +- Absolute path to a tarball created using `npm pack`. + +```sh +# This will initialize new project using template from TEMPLATE_NAME package +npx react-native init ProjectName --template ${TEMPLATE_NAME} + +# This will initialize new project using init command from react-native@VERSION but will use TEMPLATE_NAME custom template +npx react-native@${VERSION} init ProjectName --template ${TEMPLATE_NAME} +``` + +You can force usage of `npm` if you have both `yarn` and `npm` installed on your machine: + +```sh +npx react-native init ProjectName --npm +``` + +### For older `react-native` versions + +Using legacy `react-native-cli` package: + +```sh +yarn global add react-native-cli +react-native init ProjectName +``` + +> Note: It is not recommended, but you can also use legacy `react-native-cli` package to initialize projects using latest `react-native` versions. + +# Creating custom template + +Every custom template needs to have configuration file called `template.config.js` in the root of the project: + +```js +module.exports = { + // Placeholder name that will be replaced in package.json, index.json, android/, ios/ for a project name. + placeholderName: 'ProjectName', + + // Directory with the template which will be copied and processed by React Native CLI. Template directory should have package.json with all dependencies specified, including `react-native`. + templateDir: './template', + + // Path to script, which will be executed after initialization process, but before installing all the dependencies specified in the template. This script runs as a shell script but you can change that (e.g. to Node) by using a shebang (see example custom template). + postInitScript: './script.js', +}; +``` + +You can find example custom template [here](https://github.com/Esemesek/react-native-new-template). diff --git a/docs/platforms.md b/docs/platforms.md new file mode 100644 index 0000000000..8f85fbbd93 --- /dev/null +++ b/docs/platforms.md @@ -0,0 +1,259 @@ +# Platforms + +A platform is a React Native package that enables writing and shipping React Native applications to a new target. + +For example, React Native Windows is a platform, because it allows to run React Native apps on Windows. At the same time, React Native itself is also a platform - it allows to run React Native apps on Android, iOS and tvOS. + +Each platform can have an additional configuration for the CLI to enable bundling apps and linking packages for targets it provides. + +## How does it work? + +A platform can define the following `react-native.config.js` at the root: + +```js +const ios = require('@react-native-community/cli-platform-ios'); +const android = require('@react-native-community/cli-platform-android'); + +module.exports = { + platforms: { + ios: { + linkConfig: ios.linkConfig, + projectConfig: ios.projectConfig, + dependencyConfig: ios.dependencyConfig, + }, + android: { + linkConfig: android.linkConfig, + projectConfig: android.projectConfig, + dependencyConfig: android.dependencyConfig, + }, + }, +}; +``` + +> The above config adds support for linking Android and iOS dependencies by the CLI as well as bundling code for these platforms. This config can be found in [React Native repository](https://github.com/facebook/react-native/blob/0.60-stable/react-native.config.js) from 0.60 version on. + +At the startup, React Native CLI reads configuration from all dependencies listed in `package.json` and reduces them into a single configuration. + +At the end, a map of available platforms is passed to the bundler (Metro) to make it aware of the platforms available. This allows APIs such as `Platform.select` and requiring files with platform extensions to work properly. + +## Platform interface + +```ts +type PlatformConfig = { + projectConfig: (string, ProjectParams) => ?ProjectConfig, + dependencyConfig: (string, ProjectParams) => ?DependencyConfig, + linkConfig: () => { + isInstalled: (ProjectConfig, string, DependencyConfig) => boolean, + register: (string, DependencyConfig, Object, ProjectConfig) => void, + unregister: ( + string, + DependencyConfig, + ProjectConfig, + Array, + ) => void, + copyAssets: (string[], ProjectConfig) => void, + unlinkAssets: (string[], ProjectConfig) => void, + }, +}; +``` + +### projectConfig + +Returns a project configuration for a given platform or `null`, when no project found. This is later used inside `linkConfig` to perform linking and unlinking. + +First argument is a root folder where the project is located. + +Second argument is everything that users defined under: + +```js +module.exports = { + project: { + [yourPlatformKey]: {}, + }, +}; +``` + +> Note: You may find this useful in order to alter the default behavior of your function. For example, on iOS, we find an `.xcodeproj` by globbing the project files and taking the first match. There's a possibility we pick the wrong one in case the project has multiple `.xcodeproj` files. In order to support this use-case, we have allowed users to define an exact path to an iOS project in order to overwrite our `glob` mechanism. + +On Android and iOS, this function returns: + +```ts +type ProjectConfigIOST = { + sourceDir: string; + folder: string; + pbxprojPath: string; + podfile: null; + podspecPath: null; + projectPath: string; + projectName: string; + libraryFolder: string; + sharedLibraries: Array; + plist: Array; +}; + +type ProjectConfigAndroidT = { + sourceDir: string; + isFlat: boolean; + folder: string; + stringsPath: string; + manifestPath: string; + buildGradlePath: string; + settingsGradlePath: string; + assetsPath: string; + mainFilePath: string; + packageName: string; +}; +``` + +We suggest performing all side-effects inside this function (such as resolving paths to native files) and making `linkConfig` functions pure, operating on provided data. + +### dependencyConfig + +Similar to [`projectConfig`](#projectconfig) above, but for a dependency of a project. + +First argument is a path to a root folder of a dependency. + +Second argument is everything that dependency authors defined under: + +```js +module.exports = { + dependency: { + [yourPlatformKey]: {}, + }, +}; +``` + +On Android and iOS, this function returns: + +```ts +type DependencyConfigIOST = ProjectConfigIOST; + +type DependencyConfigAndroidT = { + sourceDir: string; + folder: string; + packageImportPath: string; + packageInstance: string; +}; +``` + +### linkConfig + +Returns an object with utilities that are run by the CLI while linking. + +> Note: The following is deprecated and will stop working in the future. Consider providing a [`autolinking`](./autolinking.md) support. + +#### linkConfig.isInstalled + +Returns true if a library is already linked to a given project. False otherwise. + +#### linkConfig.register + +Performs platform-specific steps in order to link a library. + +#### linkConfig.unregister + +Performs platform-specific steps in order to unlink a library. + +#### linkConfig.copyAssets + +Performs platform-specific steps in order to copy assets of a library to a project. + +#### linkConfig.unlinkAssets + +Performs platform-specific steps in order to unlink assets of a library from a project. + +## Migrating from `rnpm` configuration + +The changes are mostly cosmetic so the migration should be pretty straight-forward. + +### Changing the configuration for a platform + +A `platform` property would need to be renamed to `platforms`. `haste` is no longer supported - we are able to infer that automatically. + +For example: + +```json +{ + "rnpm": { + "haste": { + "platforms": ["windows"], + "providesModuleNodeModules": ["react-native-windows"] + }, + "platform": "./local-cli/platform.js" + } +} +``` + +to `react-native.config.js` + +```js +module.exports = { + platforms: { + windows: require('./local-cli/platform.js').windows, + }, +}; +``` + +> The above configuration is taken from `react-native-windows` and adds support for `windows` platform. + +### Changing platform configuration for a [`dependency`](./dependencies.md) + +Platform keys are now under `dependency.platforms`. + +For example: + +```json +{ + "rnpm": { + "ios": { + "project": "PathToCustomProject.xcodeproj" + } + } +} +``` + +to `react-native.config.js` + +```js +module.exports = { + dependency: { + platforms: { + ios: { + project: 'PathToCustomProject.xcodeproj', + }, + }, + }, +}; +``` + +> The above is a configuration of a dependency that explicitly sets a path to `.xcodeproj`. + +### Changing platform configuration for a [`project`](./projects.md) + +Platform keys are now under `project.platforms`. + +For example: + +```json +{ + "rnpm": { + "ios": { + "project": "PathToCustomProject.xcodeproj" + } + } +} +``` + +to `react-native.config.js` + +```js +module.exports = { + project: { + ios: { + project: 'PathToCustomProject.xcodeproj', + }, + }, +}; +``` + +> The above is a configuration of a project that explicitly sets its main `.xcodeproj` project. diff --git a/docs/plugins.md b/docs/plugins.md new file mode 100644 index 0000000000..82d988b59c --- /dev/null +++ b/docs/plugins.md @@ -0,0 +1,154 @@ +# Plugins + +Plugin is a JavaScript package that extends built-in React Native CLI features. It can provide an array of additional commands to run or platforms to target. + +For example, `react-native-windows` package is a plugin that provides `react-native run-windows` command and `windows` platform. + +Details of this particular integration as well as how to provide an additional platform for React Native were described in a [`dedicated section`](./platforms.md) about platforms. + +## How does it work? + +Except for React Native dependencies, where configuration is implicit, each package needs to have a `react-native.config.js` at the root folder in order to be discovered by the CLI as a plugin. + +```js +module.exports = { + commands: [ + { + name: 'foo-command', + func: () => console.log('It worked'), + }, + ], +}; +``` + +> Above is an example of a plugin that exports a command named `foo-command` that can be executed with `react-native foo-command` and logs "It worked" and exits. + +At the startup, React Native CLI reads configuration from all dependencies listed in `package.json` and reduces them into a single configuration. + +At the end, an array of commands concatenated from all plugins is passed on to the CLI to be loaded after built-in commands. + +## Command interface + +```ts +type Command = { + name: string, + description?: string, + func: (argv: Array, config: ConfigT, args: Object) => ?Promise, + options?: Array<{ + name: string, + description?: string, + parse?: (val: string) => any, + default?: + | string + | boolean + | number + | ((config: ConfigT) => string | boolean | number), + }>, + examples?: Array<{ + desc: string, + cmd: string, + }>, +}; +``` + +> Note: `ConfigT` is described in [`configuration`](./configuration.md) section + +#### `name` + +A name that will be used in order to run the command. + +Note: If you want your command to accept additional arguments, make sure to include them in the name. + +For example, `my-command ` will require an argument to be provided and will throw a validation error otherwise. Alternatively, `my-command [argument]` will accept an argument, but will not throw when run without it. In that case, make sure to check for its presence. + +#### `func` + +Function that will be run when this command is executed. Receives an array of arguments, in order they were provided, a config object (see [`configuration` section](./configuration.md)) and options, that were passed to your command. + +You can return a Promise if your command is async. + +All errors are handled by the built-in logger. Prefer throwing instead of implementing your own logging mechanism. + +#### `options` + +An array of options that your command accepts. + +##### `options.name` + +Name of the option. + +For example, a `--reset-cache` option will result in a `resetCache: true` or `resetCache: false` present in the `options` object - passed to a command function as a last argument. + +Just like with a [command name](#name), your option can require a value (e.g. `--port `) or accept an optional one (e.g. `--host [host]`). In this case, you may find [`default`](#optionsdefault) value useful. + +##### `options.description` + +Optional description of your option. When provided, will be used to output a better help information. + +##### `options.parse` + +Parsing function that can be used to transform a raw (string) option as passed by the user into a format expected by your function. + +##### `options.default` + +Default value for the option when not provided. Can be either a primitive value or a function, that receives a configuration and returns a primitive. + +Useful when you want to use project settings as default value for your option. + +#### `examples` + +An array of example usage of the command to be printed to the user. + +##### `examples.desc` + +String that describes this particular usage. + +##### `examples.cmd` + +A command with arguments and options (if applicable) that can be run in order to achieve the desired goal. + +## Migrating from `rnpm` configuration + +The changes are mostly cosmetic so the migration should be pretty straight-forward. + +### Changing the configuration + +A `plugin` property should be renamed to `commands`. + +For example, the following `rnpm` configuration inside `package.json`: + +```json +{ + "rnpm": { + "plugin": "./path-to-commands.js" + } +} +``` + +should be moved to a `react-native.config.js`: + +```js +module.exports = { + commands: require('./path-to-commands.js'), +}; +``` + +provided that `./path-to-commands.js` returns an array of commands. + +### Renaming command options + +If your command accepts options, rename `command` property of each of them to `name`. + +```diff + module.exports = { + name: 'foo', + func: () => console.log('My work'), + options: [ + { +- command: '--reset-cache, --resetCache', ++ name: '--reset-cache, --resetCache', + description: 'Removes cached files', + } + ] + } +``` diff --git a/docs/projects.md b/docs/projects.md new file mode 100644 index 0000000000..abc704497b --- /dev/null +++ b/docs/projects.md @@ -0,0 +1,167 @@ +# Project + +A project is an app that contains React code and has a dependency on `react-native`. + +Projects can provide additional properties to alter the CLI behavior, such as custom location of React Native files (this is useful when running RNTester from source) or a non-standard location of a project (useful when working in a brownfield app). + +## How does it work? + +A project can define a `react-native.config.js` at the root with custom configuration to be picked up by the CLI. + +For example, below configuration informs CLI of the additional assets to link and about a custom project location. + +```js +module.exports = { + project: { + ios: { + project: './CustomProject.xcodeproj', + }, + }, + assets: ['./assets'], +}; +``` + +You can check all available options below. + +## Project interface + +```ts +type ProjectConfigT = { + reactNativePath: ?string, + project: { + android?: ProjectParamsAndroidT, + ios?: ProjectParamsIOST, + [key: string]: any, + }, + assets: string[], + platforms: PlatformT, + dependencies: { + [key: string]: { + name: string, + root: string, + platforms: { + [key: string]: PlatformSettingsT + }, + assets: string[], + hooks: { + [key: string]: string + } + }, + }, + commands: CommandT[] +}; +``` + +### reactNativePath + +A custom path to React Native, in case `require('react-native')` would throw. Useful when running +React Native from a (custom) source. + +### project + +A map of specific settings that can be set per platform. The exact shape is always defined by the package that provides given platform. + +In most cases, as a React Native developer, you should not need to define any of these. + +The following settings are available on iOS and Android: + +```ts +type ProjectParamsAndroidT = { + sourceDir?: string; + manifestPath?: string; + packageName?: string; + packageFolder?: string; + mainFilePath?: string; + stringsPath?: string; + settingsGradlePath?: string; + assetsPath?: string; + buildGradlePath?: string; + packageName?: string; +}; + +type ProjectParamsIOST = { + project?: string; + podspecPath?: string; + sharedLibraries?: string[]; + libraryFolder?: string; + plist: any[]; +}; +``` + +### assets + +An array of folders to check for project assets + +### platforms + +A object with platforms defined inside a project. You can check the format and options available [`here`](platforms.md#platform-interface) + +### commands + +An array of commands defined inside a project. You can check the format and options available [`here`](plugins.md#command-interface) + +### dependencies + +Dependencies is a map where key is the name of the dependency and value is an object that can override any of the resolved settings for a particular package. + +For example, you could set: + +```js +module.exports = { + dependencies: { + 'react-native-webview': { + platforms: { + ios: null, + }, + }, + }, +}; +``` + +in order to disable linking of React Native WebView on iOS. + +Another use-case would be supporting local libraries that are not discoverable for autolinking, since they're not part of your `dependencies` or `devDependencies`: + +```js +module.exports = { + dependencies: { + 'local-rn-library': { + root: '/root/libraries', + }, + }, +}; +``` + +The object provided here is deep merged with the dependency config. Check [`projectConfig`](platforms.md#projectconfig) and [`dependencyConfig`](platforms.md#dependencyConfig) return values for a full list of properties that you can override. + +> Note: This is an advanced feature and you should not need to use it mos of the time. + +## Migrating from `rnpm` configuration + +The changes are mostly cosmetic so the migration should be pretty straight-forward. + +### Changing the configuration + +Properties `ios` and `android` were moved under `project`. Take a look at the following example for the differences. + +```json +{ + "rnpm": { + "ios": {}, + "android": {}, + "assets": ["./path-to-assets"] + } +} +``` + +to a `react-native.config.js` + +```js +module.exports = { + project: { + ios: {}, + android: {}, + }, + assets: ['./path-to-assets'], +}; +``` diff --git a/flow-typed/npm/execa_v1.0.x.js b/flow-typed/npm/execa_v1.0.x.js new file mode 100644 index 0000000000..d49b7a7b05 --- /dev/null +++ b/flow-typed/npm/execa_v1.0.x.js @@ -0,0 +1,103 @@ +// flow-typed signature: 613ee1ec7d728b6a312fcff21a7b2669 +// flow-typed version: 3163f7a6e3/execa_v1.0.x/flow_>=v0.75.x + +declare module 'execa' { + + declare type StdIoOption = + | 'pipe' + | 'ipc' + | 'ignore' + | 'inherit' + | stream$Stream + | number; + + declare type CommonOptions = {| + argv0?: string, + cleanup?: boolean, + cwd?: string, + detached?: boolean, + encoding?: string, + env?: {[string]: string}, + extendEnv?: boolean, + gid?: number, + killSignal?: string | number, + localDir?: string, + maxBuffer?: number, + preferLocal?: boolean, + reject?: boolean, + shell?: boolean | string, + stderr?: ?StdIoOption, + stdin?: ?StdIoOption, + stdio?: 'pipe' | 'ignore' | 'inherit' | $ReadOnlyArray, + stdout?: ?StdIoOption, + stripEof?: boolean, + timeout?: number, + uid?: number, + windowsVerbatimArguments?: boolean, + |}; + + declare type SyncOptions = {| + ...CommonOptions, + input?: string | Buffer, + |}; + + declare type Options = {| + ...CommonOptions, + input?: string | Buffer | stream$Readable, + |}; + + declare type SyncResult = {| + stdout: string, + stderr: string, + code: number, + failed: boolean, + signal: ?string, + cmd: string, + timedOut: boolean, + |}; + + declare type Result = {| + ...SyncResult, + killed: boolean, + |}; + + declare interface ThenableChildProcess extends child_process$ChildProcess { + then( + onfulfilled?: ?((value: Result) => R | Promise), + onrejected?: ?((reason: ExecaError) => E | Promise), + ): Promise; + + catch( + onrejected?: ?((reason: ExecaError) => E | Promise) + ): Promise; + } + + declare interface ExecaError extends ErrnoError { + stdout: string; + stderr: string; + failed: boolean; + signal: ?string; + cmd: string; + timedOut: boolean; + } + + declare interface Execa { + (file: string, args?: $ReadOnlyArray, options?: $ReadOnly): ThenableChildProcess; + (file: string, options?: $ReadOnly): ThenableChildProcess; + + stdout(file: string, args?: $ReadOnlyArray, options?: $ReadOnly): Promise; + stdout(file: string, options?: $ReadOnly): Promise; + + stderr(file: string, args?: $ReadOnlyArray, options?: $ReadOnly): Promise; + stderr(file: string, options?: $ReadOnly): Promise; + + shell(command: string, options?: $ReadOnly): ThenableChildProcess; + + sync(file: string, args?: $ReadOnlyArray, options?: $ReadOnly): SyncResult; + sync(file: string, options?: $ReadOnly): SyncResult; + + shellSync(command: string, options?: $ReadOnly): SyncResult; + } + + declare module.exports: Execa; +} diff --git a/flow-typed/npm/jest_v23.x.x.js b/flow-typed/npm/jest_v24.x.x.js similarity index 67% rename from flow-typed/npm/jest_v23.x.x.js rename to flow-typed/npm/jest_v24.x.x.js index 95835f5f2c..1c1d6d9a28 100644 --- a/flow-typed/npm/jest_v23.x.x.js +++ b/flow-typed/npm/jest_v24.x.x.js @@ -1,5 +1,5 @@ -// flow-typed signature: 78c200acffbcc16bba9478f5396c3a00 -// flow-typed version: b2980740dd/jest_v23.x.x/flow_>=v0.39.x +// flow-typed signature: 833075a5cefc49eb523160a5fca9d8b6 +// flow-typed version: 325925f1b7/jest_v24.x.x/flow_>=v0.39.x type JestMockFn, TReturn> = { (...args: TArguments): TReturn, @@ -22,7 +22,7 @@ type JestMockFn, TReturn> = { * An array that contains all the object results that have been * returned by this mock function call */ - results: Array<{ isThrow: boolean, value: TReturn }> + results: Array<{ isThrow: boolean, value: TReturn }>, }, /** * Resets all information stored in the mockFn.mock.calls and @@ -84,7 +84,9 @@ type JestMockFn, TReturn> = { /** * Sugar for jest.fn().mockImplementationOnce(() => Promise.resolve(value)) */ - mockResolvedValueOnce(value: TReturn): JestMockFn>, + mockResolvedValueOnce( + value: TReturn + ): JestMockFn>, /** * Sugar for jest.fn().mockImplementation(() => Promise.reject(value)) */ @@ -92,14 +94,14 @@ type JestMockFn, TReturn> = { /** * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) */ - mockRejectedValueOnce(value: TReturn): JestMockFn> + mockRejectedValueOnce(value: TReturn): JestMockFn>, }; type JestAsymmetricEqualityType = { /** * A custom Jasmine equality tester */ - asymmetricMatch(value: mixed): boolean + asymmetricMatch(value: mixed): boolean, }; type JestCallsType = { @@ -109,24 +111,25 @@ type JestCallsType = { count(): number, first(): mixed, mostRecent(): mixed, - reset(): void + reset(): void, }; type JestClockType = { install(): void, mockDate(date: Date): void, tick(milliseconds?: number): void, - uninstall(): void + uninstall(): void, }; type JestMatcherResult = { message?: string | (() => string), - pass: boolean + pass: boolean, }; -type JestMatcher = (actual: any, expected: any) => - | JestMatcherResult - | Promise; +type JestMatcher = ( + actual: any, + expected: any +) => JestMatcherResult | Promise; type JestPromiseType = { /** @@ -138,7 +141,7 @@ type JestPromiseType = { * Use resolves to unwrap the value of a fulfilled promise so any other * matcher can be chained. If the promise is rejected the assertion fails. */ - resolves: JestExpectType + resolves: JestExpectType, }; /** @@ -158,10 +161,10 @@ type JestStyledComponentsMatcherValue = | typeof undefined; type JestStyledComponentsMatcherOptions = { - media?: string; - modifier?: string; - supports?: string; -} + media?: string, + modifier?: string, + supports?: string, +}; type JestStyledComponentsMatchersType = { toHaveStyleRule( @@ -182,24 +185,27 @@ type EnzymeMatchersType = { toBeChecked(): void, toBeDisabled(): void, toBeEmptyRender(): void, - toContainMatchingElement(selector: string): void; - toContainMatchingElements(n: number, selector: string): void; - toContainExactlyOneMatchingElement(selector: string): void; + toContainMatchingElement(selector: string): void, + toContainMatchingElements(n: number, selector: string): void, + toContainExactlyOneMatchingElement(selector: string): void, toContainReact(element: React$Element): void, toExist(): void, toHaveClassName(className: string): void, toHaveHTML(html: string): void, - toHaveProp: ((propKey: string, propValue?: any) => void) & ((props: Object) => void), + toHaveProp: ((propKey: string, propValue?: any) => void) & + ((props: {}) => void), toHaveRef(refName: string): void, - toHaveState: ((stateKey: string, stateValue?: any) => void) & ((state: Object) => void), - toHaveStyle: ((styleKey: string, styleValue?: any) => void) & ((style: Object) => void), + toHaveState: ((stateKey: string, stateValue?: any) => void) & + ((state: {}) => void), + toHaveStyle: ((styleKey: string, styleValue?: any) => void) & + ((style: {}) => void), toHaveTagName(tagName: string): void, toHaveText(text: string): void, toHaveValue(value: any): void, toIncludeText(text: string): void, toMatchElement( element: React$Element, - options?: {| ignoreProps?: boolean, verbose?: boolean |}, + options?: {| ignoreProps?: boolean, verbose?: boolean |} ): void, toMatchSelector(selector: string): void, // 7.x @@ -219,7 +225,10 @@ type DomTestingLibraryType = { toHaveFocus(): void, toHaveFormValues(expectedValues: { [name: string]: any }): void, toHaveStyle(css: string): void, - toHaveTextContent(content: string | RegExp, options?: { normalizeWhitespace: boolean }): void, + toHaveTextContent( + content: string | RegExp, + options?: { normalizeWhitespace: boolean } + ): void, toBeInTheDOM(): void, }; @@ -235,7 +244,7 @@ type JestJQueryMatchersType = { toHaveText(text: string | RegExp): void, toHaveData(key: string, val?: any): void, toHaveValue(val: any): void, - toHaveCss(css: {[key: string]: any}): void, + toHaveCss(css: { [key: string]: any }): void, toBeChecked(): void, toBeDisabled(): void, toBeEmpty(): void, @@ -246,409 +255,407 @@ type JestJQueryMatchersType = { toBeInDom(): void, toBeMatchedBy(sel: string): void, toHaveDescendant(sel: string): void, - toHaveDescendantWithText(sel: string, text: string | RegExp): void + toHaveDescendantWithText(sel: string, text: string | RegExp): void, }; - // Jest Extended Matchers: https://github.com/jest-community/jest-extended type JestExtendedMatchersType = { /** - * Note: Currently unimplemented - * Passing assertion - * - * @param {String} message - */ + * Note: Currently unimplemented + * Passing assertion + * + * @param {String} message + */ // pass(message: string): void; - /** - * Note: Currently unimplemented - * Failing assertion - * - * @param {String} message - */ + /** + * Note: Currently unimplemented + * Failing assertion + * + * @param {String} message + */ // fail(message: string): void; - /** - * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. - */ - toBeEmpty(): void; + /** + * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. + */ + toBeEmpty(): void, - /** - * Use .toBeOneOf when checking if a value is a member of a given Array. - * @param {Array.<*>} members - */ - toBeOneOf(members: any[]): void; + /** + * Use .toBeOneOf when checking if a value is a member of a given Array. + * @param {Array.<*>} members + */ + toBeOneOf(members: any[]): void, - /** - * Use `.toBeNil` when checking a value is `null` or `undefined`. - */ - toBeNil(): void; + /** + * Use `.toBeNil` when checking a value is `null` or `undefined`. + */ + toBeNil(): void, - /** - * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. - * @param {Function} predicate - */ - toSatisfy(predicate: (n: any) => boolean): void; + /** + * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. + * @param {Function} predicate + */ + toSatisfy(predicate: (n: any) => boolean): void, - /** - * Use `.toBeArray` when checking if a value is an `Array`. - */ - toBeArray(): void; + /** + * Use `.toBeArray` when checking if a value is an `Array`. + */ + toBeArray(): void, - /** - * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. - * @param {Number} x - */ - toBeArrayOfSize(x: number): void; + /** + * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. + * @param {Number} x + */ + toBeArrayOfSize(x: number): void, - /** - * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. - * @param {Array.<*>} members - */ - toIncludeAllMembers(members: any[]): void; + /** + * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. + * @param {Array.<*>} members + */ + toIncludeAllMembers(members: any[]): void, - /** - * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. - * @param {Array.<*>} members - */ - toIncludeAnyMembers(members: any[]): void; + /** + * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. + * @param {Array.<*>} members + */ + toIncludeAnyMembers(members: any[]): void, - /** - * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. - * @param {Function} predicate - */ - toSatisfyAll(predicate: (n: any) => boolean): void; + /** + * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. + * @param {Function} predicate + */ + toSatisfyAll(predicate: (n: any) => boolean): void, - /** - * Use `.toBeBoolean` when checking if a value is a `Boolean`. - */ - toBeBoolean(): void; + /** + * Use `.toBeBoolean` when checking if a value is a `Boolean`. + */ + toBeBoolean(): void, - /** - * Use `.toBeTrue` when checking a value is equal (===) to `true`. - */ - toBeTrue(): void; + /** + * Use `.toBeTrue` when checking a value is equal (===) to `true`. + */ + toBeTrue(): void, - /** - * Use `.toBeFalse` when checking a value is equal (===) to `false`. - */ - toBeFalse(): void; + /** + * Use `.toBeFalse` when checking a value is equal (===) to `false`. + */ + toBeFalse(): void, - /** - * Use .toBeDate when checking if a value is a Date. - */ - toBeDate(): void; + /** + * Use .toBeDate when checking if a value is a Date. + */ + toBeDate(): void, - /** - * Use `.toBeFunction` when checking if a value is a `Function`. - */ - toBeFunction(): void; + /** + * Use `.toBeFunction` when checking if a value is a `Function`. + */ + toBeFunction(): void, - /** - * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. - * - * Note: Required Jest version >22 - * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same - * - * @param {Mock} mock - */ - toHaveBeenCalledBefore(mock: JestMockFn): void; + /** + * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. + * + * Note: Required Jest version >22 + * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same + * + * @param {Mock} mock + */ + toHaveBeenCalledBefore(mock: JestMockFn): void, - /** - * Use `.toBeNumber` when checking if a value is a `Number`. - */ - toBeNumber(): void; + /** + * Use `.toBeNumber` when checking if a value is a `Number`. + */ + toBeNumber(): void, - /** - * Use `.toBeNaN` when checking a value is `NaN`. - */ - toBeNaN(): void; + /** + * Use `.toBeNaN` when checking a value is `NaN`. + */ + toBeNaN(): void, - /** - * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. - */ - toBeFinite(): void; + /** + * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. + */ + toBeFinite(): void, - /** - * Use `.toBePositive` when checking if a value is a positive `Number`. - */ - toBePositive(): void; + /** + * Use `.toBePositive` when checking if a value is a positive `Number`. + */ + toBePositive(): void, - /** - * Use `.toBeNegative` when checking if a value is a negative `Number`. - */ - toBeNegative(): void; + /** + * Use `.toBeNegative` when checking if a value is a negative `Number`. + */ + toBeNegative(): void, - /** - * Use `.toBeEven` when checking if a value is an even `Number`. - */ - toBeEven(): void; + /** + * Use `.toBeEven` when checking if a value is an even `Number`. + */ + toBeEven(): void, - /** - * Use `.toBeOdd` when checking if a value is an odd `Number`. - */ - toBeOdd(): void; + /** + * Use `.toBeOdd` when checking if a value is an odd `Number`. + */ + toBeOdd(): void, - /** - * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). - * - * @param {Number} start - * @param {Number} end - */ - toBeWithin(start: number, end: number): void; + /** + * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). + * + * @param {Number} start + * @param {Number} end + */ + toBeWithin(start: number, end: number): void, - /** - * Use `.toBeObject` when checking if a value is an `Object`. - */ - toBeObject(): void; + /** + * Use `.toBeObject` when checking if a value is an `Object`. + */ + toBeObject(): void, - /** - * Use `.toContainKey` when checking if an object contains the provided key. - * - * @param {String} key - */ - toContainKey(key: string): void; + /** + * Use `.toContainKey` when checking if an object contains the provided key. + * + * @param {String} key + */ + toContainKey(key: string): void, - /** - * Use `.toContainKeys` when checking if an object has all of the provided keys. - * - * @param {Array.} keys - */ - toContainKeys(keys: string[]): void; + /** + * Use `.toContainKeys` when checking if an object has all of the provided keys. + * + * @param {Array.} keys + */ + toContainKeys(keys: string[]): void, - /** - * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. - * - * @param {Array.} keys - */ - toContainAllKeys(keys: string[]): void; + /** + * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. + * + * @param {Array.} keys + */ + toContainAllKeys(keys: string[]): void, - /** - * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. - * - * @param {Array.} keys - */ - toContainAnyKeys(keys: string[]): void; + /** + * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. + * + * @param {Array.} keys + */ + toContainAnyKeys(keys: string[]): void, - /** - * Use `.toContainValue` when checking if an object contains the provided value. - * - * @param {*} value - */ - toContainValue(value: any): void; + /** + * Use `.toContainValue` when checking if an object contains the provided value. + * + * @param {*} value + */ + toContainValue(value: any): void, - /** - * Use `.toContainValues` when checking if an object contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainValues(values: any[]): void; + /** + * Use `.toContainValues` when checking if an object contains all of the provided values. + * + * @param {Array.<*>} values + */ + toContainValues(values: any[]): void, - /** - * Use `.toContainAllValues` when checking if an object only contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainAllValues(values: any[]): void; + /** + * Use `.toContainAllValues` when checking if an object only contains all of the provided values. + * + * @param {Array.<*>} values + */ + toContainAllValues(values: any[]): void, - /** - * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. - * - * @param {Array.<*>} values - */ - toContainAnyValues(values: any[]): void; + /** + * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. + * + * @param {Array.<*>} values + */ + toContainAnyValues(values: any[]): void, - /** - * Use `.toContainEntry` when checking if an object contains the provided entry. - * - * @param {Array.} entry - */ - toContainEntry(entry: [string, string]): void; + /** + * Use `.toContainEntry` when checking if an object contains the provided entry. + * + * @param {Array.} entry + */ + toContainEntry(entry: [string, string]): void, - /** - * Use `.toContainEntries` when checking if an object contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainEntries(entries: [string, string][]): void; + /** + * Use `.toContainEntries` when checking if an object contains all of the provided entries. + * + * @param {Array.>} entries + */ + toContainEntries(entries: [string, string][]): void, - /** - * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainAllEntries(entries: [string, string][]): void; + /** + * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. + * + * @param {Array.>} entries + */ + toContainAllEntries(entries: [string, string][]): void, - /** - * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. - * - * @param {Array.>} entries - */ - toContainAnyEntries(entries: [string, string][]): void; + /** + * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. + * + * @param {Array.>} entries + */ + toContainAnyEntries(entries: [string, string][]): void, - /** - * Use `.toBeExtensible` when checking if an object is extensible. - */ - toBeExtensible(): void; + /** + * Use `.toBeExtensible` when checking if an object is extensible. + */ + toBeExtensible(): void, - /** - * Use `.toBeFrozen` when checking if an object is frozen. - */ - toBeFrozen(): void; + /** + * Use `.toBeFrozen` when checking if an object is frozen. + */ + toBeFrozen(): void, - /** - * Use `.toBeSealed` when checking if an object is sealed. - */ - toBeSealed(): void; + /** + * Use `.toBeSealed` when checking if an object is sealed. + */ + toBeSealed(): void, - /** - * Use `.toBeString` when checking if a value is a `String`. - */ - toBeString(): void; + /** + * Use `.toBeString` when checking if a value is a `String`. + */ + toBeString(): void, - /** - * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. - * - * @param {String} string - */ - toEqualCaseInsensitive(string: string): void; + /** + * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. + * + * @param {String} string + */ + toEqualCaseInsensitive(string: string): void, - /** - * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. - * - * @param {String} prefix - */ - toStartWith(prefix: string): void; + /** + * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. + * + * @param {String} prefix + */ + toStartWith(prefix: string): void, - /** - * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. - * - * @param {String} suffix - */ - toEndWith(suffix: string): void; + /** + * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. + * + * @param {String} suffix + */ + toEndWith(suffix: string): void, - /** - * Use `.toInclude` when checking if a `String` includes the given `String` substring. - * - * @param {String} substring - */ - toInclude(substring: string): void; + /** + * Use `.toInclude` when checking if a `String` includes the given `String` substring. + * + * @param {String} substring + */ + toInclude(substring: string): void, - /** - * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. - * - * @param {String} substring - * @param {Number} times - */ - toIncludeRepeated(substring: string, times: number): void; + /** + * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. + * + * @param {String} substring + * @param {Number} times + */ + toIncludeRepeated(substring: string, times: number): void, - /** - * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. - * - * @param {Array.} substring - */ - toIncludeMultiple(substring: string[]): void; + /** + * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. + * + * @param {Array.} substring + */ + toIncludeMultiple(substring: string[]): void, }; interface JestExpectType { - not: - & JestExpectType - & EnzymeMatchersType - & DomTestingLibraryType - & JestJQueryMatchersType - & JestStyledComponentsMatchersType - & JestExtendedMatchersType, + not: JestExpectType & + EnzymeMatchersType & + DomTestingLibraryType & + JestJQueryMatchersType & + JestStyledComponentsMatchersType & + JestExtendedMatchersType; /** * If you have a mock function, you can use .lastCalledWith to test what * arguments it was last called with. */ - lastCalledWith(...args: Array): void, + lastCalledWith(...args: Array): void; /** * toBe just checks that a value is what you expect. It uses === to check * strict equality. */ - toBe(value: any): void, + toBe(value: any): void; /** * Use .toBeCalledWith to ensure that a mock function was called with * specific arguments. */ - toBeCalledWith(...args: Array): void, + toBeCalledWith(...args: Array): void; /** * Using exact equality with floating point numbers is a bad idea. Rounding * means that intuitive things fail. */ - toBeCloseTo(num: number, delta: any): void, + toBeCloseTo(num: number, delta: any): void; /** * Use .toBeDefined to check that a variable is not undefined. */ - toBeDefined(): void, + toBeDefined(): void; /** * Use .toBeFalsy when you don't care what a value is, you just want to * ensure a value is false in a boolean context. */ - toBeFalsy(): void, + toBeFalsy(): void; /** * To compare floating point numbers, you can use toBeGreaterThan. */ - toBeGreaterThan(number: number): void, + toBeGreaterThan(number: number): void; /** * To compare floating point numbers, you can use toBeGreaterThanOrEqual. */ - toBeGreaterThanOrEqual(number: number): void, + toBeGreaterThanOrEqual(number: number): void; /** * To compare floating point numbers, you can use toBeLessThan. */ - toBeLessThan(number: number): void, + toBeLessThan(number: number): void; /** * To compare floating point numbers, you can use toBeLessThanOrEqual. */ - toBeLessThanOrEqual(number: number): void, + toBeLessThanOrEqual(number: number): void; /** * Use .toBeInstanceOf(Class) to check that an object is an instance of a * class. */ - toBeInstanceOf(cls: Class<*>): void, + toBeInstanceOf(cls: Class<*>): void; /** * .toBeNull() is the same as .toBe(null) but the error messages are a bit * nicer. */ - toBeNull(): void, + toBeNull(): void; /** * Use .toBeTruthy when you don't care what a value is, you just want to * ensure a value is true in a boolean context. */ - toBeTruthy(): void, + toBeTruthy(): void; /** * Use .toBeUndefined to check that a variable is undefined. */ - toBeUndefined(): void, + toBeUndefined(): void; /** * Use .toContain when you want to check that an item is in a list. For * testing the items in the list, this uses ===, a strict equality check. */ - toContain(item: any): void, + toContain(item: any): void; /** * Use .toContainEqual when you want to check that an item is in a list. For * testing the items in the list, this matcher recursively checks the * equality of all fields, rather than checking for object identity. */ - toContainEqual(item: any): void, + toContainEqual(item: any): void; /** * Use .toEqual when you want to check that two objects have the same value. * This matcher recursively checks the equality of all fields, rather than * checking for object identity. */ - toEqual(value: any): void, + toEqual(value: any): void; /** * Use .toHaveBeenCalled to ensure that a mock function got called. */ - toHaveBeenCalled(): void, + toHaveBeenCalled(): void; toBeCalled(): void; /** * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact * number of times. */ - toHaveBeenCalledTimes(number: number): void, + toHaveBeenCalledTimes(number: number): void; toBeCalledTimes(number: number): void; /** * @@ -684,46 +691,46 @@ interface JestExpectType { * Use .toHaveBeenCalledWith to ensure that a mock function was called with * specific arguments. */ - toHaveBeenCalledWith(...args: Array): void, - toBeCalledWith(...args: Array): void, + toHaveBeenCalledWith(...args: Array): void; + toBeCalledWith(...args: Array): void; /** * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called * with specific arguments. */ - toHaveBeenLastCalledWith(...args: Array): void, - lastCalledWith(...args: Array): void, + toHaveBeenLastCalledWith(...args: Array): void; + lastCalledWith(...args: Array): void; /** * Check that an object has a .length property and it is set to a certain * numeric value. */ - toHaveLength(number: number): void, + toHaveLength(number: number): void; /** * */ - toHaveProperty(propPath: string, value?: any): void, + toHaveProperty(propPath: string, value?: any): void; /** * Use .toMatch to check that a string matches a regular expression or string. */ - toMatch(regexpOrString: RegExp | string): void, + toMatch(regexpOrString: RegExp | string): void; /** * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object. */ - toMatchObject(object: Object | Array): void, + toMatchObject(object: Object | Array): void; /** * Use .toStrictEqual to check that a javascript object matches a subset of the properties of an object. */ - toStrictEqual(value: any): void, + toStrictEqual(value: any): void; /** * This ensures that an Object matches the most recent snapshot. */ - toMatchSnapshot(propertyMatchers?: any, name?: string): void, + toMatchSnapshot(propertyMatchers?: any, name?: string): void; /** * This ensures that an Object matches the most recent snapshot. */ - toMatchSnapshot(name: string): void, + toMatchSnapshot(name: string): void; - toMatchInlineSnapshot(snapshot?: string): void, - toMatchInlineSnapshot(propertyMatchers?: any, snapshot?: string): void, + toMatchInlineSnapshot(snapshot?: string): void; + toMatchInlineSnapshot(propertyMatchers?: any, snapshot?: string): void; /** * Use .toThrow to test that a function throws when it is called. * If you want to test that a specific error gets thrown, you can provide an @@ -732,14 +739,14 @@ interface JestExpectType { * * Alias: .toThrowError */ - toThrow(message?: string | Error | Class | RegExp): void, - toThrowError(message?: string | Error | Class | RegExp): void, + toThrow(message?: string | Error | Class | RegExp): void; + toThrowError(message?: string | Error | Class | RegExp): void; /** * Use .toThrowErrorMatchingSnapshot to test that a function throws a error * matching the most recent snapshot when it is called. */ - toThrowErrorMatchingSnapshot(): void, - toThrowErrorMatchingInlineSnapshot(snapshot?: string): void, + toThrowErrorMatchingSnapshot(): void; + toThrowErrorMatchingInlineSnapshot(snapshot?: string): void; } type JestObjectType = { @@ -780,6 +787,10 @@ type JestObjectType = { * Removes any pending timers from the timer system. */ clearAllTimers(): void, + /** + * Returns the number of fake timers still left to run. + */ + getTimerCount(): number, /** * The same as `mock` but not moved to the top of the expectation by * babel-jest. @@ -835,6 +846,14 @@ type JestObjectType = { * useful to isolate modules where local state might conflict between tests. */ resetModules(): JestObjectType, + + /** + * Creates a sandbox registry for the modules that are loaded inside the + * callback function. This is useful to isolate specific modules for every + * test so that local module state doesn't conflict between tests. + */ + isolateModules(fn: () => void): JestObjectType, + /** * Exhausts the micro-task queue (usually interfaced in node via * process.nextTick). @@ -893,16 +912,20 @@ type JestObjectType = { * Creates a mock function similar to jest.fn but also tracks calls to * object[methodName]. */ - spyOn(object: Object, methodName: string, accessType?: "get" | "set"): JestMockFn, + spyOn( + object: Object, + methodName: string, + accessType?: 'get' | 'set' + ): JestMockFn, /** * Set the default timeout interval for tests and before/after hooks in milliseconds. * Note: The default timeout interval is 5 seconds if this method is not called. */ - setTimeout(timeout: number): JestObjectType + setTimeout(timeout: number): JestObjectType, }; type JestSpyType = { - calls: JestCallsType + calls: JestCallsType, }; /** Runs this function after every test inside this context */ @@ -1006,6 +1029,13 @@ declare var it: { timeout?: number ): void, + /** + * Highlight planned tests in the summary output + * + * @param {String} Name of Test to do + */ + todo(name: string): void, + /** * Run the test concurrently * @@ -1088,7 +1118,7 @@ type JestPrettyFormatPlugin = { serialize: JestPrettyFormatPrint, indent: JestPrettyFormatIndent, opts: JestPrettyFormatOptions, - colors: JestPrettyFormatColors, + colors: JestPrettyFormatColors ) => string, test: any => boolean, }; @@ -1098,14 +1128,15 @@ type JestPrettyFormatPlugins = Array; /** The expect function is used every time you want to test a value */ declare var expect: { /** The object that you want to make assertions against */ - (value: any): - & JestExpectType - & JestPromiseType - & EnzymeMatchersType - & DomTestingLibraryType - & JestJQueryMatchersType - & JestStyledComponentsMatchersType - & JestExtendedMatchersType, + ( + value: any + ): JestExpectType & + JestPromiseType & + EnzymeMatchersType & + DomTestingLibraryType & + JestJQueryMatchersType & + JestStyledComponentsMatchersType & + JestExtendedMatchersType, /** Add additional Jasmine matchers to Jest's roster */ extend(matchers: { [name: string]: JestMatcher }): void, @@ -1151,5 +1182,5 @@ declare var jasmine: { methodNames: Array ): { [methodName: string]: JestSpyType }, objectContaining(value: Object): Object, - stringMatching(value: string): string + stringMatching(value: string): string, }; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000000..e98503396a --- /dev/null +++ b/jest.config.js @@ -0,0 +1,18 @@ +const common = {testEnvironment: 'node'}; + +module.exports = { + projects: [ + { + ...common, + displayName: 'e2e', + setupFiles: ['/jest/setupE2eTests.js'], + testMatch: ['/**/__e2e__/*{.,-}test.js'], + }, + { + ...common, + displayName: 'unit', + setupFiles: ['/jest/setupUnitTests.js'], + testMatch: ['/**/__tests__/*{.,-}test.[jt]s'], + }, + ], +}; diff --git a/jest/helpers.js b/jest/helpers.js new file mode 100644 index 0000000000..e9b8ce6ecd --- /dev/null +++ b/jest/helpers.js @@ -0,0 +1,176 @@ +// @flow +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import {createDirectory} from 'jest-util'; +import rimraf from 'rimraf'; +import execa from 'execa'; +import chalk from 'chalk'; +import {Writable} from 'readable-stream'; + +const CLI_PATH = path.resolve(__dirname, '../packages/cli/build/bin.js'); + +type RunOptions = { + nodeOptions?: string, + nodePath?: string, + timeout?: number, // kill the process after X milliseconds + expectedFailure?: boolean, +}; + +export function run( + dir: string, + args?: Array, + options: RunOptions = { + expectedFailure: false, + }, +) { + return spawnCli(dir, args, options); +} + +// Runs cli until a given output is achieved, then kills it with `SIGTERM` +export async function runUntil( + dir: string, + args: Array | void, + text: string, + options: RunOptions = { + expectedFailure: false, + }, +) { + const spawnPromise = spawnCliAsync(dir, args, {timeout: 30000, ...options}); + + spawnPromise.stderr.pipe( + new Writable({ + write(chunk, _encoding, callback) { + const output = chunk.toString('utf8'); + + if (output.includes(text)) { + spawnPromise.kill(); + } + + callback(); + }, + }), + ); + + return spawnPromise; +} + +export const makeTemplate = ( + str: string, +): ((values?: Array) => string) => (values?: Array) => + str.replace(/\$(\d+)/g, (_match, number) => { + if (!Array.isArray(values)) { + throw new Error('Array of values must be passed to the template.'); + } + return values[number - 1]; + }); + +export const cleanup = (directory: string) => rimraf.sync(directory); + +/** + * Creates a nested directory with files and their contents + * writeFiles( + * '/home/tmp', + * { + * 'package.json': '{}', + * 'dir/file.js': 'module.exports = "x";', + * } + * ); + */ +export const writeFiles = ( + directory: string, + files: {[filename: string]: string}, +) => { + createDirectory(directory); + Object.keys(files).forEach(fileOrPath => { + const dirname = path.dirname(fileOrPath); + + if (dirname !== '/') { + createDirectory(path.join(directory, dirname)); + } + fs.writeFileSync( + path.resolve(directory, ...fileOrPath.split('/')), + files[fileOrPath], + ); + }); +}; + +export const copyDir = (src: string, dest: string) => { + const srcStat = fs.lstatSync(src); + if (srcStat.isDirectory()) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest); + } + fs.readdirSync(src).map(filePath => + copyDir(path.join(src, filePath), path.join(dest, filePath)), + ); + } else { + fs.writeFileSync(dest, fs.readFileSync(src)); + } +}; + +export const getTempDirectory = (name: string) => + path.resolve(os.tmpdir(), name); + +function spawnCli(dir: string, args?: Array, options: RunOptions = {}) { + const {spawnArgs, spawnOptions} = getCliArguments({dir, args, options}); + + const result = execa.sync(process.execPath, spawnArgs, spawnOptions); + + handleTestCliFailure(options, result, dir, args); + + return result; +} + +function spawnCliAsync( + dir: string, + args?: Array, + options: RunOptions = {}, +) { + const {spawnArgs, spawnOptions} = getCliArguments({dir, args, options}); + + try { + return execa(process.execPath, spawnArgs, spawnOptions); + } catch (result) { + handleTestCliFailure(options, result, dir, args); + return result; + } +} + +function getCliArguments({dir, args, options}) { + const isRelative = !path.isAbsolute(dir); + + if (isRelative) { + dir = path.resolve(__dirname, dir); + } + + const env = Object.assign({}, process.env, {FORCE_COLOR: '0'}); + + if (options.nodeOptions) { + env.NODE_OPTIONS = options.nodeOptions; + } + if (options.nodePath) { + env.NODE_PATH = options.nodePath; + } + + const spawnArgs = [CLI_PATH, ...(args || [])]; + const spawnOptions = { + cwd: dir, + env, + reject: false, + timeout: options.timeout || 0, + }; + return {spawnArgs, spawnOptions}; +} + +function handleTestCliFailure(options, result, dir, args) { + if (!options.expectedFailure && result.code !== 0) { + console.log(`Running CLI failed for unexpected reason. Here's more info: + +${chalk.bold('dir:')} ${dir} +${chalk.bold('args:')} ${(args || []).join(' ')} +${chalk.bold('stderr:')} ${result.stderr} +${chalk.bold('stdout:')} ${result.stdout} +${chalk.bold('code:')} ${result.code}`); + } +} diff --git a/jest/setupE2eTests.js b/jest/setupE2eTests.js new file mode 100644 index 0000000000..09ffd355df --- /dev/null +++ b/jest/setupE2eTests.js @@ -0,0 +1 @@ +jest.setTimeout(60000); diff --git a/jest/setupUnitTests.js b/jest/setupUnitTests.js new file mode 100644 index 0000000000..a6ea7c3723 --- /dev/null +++ b/jest/setupUnitTests.js @@ -0,0 +1,21 @@ +/** + * @flow + */ + +jest.mock('@react-native-community/cli-tools', () => { + return { + ...jest.requireActual('@react-native-community/cli-tools'), + logger: { + success: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + debug: jest.fn(), + log: jest.fn(), + setVerbose: jest.fn(), + isVerbose: jest.fn(), + }, + }; +}); + +jest.setTimeout(20000); diff --git a/lerna.json b/lerna.json index 94399037e2..6417ed7a99 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.10.6", - "version": "independent", + "version": "2.4.3", "npmClient": "yarn", "useWorkspaces": true } diff --git a/package.json b/package.json index d03f91bc2d..30d6f00d5a 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,20 @@ "packages/*" ], "scripts": { + "prebuild": "yarn build:ts", "build": "node ./scripts/build.js", + "build:ts": "node ./scripts/buildTs.js", "build-clean": "rm -rf ./packages/*/build", + "build-clean-with-ts-cache": "rm -rf ./packages/*/build ./packages/*/tsconfig.tsbuildinfo", "watch": "node ./scripts/watch.js", "test": "jest", - "lint": "eslint . --cache --report-unused-disable-directives", + "test:ci:unit": "jest packages --ci --coverage", + "test:ci:e2e": "jest e2e --ci -i", + "lint": "eslint --ext .js,.ts . --cache --report-unused-disable-directives", + "test:ci:cocoapods": "ruby packages/platform-ios/native_modules.rb", "flow-check": "flow check", "postinstall": "yarn build", - "publish": "yarn build-clean && yarn build && lerna publish" + "publish": "yarn build-clean && yarn install && lerna publish" }, "dependencies": { "@babel/core": "^7.0.0", @@ -19,35 +25,28 @@ "@babel/plugin-transform-strict-mode": "^7.0.0", "@babel/preset-env": "^7.0.0", "@babel/preset-flow": "^7.0.0", - "@callstack/eslint-config": "^3.0.2", - "babel-jest": "^24.0.0", + "@babel/preset-typescript": "^7.3.3", + "@react-native-community/eslint-config": "^0.0.5", + "@types/jest": "^24.0.11", + "@types/node": "^11.13.0", + "@types/node-fetch": "^2.3.7", + "babel-jest": "^24.6.0", + "babel-plugin-module-resolver": "^3.2.0", "chalk": "^2.4.2", "eslint": "^5.10.0", - "eslint-plugin-prettier": "^3.0.1", - "flow-bin": "^0.94.0", + "eslint-import-resolver-alias": "^1.1.2", + "eslint-import-resolver-typescript": "^1.1.1", + "eslint-plugin-import": "^2.17.0", + "execa": "^1.0.0", + "flow-bin": "^0.101.0", + "flow-typed": "^2.5.1", "glob": "^7.1.3", - "jest": "^24.0.0", - "lerna": "^3.10.6", + "jest": "^24.6.0", + "lerna": "^3.14.0", + "metro-memory-fs": "^0.53.1", "micromatch": "^3.1.10", "mkdirp": "^0.5.1", - "prettier": "^1.16.0", - "string-length": "^2.0.0" - }, - "eslintConfig": { - "extends": "@callstack", - "rules": { - "global-require": 0, - "no-console": 0 - } - }, - "prettier": { - "proseWrap": "never", - "singleQuote": true, - "trailingComma": "es5" - }, - "jest": { - "projects": [ - "packages/*" - ] + "string-length": "^2.0.0", + "typescript": "^3.4.5" } } diff --git a/packages/cli/.npmignore b/packages/cli/.npmignore deleted file mode 100644 index 11f4e9ffb6..0000000000 --- a/packages/cli/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -__fixtures__ -__tests__ -__mocks__ -src diff --git a/packages/cli/README.md b/packages/cli/README.md index 2639cde0cd..09780d1a58 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -2,79 +2,6 @@ Command line tools to interact with React Native projects. -## Commands +This package contains source code for `@react-native-community/cli`, the actual CLI that comes bundled with React Native. You don't need to install it separately in your project. -CLI comes with a set of commands and flags you can pass to them. - -- [`bundle`](#bundle) -- [`dependencies`](#dependencies) -- [`eject`](#eject) -- [`info`](#info) -- [`install`](#install) -- [`library`](#library) -- [`link`](#link) -- [`log-android`](#log-android) -- [`log-ios`](#log-ios) -- [`ram-bundle`](#ram-bundle) -- [`run-android`](#run-android) -- [`run-ios`](#run-ios) -- [`server`](#server) -- [`uninstall`](#uninstall) -- [`unlink`](#unlink) -- [`upgrade`](#upgrade) - -_Note: This document is still under development and doesn't represent the full API area._ - -### `run-ios` - -Builds your app and starts it on iOS simulator. - -#### Options - -#### `--simulator [simulator_name]` - -Explicitly set the simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version, e.g. `"iPhone 6 (10.0)"`. - -Default: `"iPhone X"` - -Notes: `simulator_name` must be a valid iOS simulator name. If in doubt, open your AwesomeApp/ios/AwesomeApp.xcodeproj folder on XCode and unroll the dropdown menu containing the simulator list. The dropdown menu is situated on the right hand side of the play button (top left corner). - -Example: this will launch your projet directly onto the iPhone XS Max simulator: - -```sh -react-native run-ios --simulator "iPhone XS Max" -``` - -#### `--configuration [string]` - -Explicitly set the scheme configuration to use default: 'Debug'. - -#### `--scheme [string]` - -Explicitly set Xcode scheme to use. - -#### `--project-path [string]` - -Path relative to project root where the Xcode project (.xcodeproj) lives. default: 'ios'. - -#### `--device [string]` - -Explicitly set device to use by name. The value is not required if you have a single device connected. - -#### `--udid [string]` - -Explicitly set device to use by udid. - -#### `--no-packager` - -Do not launch packager while building. - -#### `--verbose` - -Do not use `xcpretty` even if installed. - -#### `--port [number]` - -Runs packager on specified port - -Default: `process.env.RCT_METRO_PORT || 8081` +See the [list of available commands](../../docs/commands.md). diff --git a/packages/cli/jest.config.js b/packages/cli/jest.config.js deleted file mode 100644 index d7999eb600..0000000000 --- a/packages/cli/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - setupFiles: ['./testSetup.js'], - testEnvironment: 'node', -}; diff --git a/packages/cli/package.json b/packages/cli/package.json index 5662ced6b6..de2b231482 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,12 +1,16 @@ { "name": "@react-native-community/cli", - "version": "1.3.2", + "version": "2.4.3", "description": "React Native CLI", "license": "MIT", "main": "build/index.js", "bin": { "react-native": "build/bin.js" }, + "files": [ + "build", + "setup_env.sh" + ], "engineStrict": true, "engines": { "node": ">=8.3" @@ -19,43 +23,42 @@ "testEnvironment": "node" }, "dependencies": { - "chalk": "^1.1.1", - "commander": "^2.9.0", + "@hapi/joi": "^15.0.3", + "@react-native-community/cli-platform-android": "^2.4.1", + "@react-native-community/cli-platform-ios": "^2.4.1", + "@react-native-community/cli-tools": "^2.4.1", + "chalk": "^2.4.2", + "commander": "^2.19.0", "compression": "^1.7.1", "connect": "^3.6.5", - "denodeify": "^1.2.1", - "envinfo": "^5.7.0", + "cosmiconfig": "^5.1.0", + "deepmerge": "^3.2.0", + "envinfo": "^7.1.0", "errorhandler": "^1.5.0", - "escape-string-regexp": "^1.0.5", "execa": "^1.0.0", - "fs-extra": "^1.0.0", + "fs-extra": "^7.0.1", "glob": "^7.1.1", "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.51.0", - "metro-config": "^0.51.0", - "metro-core": "^0.51.0", - "metro-memory-fs": "^0.51.0", - "metro-react-native-babel-transformer": "^0.51.0", - "mime": "^1.3.4", + "metro": "^0.54.1", + "metro-config": "^0.54.1", + "metro-core": "^0.54.1", + "metro-react-native-babel-transformer": "^0.54.1", "minimist": "^1.2.0", "mkdirp": "^0.5.1", "morgan": "^1.9.0", - "node-fetch": "^2.2.0", "node-notifier": "^5.2.1", - "opn": "^3.0.2", + "open": "^6.2.0", + "ora": "^3.4.0", "plist": "^3.0.0", "semver": "^5.0.3", "serve-static": "^1.13.1", "shell-quote": "1.6.1", - "slash": "^2.0.0", - "ws": "^1.1.0", - "xcode": "^2.0.0", - "xmldoc": "^0.4.0" + "ws": "^1.1.0" }, "peerDependencies": { - "react-native": "^0.57.0" + "react-native": "^0.60.0" }, "devDependencies": { "snapshot-diff": "^0.5.0" diff --git a/packages/cli/src/bin.js b/packages/cli/src/bin.js index 78b528f7f7..d8f99f54a6 100755 --- a/packages/cli/src/bin.js +++ b/packages/cli/src/bin.js @@ -9,6 +9,7 @@ * @flow */ +// eslint-disable-next-line import/default import cliEntry from '.'; cliEntry.run(); diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index 8e8efe5ca3..b2342de34d 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -10,20 +10,21 @@ import chalk from 'chalk'; import childProcess from 'child_process'; import commander from 'commander'; -import minimist from 'minimist'; import path from 'path'; -import type { CommandT, ContextT } from './tools/types.flow'; -import getLegacyConfig from './tools/getLegacyConfig'; -import { getCommands } from './commands'; -import init from './commands/init/init'; + +import type {CommandT, ConfigT} from 'types'; + +import commands from './commands'; +import init from './commands/init/initCompat'; import assertRequiredOptions from './tools/assertRequiredOptions'; -import logger from './tools/logger'; -import pkg from '../package.json'; +import {logger} from '@react-native-community/cli-tools'; +import {setProjectDir} from './tools/packageManager'; +import pkgJson from '../package.json'; +import loadConfig from './tools/config'; commander - .version(pkg.version) - .option('--projectRoot [string]', 'Path to the root of the project') - .option('--reactNativePath [string]', 'Path to React Native'); + .option('--version', 'Print CLI version') + .option('--verbose', 'Increase logging verbosity'); commander.on('command:*', () => { printUnknownCommand(commander.args.join(' ')); @@ -33,47 +34,58 @@ commander.on('command:*', () => { const defaultOptParser = val => val; const handleError = err => { - logger.error(err.message); + if (commander.verbose) { + logger.error(err.message); + } else { + // Some error messages (esp. custom ones) might have `.` at the end already. + const message = err.message.replace(/\.$/, ''); + logger.error( + `${message}. ${chalk.dim( + `Run CLI with ${chalk.reset('--verbose')} ${chalk.dim( + 'flag for more details.', + )}`, + )}`, + ); + } + if (err.stack) { + logger.log(chalk.dim(err.stack)); + } process.exit(1); }; // Custom printHelpInformation command inspired by internal Commander.js // one modified to suit our needs -function printHelpInformation() { +function printHelpInformation(examples, pkg) { let cmdName = this._name; + const argsList = this._args + .map(arg => (arg.required ? `<${arg.name}>` : `[${arg.name}]`)) + .join(' '); + if (this._alias) { cmdName = `${cmdName}|${this._alias}`; } - const sourceInformation = this.pkg - ? [` ${chalk.bold('Source:')} ${this.pkg.name}@${this.pkg.version}`, ''] + const sourceInformation = pkg + ? [`${chalk.bold('Source:')} ${pkg.name}@${pkg.version}`, ''] : []; let output = [ - '', - chalk.bold(chalk.cyan(` react-native ${cmdName} ${this.usage()}`)), - this._description ? ` ${this._description}` : '', - '', + chalk.bold(`react-native ${cmdName} ${argsList}`), + this._description ? `\n${this._description}\n` : '', ...sourceInformation, - ` ${chalk.bold('Options:')}`, - '', - this.optionHelp().replace(/^/gm, ' '), - '', + `${chalk.bold('Options:')}`, + this.optionHelp().replace(/^/gm, ' '), ]; - if (this.examples && this.examples.length > 0) { - const formattedUsage = this.examples - .map(example => ` ${example.desc}: \n ${chalk.cyan(example.cmd)}`) + if (examples && examples.length > 0) { + const formattedUsage = examples + .map(example => ` ${example.desc}: \n ${chalk.cyan(example.cmd)}`) .join('\n\n'); - output = output.concat([ - chalk.bold(' Example usage:'), - '', - formattedUsage, - ]); + output = output.concat([chalk.bold('\nExample usage:'), formattedUsage]); } - return output.concat(['', '']).join('\n'); + return output.join('\n').concat('\n'); } function printUnknownCommand(cmdName) { @@ -81,52 +93,47 @@ function printUnknownCommand(cmdName) { logger.error(`Unrecognized command "${chalk.bold(cmdName)}".`); logger.info( `Run ${chalk.bold( - '"react-native --help"' - )} to see a list of all available commands.` + '"react-native --help"', + )} to see a list of all available commands.`, ); } else { commander.outputHelp(); } } -const addCommand = (command: CommandT, ctx: ContextT) => { +const addCommand = (command: CommandT, ctx: ConfigT) => { const options = command.options || []; const cmd = commander - .command(command.name, undefined, { - noHelp: !command.description, - }) + .command(command.name) .description(command.description) - .action(function handleAction(...args) { + .action(async function handleAction(...args) { const passedOptions = this.opts(); const argv: Array = Array.from(args).slice(0, -1); - Promise.resolve() - .then(() => { - assertRequiredOptions(options, passedOptions); - return command.func(argv, ctx, passedOptions); - }) - .catch(handleError); + try { + assertRequiredOptions(options, passedOptions); + await command.func(argv, ctx, passedOptions); + } catch (error) { + handleError(error); + } }); - cmd.helpInformation = printHelpInformation.bind(cmd); - cmd.examples = command.examples; - // $FlowFixMe: This is either null or not - cmd.pkg = command.pkg; + cmd.helpInformation = printHelpInformation.bind( + cmd, + command.examples, + // $FlowFixMe - we know pkg may be missing... + command.pkg, + ); options.forEach(opt => cmd.option( - opt.command, + opt.name, opt.description, opt.parse || defaultOptParser, - opt.default - ) + typeof opt.default === 'function' ? opt.default(ctx) : opt.default, + ), ); - - // Redefined here to appear in the `--help` section - cmd - .option('--projectRoot [string]', 'Path to the root of the project') - .option('--reactNativePath [string]', 'Path to React Native'); }; async function run() { @@ -144,68 +151,53 @@ async function setupAndRun() { const absolutePath = path.join(__dirname, '..', scriptName); try { - childProcess.execFileSync(absolutePath, { stdio: 'pipe' }); + childProcess.execFileSync(absolutePath, {stdio: 'pipe'}); } catch (error) { logger.warn( `Failed to run environment setup script "${scriptName}"\n\n${chalk.red( - error - )}` + error, + )}`, ); logger.info( - `React Native CLI will continue to run if your local environment matches what React Native expects. If it does fail, check out "${absolutePath}" and adjust your environment to match it.` + `React Native CLI will continue to run if your local environment matches what React Native expects. If it does fail, check out "${absolutePath}" and adjust your environment to match it.`, ); } } - /** - * Read passed `options` and take the "global" settings - * - * @todo(grabbou): Consider unifying this by removing either `commander` - * or `minimist` - */ - const options = minimist(process.argv.slice(2)); - - const root = options.projectRoot - ? path.resolve(options.projectRoot) - : process.cwd(); - - const reactNativePath = options.reactNativePath - ? path.resolve(options.reactNativePath) - : (() => { - try { - return path.dirname( - // $FlowIssue: Wrong `require.resolve` type definition - require.resolve('react-native/package.json', { - paths: [root], - }) - ); - } catch (_ignored) { - throw new Error( - 'Unable to find React Native files. Make sure "react-native" module is installed in your project dependencies.' - ); - } - })(); - - const ctx = { - ...getLegacyConfig(root), - reactNativePath, - root, - }; - - const commands = getCommands(ctx.root); - - commands.forEach(command => addCommand(command, ctx)); + // when we run `config`, we don't want to output anything to the console. We + // expect it to return valid JSON + if (process.argv.includes('config')) { + logger.disable(); + } + + const ctx = loadConfig(); + + logger.enable(); + + setProjectDir(ctx.root); + + [...commands, ...ctx.commands].forEach(command => addCommand(command, ctx)); commander.parse(process.argv); - if (!options._.length) { + if (commander.rawArgs.length === 2) { commander.outputHelp(); } + + // We handle --version as a special case like this because both `commander` + // and `yargs` append it to every command and we don't want to do that. + // E.g. outside command `init` has --version flag and we want to preserve it. + if (commander.args.length === 0 && commander.version === true) { + console.log(pkgJson.version); + } + + logger.setVerbose(commander.verbose); } export default { run, init, + loadConfig, }; -// export { run, init }; +export {run, init, loadConfig}; diff --git a/packages/cli/src/commands/bundle/__tests__/getAssetDestPathAndroid-test.js b/packages/cli/src/commands/bundle/__tests__/getAssetDestPathAndroid-test.js index c169e0a3c8..2670f14cdc 100644 --- a/packages/cli/src/commands/bundle/__tests__/getAssetDestPathAndroid-test.js +++ b/packages/cli/src/commands/bundle/__tests__/getAssetDestPathAndroid-test.js @@ -25,7 +25,7 @@ describe('getAssetDestPathAndroid', () => { const expectDestPathForScaleToStartWith = (scale, location) => { if (!getAssetDestPathAndroid(asset, scale).startsWith(location)) { throw new Error( - `asset for scale ${scale} should start with path '${location}'` + `asset for scale ${scale} should start with path '${location}'`, ); } }; @@ -45,7 +45,7 @@ describe('getAssetDestPathAndroid', () => { }; expect(getAssetDestPathAndroid(asset, 1)).toBe( - path.normalize('drawable-mdpi/app_test_icon.png') + path.normalize('drawable-mdpi/app_test_icon.png'), ); }); @@ -67,7 +67,7 @@ describe('getAssetDestPathAndroid', () => { }; expect(getAssetDestPathAndroid(asset, 1)).toBe( - path.normalize('raw/app_test_video.mp4') + path.normalize('raw/app_test_video.mp4'), ); }); }); diff --git a/packages/cli/src/commands/bundle/__tests__/getAssetDestPathIOS-test.js b/packages/cli/src/commands/bundle/__tests__/getAssetDestPathIOS-test.js index 37878875a2..7a820b6173 100644 --- a/packages/cli/src/commands/bundle/__tests__/getAssetDestPathIOS-test.js +++ b/packages/cli/src/commands/bundle/__tests__/getAssetDestPathIOS-test.js @@ -23,7 +23,7 @@ describe('getAssetDestPathIOS', () => { }; expect(getAssetDestPathIOS(asset, 1)).toBe( - path.normalize('assets/test/icon.png') + path.normalize('assets/test/icon.png'), ); }); @@ -35,10 +35,10 @@ describe('getAssetDestPathIOS', () => { }; expect(getAssetDestPathIOS(asset, 2)).toBe( - path.normalize('assets/test/icon@2x.png') + path.normalize('assets/test/icon@2x.png'), ); expect(getAssetDestPathIOS(asset, 3)).toBe( - path.normalize('assets/test/icon@3x.png') + path.normalize('assets/test/icon@3x.png'), ); }); }); diff --git a/packages/cli/src/commands/bundle/assetPathUtils.js b/packages/cli/src/commands/bundle/assetPathUtils.js index 7778684def..32334dd723 100644 --- a/packages/cli/src/commands/bundle/assetPathUtils.js +++ b/packages/cli/src/commands/bundle/assetPathUtils.js @@ -56,8 +56,8 @@ function getAndroidResourceFolderName(asset: PackagerAsset, scale: number) { if (!suffix) { throw new Error( `Don't know which android drawable suffix to use for asset: ${JSON.stringify( - asset - )}` + asset, + )}`, ); } const androidFolder = `drawable-${suffix}`; diff --git a/packages/cli/src/commands/bundle/buildBundle.js b/packages/cli/src/commands/bundle/buildBundle.js index a10dc2457d..97557b1296 100644 --- a/packages/cli/src/commands/bundle/buildBundle.js +++ b/packages/cli/src/commands/bundle/buildBundle.js @@ -11,22 +11,42 @@ import Server from 'metro/src/Server'; import outputBundle from 'metro/src/shared/output/bundle'; import path from 'path'; -import type { CommandLineArgs } from './bundleCommandLineArgs'; -import type { ContextT } from '../../tools/types.flow'; +import chalk from 'chalk'; +import type {CommandLineArgs} from './bundleCommandLineArgs'; +import type {ConfigT} from 'types'; import saveAssets from './saveAssets'; import loadMetroConfig from '../../tools/loadMetroConfig'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; async function buildBundle( args: CommandLineArgs, - ctx: ContextT, - output: typeof outputBundle = outputBundle + ctx: ConfigT, + output: typeof outputBundle = outputBundle, ) { const config = await loadMetroConfig(ctx, { + maxWorkers: args.maxWorkers, resetCache: args.resetCache, config: args.config, }); + if (config.resolver.platforms.indexOf(args.platform) === -1) { + logger.error( + `Invalid platform ${ + args.platform ? `"${chalk.bold(args.platform)}" ` : '' + }selected.`, + ); + + logger.info( + `Available platforms are: ${config.resolver.platforms + .map(x => `"${chalk.bold(x)}"`) + .join( + ', ', + )}. If you are trying to bundle for an out-of-tree platform, it may not be installed.`, + ); + + throw new Error('Bundling failed'); + } + // This is used by a bazillion of npm modules we don't control so we don't // have other choice than defining it as an env variable here. process.env.NODE_ENV = args.dev ? 'development' : 'production'; diff --git a/packages/cli/src/commands/bundle/bundle.js b/packages/cli/src/commands/bundle/bundle.js index 5c57882092..dc9790ec52 100644 --- a/packages/cli/src/commands/bundle/bundle.js +++ b/packages/cli/src/commands/bundle/bundle.js @@ -28,4 +28,4 @@ export default { const withOutput = bundleWithOutput; -export { withOutput }; +export {withOutput}; diff --git a/packages/cli/src/commands/bundle/bundleCommandLineArgs.js b/packages/cli/src/commands/bundle/bundleCommandLineArgs.js index f347eb0096..465e12b337 100644 --- a/packages/cli/src/commands/bundle/bundleCommandLineArgs.js +++ b/packages/cli/src/commands/bundle/bundleCommandLineArgs.js @@ -30,27 +30,27 @@ export type CommandLineArgs = { export default [ { - command: '--entry-file ', + name: '--entry-file ', description: 'Path to the root JS file, either absolute or relative to JS root', }, { - command: '--platform [string]', + name: '--platform [string]', description: 'Either "ios" or "android"', default: 'ios', }, { - command: '--transformer [string]', + name: '--transformer [string]', description: 'Specify a custom transformer to be used', }, { - command: '--dev [boolean]', + name: '--dev [boolean]', description: 'If false, warnings are disabled and the bundle is minified', parse: (val: string) => val !== 'false', default: true, }, { - command: '--minify [boolean]', + name: '--minify [boolean]', description: 'Allows overriding whether bundle is minified. This defaults to ' + 'false if dev is true, and true if dev is false. Disabling minification ' + @@ -58,18 +58,18 @@ export default [ parse: (val: string) => val !== 'false', }, { - command: '--bundle-output ', + name: '--bundle-output ', description: 'File name where to store the resulting bundle, ex. /tmp/groups.bundle', }, { - command: '--bundle-encoding [string]', + name: '--bundle-encoding [string]', description: 'Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).', default: 'utf8', }, { - command: '--max-workers [number]', + name: '--max-workers [number]', description: 'Specifies the maximum number of workers the worker-pool ' + 'will spawn for transforming files. This defaults to the number of the ' + @@ -77,38 +77,38 @@ export default [ parse: (workers: string) => Number(workers), }, { - command: '--sourcemap-output [string]', + name: '--sourcemap-output [string]', description: 'File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map', }, { - command: '--sourcemap-sources-root [string]', + name: '--sourcemap-sources-root [string]', description: "Path to make sourcemap's sources entries relative to, ex. /root/dir", }, { - command: '--sourcemap-use-absolute-path', + name: '--sourcemap-use-absolute-path', description: 'Report SourceMapURL using its full path', default: false, }, { - command: '--assets-dest [string]', + name: '--assets-dest [string]', description: 'Directory name where to store assets referenced in the bundle', }, { - command: '--reset-cache', + name: '--reset-cache', description: 'Removes cached files', default: false, }, { - command: '--read-global-cache', + name: '--read-global-cache', description: 'Try to fetch transformed JS code from the global cache, if configured.', default: false, }, { - command: '--config [string]', + name: '--config [string]', description: 'Path to the CLI configuration file', parse: (val: string) => path.resolve(val), }, diff --git a/packages/cli/src/commands/bundle/filterPlatformAssetScales.js b/packages/cli/src/commands/bundle/filterPlatformAssetScales.js index c34d6b4cd2..94c6bd9fa0 100644 --- a/packages/cli/src/commands/bundle/filterPlatformAssetScales.js +++ b/packages/cli/src/commands/bundle/filterPlatformAssetScales.js @@ -14,7 +14,7 @@ const ALLOWED_SCALES = { function filterPlatformAssetScales( platform: string, - scales: $ReadOnlyArray + scales: $ReadOnlyArray, ): $ReadOnlyArray { const whitelist = ALLOWED_SCALES[platform]; if (!whitelist) { diff --git a/packages/cli/src/commands/bundle/getAssetDestPathAndroid.js b/packages/cli/src/commands/bundle/getAssetDestPathAndroid.js index d331b2f19d..510d6ab483 100644 --- a/packages/cli/src/commands/bundle/getAssetDestPathAndroid.js +++ b/packages/cli/src/commands/bundle/getAssetDestPathAndroid.js @@ -9,14 +9,14 @@ */ import path from 'path'; -import type { PackagerAsset } from './assetPathUtils'; +import type {PackagerAsset} from './assetPathUtils'; import assetPathUtils from './assetPathUtils'; function getAssetDestPathAndroid(asset: PackagerAsset, scale: number): string { const androidFolder = assetPathUtils.getAndroidResourceFolderName( asset, - scale + scale, ); const fileName = assetPathUtils.getAndroidResourceIdentifier(asset); return path.join(androidFolder, `${fileName}.${asset.type}`); diff --git a/packages/cli/src/commands/bundle/getAssetDestPathIOS.js b/packages/cli/src/commands/bundle/getAssetDestPathIOS.js index e8e153d038..cc50c2be10 100644 --- a/packages/cli/src/commands/bundle/getAssetDestPathIOS.js +++ b/packages/cli/src/commands/bundle/getAssetDestPathIOS.js @@ -9,7 +9,7 @@ */ import path from 'path'; -import type { PackagerAsset } from './assetPathUtils'; +import type {PackagerAsset} from './assetPathUtils'; function getAssetDestPathIOS(asset: PackagerAsset, scale: number): string { const suffix = scale === 1 ? '' : `@${scale}x`; diff --git a/packages/cli/src/commands/bundle/ramBundle.js b/packages/cli/src/commands/bundle/ramBundle.js index c4fdbd7321..c9420ad8bf 100644 --- a/packages/cli/src/commands/bundle/ramBundle.js +++ b/packages/cli/src/commands/bundle/ramBundle.js @@ -8,7 +8,7 @@ */ import outputUnbundle from 'metro/src/shared/output/RamBundle'; -import { withOutput as bundleWithOutput } from './bundle'; +import {withOutput as bundleWithOutput} from './bundle'; import bundleCommandLineArgs from './bundleCommandLineArgs'; /** @@ -24,7 +24,7 @@ export default { 'builds javascript as a "Random Access Module" bundle for offline use', func: ramBundle, options: bundleCommandLineArgs.concat({ - command: '--indexed-ram-bundle', + name: '--indexed-ram-bundle', description: 'Force the "Indexed RAM" bundle file format, even when building for android', default: false, diff --git a/packages/cli/src/commands/bundle/saveAssets.js b/packages/cli/src/commands/bundle/saveAssets.js index c98bbb315d..34e7dcc084 100644 --- a/packages/cli/src/commands/bundle/saveAssets.js +++ b/packages/cli/src/commands/bundle/saveAssets.js @@ -14,7 +14,7 @@ import fs from 'fs'; import filterPlatformAssetScales from './filterPlatformAssetScales'; import getAssetDestPathAndroid from './getAssetDestPathAndroid'; import getAssetDestPathIOS from './getAssetDestPathIOS'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; function saveAssets(assets, platform, assetsDest) { if (!assetsDest) { @@ -28,7 +28,7 @@ function saveAssets(assets, platform, assetsDest) { const filesToCopy = Object.create(null); // Map src -> dest assets.forEach(asset => { const validScales = new Set( - filterPlatformAssetScales(platform, asset.scales) + filterPlatformAssetScales(platform, asset.scales), ); asset.scales.forEach((scale, idx) => { if (!validScales.has(scale)) { diff --git a/packages/cli/src/commands/config/config.js b/packages/cli/src/commands/config/config.js new file mode 100644 index 0000000000..37705d0d38 --- /dev/null +++ b/packages/cli/src/commands/config/config.js @@ -0,0 +1,32 @@ +/** + * @flow + */ +import {type ConfigT} from 'types'; + +function isValidRNDependency(config) { + return ( + Object.keys(config.platforms).filter(key => Boolean(config.platforms[key])) + .length !== 0 || + Object.keys(config.hooks).length !== 0 || + config.assets.length !== 0 || + config.params.length !== 0 + ); +} + +function filterConfig(config) { + const filtered = {...config}; + Object.keys(filtered.dependencies).forEach(item => { + if (!isValidRNDependency(filtered.dependencies[item])) { + delete filtered.dependencies[item]; + } + }); + return filtered; +} + +export default { + name: 'config', + description: 'Print CLI configuration', + func: async (argv: string[], ctx: ConfigT) => { + console.log(JSON.stringify(filterConfig(ctx), null, 2)); + }, +}; diff --git a/packages/cli/src/commands/dependencies/dependencies.js b/packages/cli/src/commands/dependencies/dependencies.js deleted file mode 100644 index c7a4e5d461..0000000000 --- a/packages/cli/src/commands/dependencies/dependencies.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import Metro from 'metro'; - -import denodeify from 'denodeify'; -import fs from 'fs'; -import path from 'path'; -import util from 'util'; - -async function dependencies(argv, configPromise, args, packagerInstance) { - const rootModuleAbsolutePath = args.entryFile; - const config = await configPromise; - if (!fs.existsSync(rootModuleAbsolutePath)) { - return Promise.reject( - new Error(`File ${rootModuleAbsolutePath} does not exist`) - ); - } - - config.cacheStores = []; - - const relativePath = path.relative( - config.projectRoot, - rootModuleAbsolutePath - ); - - const options = { - platform: args.platform, - entryFile: relativePath, - dev: args.dev, - minify: false, - generateSourceMaps: !args.dev, - }; - - const writeToFile = args.output; - const outStream = writeToFile - ? fs.createWriteStream(args.output) - : process.stdout; - - const deps = packagerInstance - ? await packagerInstance.getOrderedDependencyPaths(options) - : await Metro.getOrderedDependencyPaths(config, options); - - deps.forEach(modulePath => { - // Temporary hack to disable listing dependencies not under this directory. - // Long term, we need either - // (a) JS code to not depend on anything outside this directory, or - // (b) Come up with a way to declare this dependency in Buck. - const isInsideProjectRoots = - config.watchFolders.filter(root => modulePath.startsWith(root)).length > - 0; - - if (isInsideProjectRoots) { - outStream.write(`${modulePath}\n`); - } - }); - return writeToFile - ? denodeify(outStream.end).bind(outStream)() - : Promise.resolve(); -} - -export default { - name: 'dependencies', - description: 'lists dependencies', - func: util.deprecate( - dependencies, - 'dependencies command was moved to metro, and will be removed from cli in next release' - ), - options: [ - { - command: '--entry-file ', - description: 'Absolute path to the root JS file', - }, - { - command: '--output [path]', - description: - 'File name where to store the output, ex. /tmp/dependencies.txt', - }, - { - command: '--platform [extension]', - description: 'The platform extension used for selecting modules', - }, - { - command: '--transformer [path]', - description: 'Specify a custom transformer to be used', - }, - { - command: '--max-workers [number]', - description: - 'Specifies the maximum number of workers the worker-pool ' + - 'will spawn for transforming files. This defaults to the number of the ' + - 'cores available on your machine.', - parse: workers => Number(workers), - }, - { - command: '--dev [boolean]', - description: 'If false, skip all dev-only code path', - parse: val => val !== 'false', - default: true, - }, - { - command: '--verbose', - description: 'Enables logging', - default: false, - }, - ], -}; diff --git a/packages/cli/src/commands/eject/eject.js b/packages/cli/src/commands/eject/eject.js deleted file mode 100644 index c8c970eb67..0000000000 --- a/packages/cli/src/commands/eject/eject.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import path from 'path'; -import fs from 'fs'; -import copyProjectTemplateAndReplace from '../../tools/generator/copyProjectTemplateAndReplace'; -import logger from '../../tools/logger'; - -/** - * The eject command re-creates the `android` and `ios` native folders. Because native code can be - * difficult to maintain, this new script allows an `app.json` to be defined for the project, which - * is used to configure the native app. - * - * The `app.json` config may contain the following keys: - * - * - `name` - The short name used for the project, should be TitleCase - * - `displayName` - The app's name on the home screen - */ - -function eject() { - const doesIOSExist = fs.existsSync(path.resolve('ios')); - const doesAndroidExist = fs.existsSync(path.resolve('android')); - if (doesIOSExist && doesAndroidExist) { - logger.error( - 'Both the iOS and Android folders already exist! Please delete `ios` and/or `android` ' + - 'before ejecting.' - ); - process.exit(1); - } - - let appConfig = null; - try { - appConfig = require(path.resolve('app.json')); - } catch (e) { - logger.error( - 'Eject requires an `app.json` config file to be located at ' + - `${path.resolve( - 'app.json' - )}, and it must at least specify a \`name\` for the project ` + - "name, and a `displayName` for the app's home screen label." - ); - process.exit(1); - } - - const appName = appConfig.name; - if (!appName) { - logger.error( - 'App `name` must be defined in the `app.json` config file to define the project name. ' + - 'It must not contain any spaces or dashes.' - ); - process.exit(1); - } - - // eslint-disable-next-line prefer-destructuring - const displayName = appConfig.displayName; - if (!displayName) { - logger.error( - 'App `displayName` must be defined in the `app.json` config file, to define the label ' + - 'of the app on the home screen.' - ); - process.exit(1); - } - - const templateOptions = { displayName }; - - if (!doesIOSExist) { - logger.info('Generating the iOS folder.'); - copyProjectTemplateAndReplace( - path.resolve( - 'node_modules', - 'react-native', - '@react-native-community', - 'cli', - 'templates', - 'HelloWorld', - 'ios' - ), - path.resolve('ios'), - appName, - templateOptions - ); - } - - if (!doesAndroidExist) { - logger.info('Generating the Android folder.'); - copyProjectTemplateAndReplace( - path.resolve( - 'node_modules', - 'react-native', - '@react-native-community', - 'cli', - 'templates', - 'HelloWorld', - 'android' - ), - path.resolve('android'), - appName, - templateOptions - ); - } -} - -export default { - name: 'eject', - description: 'Re-create the iOS and Android folders and native code', - func: eject, - options: [], -}; diff --git a/packages/cli/src/commands/index.js b/packages/cli/src/commands/index.js index bab984b73a..6c56740c4f 100644 --- a/packages/cli/src/commands/index.js +++ b/packages/cli/src/commands/index.js @@ -1,120 +1,30 @@ /** * @flow */ - -import path from 'path'; - -import findPlugins from '../tools/findPlugins'; -import logger from '../tools/logger'; - -import type { - CommandT, - ProjectCommandT, - LocalCommandT, -} from '../tools/types.flow'; +import {type CommandT} from 'types'; 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 eject from './eject/eject'; 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 dependencies from './dependencies/dependencies'; import info from './info/info'; +import config from './config/config'; +import init from './init'; -/** - * List of built-in commands - */ - -const loadLocalCommands: Array = [ +export default ([ server, - runIOS, - runAndroid, - library, bundle, ramBundle, - eject, link, unlink, install, uninstall, upgrade, - logAndroid, - logIOS, - dependencies, info, -]; - -/** - * 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: string): Array => { - const plugins = findPlugins(root); - - return plugins.commands.reduce((acc: Array, pathToCommands) => { - /** - * `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 = - pathToCommands[0] === '@' - ? pathToCommands - .split(path.sep) - .slice(0, 2) - .join(path.sep) - : pathToCommands.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', - pathToCommands - )); - - if (Array.isArray(requiredCommands)) { - return acc.concat( - requiredCommands.map(requiredCommand => ({ ...requiredCommand, pkg })) - ); - } - - return acc.concat({ ...requiredCommands }); - }, []); -}; - -/** - * Loads all the commands inside a given `root` folder - */ -export function getCommands(root: string): Array { - return [ - ...loadLocalCommands, - { - name: 'init', - func: () => { - logger.warn( - [ - 'Looks like a React Native project already exists in the current', - 'folder. Run this command from a different folder or remove node_modules/react-native', - ].join('\n') - ); - }, - }, - ...loadProjectCommands(root), - ]; -} + config, + init, +]: CommandT[]); diff --git a/packages/cli/src/commands/info/__tests__/info.test.js b/packages/cli/src/commands/info/__tests__/info.test.js new file mode 100644 index 0000000000..bea3af2c90 --- /dev/null +++ b/packages/cli/src/commands/info/__tests__/info.test.js @@ -0,0 +1,26 @@ +// @flow +import info from '../info'; +import {logger} from '@react-native-community/cli-tools'; +import loadConfig from '../../../tools/config'; + +jest.mock('../../../tools/config'); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +const config = loadConfig(); + +test('prints output without arguments', async () => { + await info.func([], config, {}); + expect(logger.info).toHaveBeenCalledWith( + 'Fetching system and libraries information...', + ); + const output = (logger.log: any).mock.calls[0][0]; + // Checking on output that should be present on all OSes. + // TODO: move to e2e tests and adjust expectations to include npm packages + expect(output).toContain('System:'); + expect(output).toContain('Binaries:'); +}, 20000); + +test.todo('prints output with --packages'); diff --git a/packages/cli/src/commands/info/info.js b/packages/cli/src/commands/info/info.js index 9b6bffaca2..149f87459d 100644 --- a/packages/cli/src/commands/info/info.js +++ b/packages/cli/src/commands/info/info.js @@ -4,77 +4,39 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import envinfo from 'envinfo'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; +import releaseChecker from '../../tools/releaseChecker'; -const info = function getInfo(argv, ctx, options) { +const info = async function getInfo( + argv: Array, + ctx: ConfigT, + options: {}, +) { try { - envinfo - .run( - { - System: ['OS', 'CPU', 'Memory', 'Shell'], - Binaries: ['Node', 'Yarn', 'npm', 'Watchman'], - IDEs: ['Xcode', 'Android Studio'], - SDKs: ['iOS SDK', 'Android SDK'], - npmPackages: - (typeof options.packages === 'string' && - !options.packages.includes('*')) || - !options.packages - ? ['react', 'react-native'].concat( - (options.packages || '').split(',') - ) - : options.packages, - npmGlobalPackages: '*react-native*', - }, - { - clipboard: !!options.clipboard, - title: 'React Native Environment Info', - } - ) - .then(logger.info) - .catch(err => { - logger.error(`Unable to print environment info.\n${err}`); - }); + logger.info('Fetching system and libraries information...'); + const output = await envinfo.run({ + System: ['OS', 'CPU', 'Memory', 'Shell'], + Binaries: ['Node', 'Yarn', 'npm', 'Watchman'], + IDEs: ['Xcode', 'Android Studio'], + SDKs: ['iOS SDK', 'Android SDK'], + npmPackages: ['react', 'react-native', '@react-native-community/cli'], + npmGlobalPackages: '*react-native*', + }); + logger.log(output.trim()); } catch (err) { logger.error(`Unable to print environment info.\n${err}`); + } finally { + await releaseChecker(ctx.root); } }; export default { name: 'info', description: 'Get relevant version info about OS, toolchain and libraries', - options: [ - { - command: '--packages [string]', - description: - 'Which packages from your package.json to include, in addition to the default React Native and React versions.', - }, - { - command: '--clipboard [boolean]', - description: - 'Automagically copy the environment report output to the clipboard', - }, - ], - examples: [ - { - desc: 'Get standard version info', - cmd: 'react-native info', - }, - { - desc: 'Get standard version info & specified package versions', - cmd: 'react-native info --packages jest,eslint', - }, - { - desc: 'Get standard version info & globbed package versions', - cmd: 'react-native info --packages "*react*"', - }, - { - desc: 'Get standard version info & all package versions', - cmd: 'react-native info --packages', - }, - ], func: info, }; diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/android/com/placeholdername/Main.java b/packages/cli/src/commands/init/__fixtures__/editTemplate/android/com/placeholdername/Main.java new file mode 100644 index 0000000000..a4dca4603d --- /dev/null +++ b/packages/cli/src/commands/init/__fixtures__/editTemplate/android/com/placeholdername/Main.java @@ -0,0 +1,7 @@ +com.placeholdername; + +public static class Main { + public static void run() { + String name = "PlaceholderName"; + } +} diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/android/com/placeholdername/PlaceholderName.java b/packages/cli/src/commands/init/__fixtures__/editTemplate/android/com/placeholdername/PlaceholderName.java new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderName-tvOS/.gitkeep b/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderName-tvOS/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderName/AppDelegate.m b/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderName/AppDelegate.m new file mode 100644 index 0000000000..0bc93c7c4e --- /dev/null +++ b/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderName/AppDelegate.m @@ -0,0 +1,17 @@ +#import "AppDelegate.h" + +#import +#import +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:@"PlaceholderName" + initialProperties:nil]; +} + +@end \ No newline at end of file diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderNameTests/.gitkeep b/packages/cli/src/commands/init/__fixtures__/editTemplate/ios/PlaceholderNameTests/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/commands/init/__fixtures__/editTemplate/node_modules/PlaceholderName b/packages/cli/src/commands/init/__fixtures__/editTemplate/node_modules/PlaceholderName new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/commands/init/__tests__/__snapshots__/editTemplate.test.js.snap b/packages/cli/src/commands/init/__tests__/__snapshots__/editTemplate.test.js.snap new file mode 100644 index 0000000000..5e9a1f488c --- /dev/null +++ b/packages/cli/src/commands/init/__tests__/__snapshots__/editTemplate.test.js.snap @@ -0,0 +1,58 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should edit template 1`] = ` +"Snapshot Diff: +- First value ++ Second value + +@@ -12,3 +12,3 @@ + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge +- moduleName:@\\"PlaceholderName\\" ++ moduleName:@\\"ProjectName\\" + initialProperties:nil];" +`; + +exports[`should edit template 2`] = ` +"Snapshot Diff: +- First value ++ Second value + +@@ -1,2 +1,2 @@ +- com.placeholdername; ++ com.projectname; + +@@ -4,3 +4,3 @@ + public static void run() { +- String name = \\"PlaceholderName\\"; ++ String name = \\"ProjectName\\"; + }" +`; + +exports[`should edit template 3`] = ` +"Snapshot Diff: +- First value ++ Second value + +@@ -4,12 +4,12 @@ + \\"/android/com\\", +- \\"/android/com/placeholdername\\", +- \\"/android/com/placeholdername/Main.java\\", +- \\"/android/com/placeholdername/PlaceholderName.java\\", ++ \\"/android/com/projectname\\", ++ \\"/android/com/projectname/Main.java\\", ++ \\"/android/com/projectname/ProjectName.java\\", + \\"/ios\\", +- \\"/ios/PlaceholderName\\", +- \\"/ios/PlaceholderName/AppDelegate.m\\", +- \\"/ios/PlaceholderName-tvOS\\", +- \\"/ios/PlaceholderName-tvOS/.gitkeep\\", +- \\"/ios/PlaceholderNameTests\\", +- \\"/ios/PlaceholderNameTests/.gitkeep\\", ++ \\"/ios/ProjectName\\", ++ \\"/ios/ProjectName/AppDelegate.m\\", ++ \\"/ios/ProjectName-tvOS\\", ++ \\"/ios/ProjectName-tvOS/.gitkeep\\", ++ \\"/ios/ProjectNameTests\\", ++ \\"/ios/ProjectNameTests/.gitkeep\\", + \\"/node_modules\\"," +`; diff --git a/packages/cli/src/commands/init/__tests__/editTemplate.test.js b/packages/cli/src/commands/init/__tests__/editTemplate.test.js new file mode 100644 index 0000000000..f59c52abc7 --- /dev/null +++ b/packages/cli/src/commands/init/__tests__/editTemplate.test.js @@ -0,0 +1,85 @@ +// @flow +import os from 'os'; +import path from 'path'; +import fs from 'fs-extra'; +import snapshotDiff from 'snapshot-diff'; +import walk from '../../../tools/walk'; +import copyFiles from '../../../tools/copyFiles'; +import {changePlaceholderInTemplate} from '../editTemplate'; + +const FIXTURE_DIR = path.resolve( + __dirname, + '..', + '__fixtures__', + 'editTemplate', +); +const PLACEHOLDER_NAME = 'PlaceholderName'; +const PROJECT_NAME = 'ProjectName'; + +async function createTestEnv() { + const TEST_DIR = `rncli-should-edit-template-${Date.now()}`; + const tmpDir = os.tmpdir(); + const testPath = path.resolve(tmpDir, TEST_DIR); + + fs.mkdirSync(testPath); + await copyFiles(FIXTURE_DIR, testPath); + + return testPath; +} + +let testPath; + +beforeEach(async () => { + testPath = await createTestEnv(); +}); + +afterEach(() => { + fs.removeSync(testPath); +}); + +test('should edit template', () => { + jest.spyOn(process, 'cwd').mockImplementation(() => testPath); + + changePlaceholderInTemplate(PROJECT_NAME, PLACEHOLDER_NAME); + + const transformedTree = walk(testPath).map(e => e.replace(testPath, '')); + const fixtureTree = walk(FIXTURE_DIR).map(e => e.replace(FIXTURE_DIR, '')); + + const oldJavaFile = fs.readFileSync( + path.resolve( + FIXTURE_DIR, + 'android', + 'com', + PLACEHOLDER_NAME.toLowerCase(), + 'Main.java', + ), + 'utf8', + ); + const newJavaFile = fs.readFileSync( + path.resolve( + testPath, + 'android', + 'com', + PROJECT_NAME.toLowerCase(), + 'Main.java', + ), + 'utf8', + ); + + const oldCFile = fs.readFileSync( + path.resolve(FIXTURE_DIR, 'ios', PLACEHOLDER_NAME, 'AppDelegate.m'), + 'utf8', + ); + const newCFile = fs.readFileSync( + path.resolve(testPath, 'ios', PROJECT_NAME, 'AppDelegate.m'), + 'utf8', + ); + + expect(snapshotDiff(oldCFile, newCFile, {contextLines: 1})).toMatchSnapshot(); + expect( + snapshotDiff(oldJavaFile, newJavaFile, {contextLines: 1}), + ).toMatchSnapshot(); + expect( + snapshotDiff(fixtureTree, transformedTree, {contextLines: 1}), + ).toMatchSnapshot(); +}); diff --git a/packages/cli/src/commands/init/__tests__/template.test.js b/packages/cli/src/commands/init/__tests__/template.test.js new file mode 100644 index 0000000000..fc41fdce08 --- /dev/null +++ b/packages/cli/src/commands/init/__tests__/template.test.js @@ -0,0 +1,97 @@ +// @flow +jest.mock('execa', () => jest.fn()); +import execa from 'execa'; +import path from 'path'; +import * as PackageManger from '../../../tools/packageManager'; +import { + installTemplatePackage, + getTemplateConfig, + copyTemplate, + executePostInitScript, +} from '../template'; +import * as copyFiles from '../../../tools/copyFiles'; + +const TEMPLATE_NAME = 'templateName'; +const TEMPLATE_SOURCE_DIR = '/tmp/rncli-init-template-123456'; + +afterEach(() => { + jest.restoreAllMocks(); + jest.clearAllMocks(); +}); + +test('installTemplatePackage', async () => { + jest.spyOn(PackageManger, 'install').mockImplementationOnce(() => {}); + + await installTemplatePackage(TEMPLATE_NAME, TEMPLATE_SOURCE_DIR, true); + + expect(PackageManger.install).toHaveBeenCalledWith([TEMPLATE_NAME], { + preferYarn: false, + silent: true, + cwd: TEMPLATE_SOURCE_DIR, + }); +}); + +test('getTemplateConfig', () => { + jest.mock( + `${TEMPLATE_SOURCE_DIR}/node_modules/${TEMPLATE_NAME}/template.config`, + () => ({ + placeholderName: 'someName', + templateDir: 'someDir', + }), + { + virtual: true, + }, + ); + jest.spyOn(path, 'resolve').mockImplementationOnce((...e) => e.join('/')); + + expect(getTemplateConfig(TEMPLATE_NAME, TEMPLATE_SOURCE_DIR)).toEqual({ + placeholderName: 'someName', + templateDir: 'someDir', + }); + expect(path.resolve).toHaveBeenCalledWith( + TEMPLATE_SOURCE_DIR, + 'node_modules', + TEMPLATE_NAME, + 'template.config', + ); +}); + +test('copyTemplate', async () => { + const TEMPLATE_DIR = 'some/dir'; + const CWD = '.'; + + jest.spyOn(path, 'resolve').mockImplementationOnce((...e) => e.join('/')); + jest.spyOn(copyFiles, 'default').mockImplementationOnce(() => {}); + jest.spyOn(process, 'cwd').mockImplementationOnce(() => CWD); + + await copyTemplate(TEMPLATE_NAME, TEMPLATE_DIR, TEMPLATE_SOURCE_DIR); + + expect(path.resolve).toHaveBeenCalledWith( + TEMPLATE_SOURCE_DIR, + 'node_modules', + TEMPLATE_NAME, + TEMPLATE_DIR, + ); + expect(copyFiles.default).toHaveBeenCalledWith(expect.any(String), CWD, { + exclude: [expect.any(RegExp)], + }); +}); + +test('executePostInitScript', async () => { + const RESOLVED_PATH = '/some/path/script.js'; + const SCRIPT_PATH = './script.js'; + + jest.spyOn(path, 'resolve').mockImplementationOnce(() => RESOLVED_PATH); + + await executePostInitScript(TEMPLATE_NAME, SCRIPT_PATH, TEMPLATE_SOURCE_DIR); + + expect(path.resolve).toHaveBeenCalledWith( + TEMPLATE_SOURCE_DIR, + 'node_modules', + TEMPLATE_NAME, + SCRIPT_PATH, + ); + expect(execa).toHaveBeenCalledWith(RESOLVED_PATH, { + stdio: 'inherit', + }); +}); diff --git a/packages/cli/src/commands/init/__tests__/templateName.test.js b/packages/cli/src/commands/init/__tests__/templateName.test.js new file mode 100644 index 0000000000..27fc9c44da --- /dev/null +++ b/packages/cli/src/commands/init/__tests__/templateName.test.js @@ -0,0 +1,52 @@ +// @flow +import {processTemplateName} from '../templateName'; +import {fetch} from '../../../tools/fetch'; + +jest.mock('../../../tools/fetch', () => ({fetch: jest.fn()})); + +const RN_NPM_PACKAGE = 'react-native'; +const ABS_RN_PATH = '/path/to/react-native'; + +test('supports file protocol with absolute path', async () => { + jest.mock( + `${ABS_RN_PATH}/package.json`, + () => ({ + name: 'react-native', + }), + {virtual: true}, + ); + expect(await processTemplateName(`file://${ABS_RN_PATH}`)).toEqual({ + uri: ABS_RN_PATH, + name: RN_NPM_PACKAGE, + }); +}); + +test('supports npm packages as template names', async () => { + expect(await processTemplateName(RN_NPM_PACKAGE)).toEqual({ + uri: RN_NPM_PACKAGE, + name: RN_NPM_PACKAGE, + }); +}); + +test.each` + templateName | uri | name + ${'react-native@0.58.0'} | ${'react-native@0.58.0'} | ${'react-native'} + ${'some-name@latest'} | ${'some-name@latest'} | ${'some-name'} + ${'@scoped/name'} | ${'@scoped/name'} | ${'@scoped/name'} + ${'@scoped/name@0.58.0'} | ${'@scoped/name@0.58.0'} | ${'@scoped/name'} + ${'@scoped/name@tag'} | ${'@scoped/name@tag'} | ${'@scoped/name'} +`( + 'supports versioned npm package "$templateName" as template name', + async ({templateName, uri, name}) => { + expect(await processTemplateName(templateName)).toEqual({uri, name}); + }, +); + +test('supports path to tgz archives', async () => { + const ABS_RN_TARBALL_PATH = + '/path/to/react-native/react-native-1.2.3-rc.0.tgz'; + expect(await processTemplateName(`file://${ABS_RN_TARBALL_PATH}`)).toEqual({ + uri: `file://${ABS_RN_TARBALL_PATH}`, + name: 'react-native', + }); +}); diff --git a/packages/cli/src/commands/init/__tests__/validate.test.js b/packages/cli/src/commands/init/__tests__/validate.test.js new file mode 100644 index 0000000000..fda90efcf4 --- /dev/null +++ b/packages/cli/src/commands/init/__tests__/validate.test.js @@ -0,0 +1,28 @@ +// @flow +import {validateProjectName} from '../validate'; +import InvalidNameError from '../errors/InvalidNameError'; +import ReservedNameError from '../errors/ReservedNameError'; + +test.each(['projectName', 'ProjectName', 'project_name'])( + "'%s' project name should be valid", + (name: string) => { + expect(() => validateProjectName(name)).not.toThrowError(); + }, +); + +test.each([ + { + name: 'project-name', + error: InvalidNameError, + }, + { + name: 'React', + error: ReservedNameError, + }, + { + name: 'react', + error: ReservedNameError, + }, +])("'%s' is invalid name", ({name, error}: {name: string, error: Error}) => { + expect(() => validateProjectName(name)).toThrowError(error); +}); diff --git a/packages/cli/src/commands/init/banner.js b/packages/cli/src/commands/init/banner.js new file mode 100644 index 0000000000..bf865302df --- /dev/null +++ b/packages/cli/src/commands/init/banner.js @@ -0,0 +1,43 @@ +// @flow +import chalk from 'chalk'; + +const reactLogoArray = [ + ' ', + ' ###### ###### ', + ' ### #### #### ### ', + ' ## ### ### ## ', + ' ## #### ## ', + ' ## #### ## ', + ' ## ## ## ## ', + ' ## ### ### ## ', + ' ## ######################## ## ', + ' ###### ### ### ###### ', + ' ### ## ## ## ## ### ', + ' ### ## ### #### ### ## ### ', + ' ## #### ######## #### ## ', + ' ## ### ########## ### ## ', + ' ## #### ######## #### ## ', + ' ### ## ### #### ### ## ### ', + ' ### ## ## ## ## ### ', + ' ###### ### ### ###### ', + ' ## ######################## ## ', + ' ## ### ### ## ', + ' ## ## ## ## ', + ' ## #### ## ', + ' ## #### ## ', + ' ## ### ### ## ', + ' ### #### #### ### ', + ' ###### ###### ', + ' ', +]; + +const welcomeMessage = + ' Welcome to React Native! '; +const learnOnceMessage = + ' Learn Once Write Anywhere '; + +export default `${chalk.blue(reactLogoArray.join('\n'))} + +${chalk.yellow.bold(welcomeMessage)} +${chalk.gray(learnOnceMessage)} +`; diff --git a/packages/cli/src/commands/init/editTemplate.js b/packages/cli/src/commands/init/editTemplate.js new file mode 100644 index 0000000000..a72ca07f37 --- /dev/null +++ b/packages/cli/src/commands/init/editTemplate.js @@ -0,0 +1,92 @@ +// @flow +import fs from 'fs'; +import path from 'path'; +import walk from '../../tools/walk'; +import {logger} from '@react-native-community/cli-tools'; + +function replaceNameInUTF8File( + filePath: string, + projectName: string, + templateName: string, +) { + logger.debug(`Replacing in ${filePath}`); + const fileContent = fs.readFileSync(filePath, 'utf8'); + const replacedFileContent = fileContent + .replace(new RegExp(templateName, 'g'), projectName) + .replace( + new RegExp(templateName.toLowerCase(), 'g'), + projectName.toLowerCase(), + ); + + if (fileContent !== replacedFileContent) { + fs.writeFileSync(filePath, replacedFileContent, 'utf8'); + } +} + +function renameFile(filePath: string, oldName: string, newName: string) { + const newFileName = path.join( + path.dirname(filePath), + path.basename(filePath).replace(new RegExp(oldName, 'g'), newName), + ); + + logger.debug(`Renaming ${filePath} -> file:${newFileName}`); + + fs.renameSync(filePath, newFileName); +} + +function shouldRenameFile(filePath: string, nameToReplace: string) { + return path.basename(filePath).includes(nameToReplace); +} + +function shouldIgnoreFile(filePath: string) { + return filePath.match(/node_modules|yarn.lock|package-lock.json/g); +} + +const UNDERSCORED_DOTFILES = [ + 'buckconfig', + 'eslintrc.js', + 'flowconfig', + 'gitattributes', + 'gitignore', + 'watchmanconfig', +]; + +function processDotfiles(filePath: string) { + const dotfile = UNDERSCORED_DOTFILES.find(e => filePath.includes(`_${e}`)); + + if (dotfile === undefined) { + return; + } + + renameFile(filePath, `_${dotfile}`, `.${dotfile}`); +} + +export function changePlaceholderInTemplate( + projectName: string, + placeholderName: string, +) { + logger.debug(`Changing ${placeholderName} for ${projectName} in template`); + + walk(process.cwd()) + .reverse() + .forEach((filePath: string) => { + if (shouldIgnoreFile(filePath)) { + return; + } + if (!fs.statSync(filePath).isDirectory()) { + replaceNameInUTF8File(filePath, projectName, placeholderName); + } + if (shouldRenameFile(filePath, placeholderName)) { + renameFile(filePath, placeholderName, projectName); + } + if (shouldRenameFile(filePath, placeholderName.toLowerCase())) { + renameFile( + filePath, + placeholderName.toLowerCase(), + projectName.toLowerCase(), + ); + } + + processDotfiles(filePath); + }); +} diff --git a/packages/cli/src/commands/init/errors/DirectoryAlreadyExistsError.js b/packages/cli/src/commands/init/errors/DirectoryAlreadyExistsError.js new file mode 100644 index 0000000000..c24352d170 --- /dev/null +++ b/packages/cli/src/commands/init/errors/DirectoryAlreadyExistsError.js @@ -0,0 +1,8 @@ +// @flow +export default class DirectoryAlreadyExistsError extends Error { + constructor(directory: string) { + super( + `Cannot initialize new project because directory "${directory}" already exists.`, + ); + } +} diff --git a/packages/cli/src/commands/init/errors/InvalidNameError.js b/packages/cli/src/commands/init/errors/InvalidNameError.js new file mode 100644 index 0000000000..b7391cd54d --- /dev/null +++ b/packages/cli/src/commands/init/errors/InvalidNameError.js @@ -0,0 +1,8 @@ +// @flow +export default class InvalidNameError extends Error { + constructor(name: string) { + super( + `"${name}" is not a valid name for a project. Please use a valid identifier name (alphanumeric).`, + ); + } +} diff --git a/packages/cli/src/commands/init/errors/ReservedNameError.js b/packages/cli/src/commands/init/errors/ReservedNameError.js new file mode 100644 index 0000000000..6c747caac7 --- /dev/null +++ b/packages/cli/src/commands/init/errors/ReservedNameError.js @@ -0,0 +1,8 @@ +// @flow +export default class ReservedNameError extends Error { + constructor() { + super( + 'Not a valid name for a project. Please do not use the reserved word "React".', + ); + } +} diff --git a/packages/cli/src/commands/init/index.js b/packages/cli/src/commands/init/index.js new file mode 100644 index 0000000000..b80e4f0f5c --- /dev/null +++ b/packages/cli/src/commands/init/index.js @@ -0,0 +1,28 @@ +// @flow +import init from './init'; + +export default { + func: init, + name: 'init ', + description: + 'Initialize a new React Native project named in a directory of the same name.', + options: [ + { + name: '--version [string]', + description: 'Uses a valid semver version of React Native as a template', + }, + { + name: '--template [string]', + description: + 'Uses a custom template. Valid arguments are: npm package, absolute directory prefixed with `file://`, Git repository or a tarball', + }, + { + name: '--npm', + description: 'Forces using npm for initialization', + }, + { + name: '--directory [string]', + description: 'Uses a custom directory instead of ``.', + }, + ], +}; diff --git a/packages/cli/src/commands/init/init.js b/packages/cli/src/commands/init/init.js index c904c4d099..35099c8839 100644 --- a/packages/cli/src/commands/init/init.js +++ b/packages/cli/src/commands/init/init.js @@ -1,116 +1,230 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import fs from 'fs'; -import minimist from 'minimist'; +// @flow +import os from 'os'; import path from 'path'; -import process from 'process'; -import printRunInstructions from '../../tools/generator/printRunInstructions'; -import { createProjectFromTemplate } from '../../tools/generator/templates'; -import PackageManager from '../../tools/PackageManager'; -import logger from '../../tools/logger'; - -/** - * Creates the template for a React Native project given the provided - * parameters: - * @param projectDir Templates will be copied here. - * @param argsOrName Project name or full list of custom arguments - * for the generator. - * @param options Command line options passed from the react-native-cli directly. - * E.g. `{ version: '0.43.0', template: 'navigation' }` - */ -function init(projectDir, argsOrName) { - const args = Array.isArray(argsOrName) - ? argsOrName // argsOrName was e.g. ['AwesomeApp', '--verbose'] - : [argsOrName].concat(process.argv.slice(4)); // argsOrName was e.g. 'AwesomeApp' - - // args array is e.g. ['AwesomeApp', '--verbose', '--template', 'navigation'] - if (!args || args.length === 0) { - logger.error('react-native init requires a project name.'); - return; - } +import fs from 'fs-extra'; +import Ora from 'ora'; +import minimist from 'minimist'; +import semver from 'semver'; +import inquirer from 'inquirer'; +import mkdirp from 'mkdirp'; +import type {ConfigT} from 'types'; +import {validateProjectName} from './validate'; +import DirectoryAlreadyExistsError from './errors/DirectoryAlreadyExistsError'; +import printRunInstructions from './printRunInstructions'; +import {logger} from '@react-native-community/cli-tools'; +import { + installTemplatePackage, + getTemplateConfig, + copyTemplate, + executePostInitScript, +} from './template'; +import {changePlaceholderInTemplate} from './editTemplate'; +import * as PackageManager from '../../tools/packageManager'; +import installPods from '../../tools/installPods'; +import {processTemplateName} from './templateName'; +import banner from './banner'; +import {getLoader} from '../../tools/loader'; +import {CLIError} from '@react-native-community/cli-tools'; - const newProjectName = args[0]; - const options = minimist(args); +const DEFAULT_VERSION = 'latest'; - logger.info(`Setting up new React Native app in ${projectDir}`); - generateProject(projectDir, newProjectName, options); +type Options = {| + template?: string, + npm?: boolean, + directory?: string, +|}; + +function doesDirectoryExist(dir: string) { + return fs.existsSync(dir); } -/** - * Generates a new React Native project based on the template. - * @param Absolute path at which the project folder should be created. - * @param options Command line arguments parsed by minimist. - */ -function generateProject(destinationRoot, newProjectName, options) { - // eslint-disable-next-line import/no-unresolved - const reactNativePackageJson = require('react-native/package.json'); - const { peerDependencies } = reactNativePackageJson; - if (!peerDependencies) { - logger.error( - "Missing React peer dependency in React Native's package.json. Aborting." - ); - return; +function getProjectDirectory({projectName, directory}): string { + return path.relative(process.cwd(), directory || projectName); +} + +async function setProjectDirectory(directory) { + const directoryExists = doesDirectoryExist(directory); + if (directoryExists) { + const {shouldReplaceprojectDirectory} = await inquirer.prompt([ + { + type: 'confirm', + name: 'shouldReplaceprojectDirectory', + message: `Directory "${directory}" already exists, do you want to replace it?`, + default: false, + }, + ]); + + if (!shouldReplaceprojectDirectory) { + throw new DirectoryAlreadyExistsError(directory); + } + + await fs.emptyDir(directory); } - const reactVersion = peerDependencies.react; - if (!reactVersion) { - logger.error( - "Missing React peer dependency in React Native's package.json. Aborting." + try { + mkdirp.sync(directory); + process.chdir(directory); + } catch (error) { + throw new CLIError( + `Error occurred while trying to ${ + directoryExists ? 'replace' : 'create' + } project directory.`, + error, ); - return; } +} - const packageManager = new PackageManager({ - projectDir: destinationRoot, - forceNpm: options.npm, - }); +function adjustNameIfUrl(name, cwd) { + // We use package manager to infer the name of the template module for us. + // That's why we get it from temporary package.json, where the name is the + // first and only dependency (hence 0). + if (name.match(/https?:/)) { + name = Object.keys( + JSON.parse(fs.readFileSync(path.join(cwd, './package.json'), 'utf8')) + .dependencies, + )[0]; + } + return name; +} + +async function createFromTemplate({ + projectName, + templateName, + npm, + directory, +}: { + projectName: string, + templateName: string, + npm?: boolean, + directory: string, +}) { + logger.debug('Initializing new project'); + logger.log(banner); - createProjectFromTemplate( - destinationRoot, - newProjectName, - options.template, - destinationRoot + await setProjectDirectory(directory); + + const Loader = getLoader(); + const loader = new Loader({text: 'Downloading template'}); + const templateSourceDir = fs.mkdtempSync( + path.join(os.tmpdir(), 'rncli-init-template-'), ); - logger.info('Adding required dependencies'); - packageManager.install([`react@${reactVersion}`]); - - logger.info('Adding required dev dependencies'); - packageManager.installDev([ - '@babel/core', - '@babel/runtime', - 'jest', - 'babel-jest', - 'metro-react-native-babel-preset', - `react-test-renderer@${reactVersion}`, - ]); - - addJestToPackageJson(destinationRoot); - printRunInstructions(destinationRoot, newProjectName); + try { + loader.start(); + let {uri, name} = await processTemplateName(templateName); + + await installTemplatePackage(uri, templateSourceDir, npm); + + loader.succeed(); + loader.start('Copying template'); + + name = adjustNameIfUrl(name, templateSourceDir); + const templateConfig = getTemplateConfig(name, templateSourceDir); + await copyTemplate(name, templateConfig.templateDir, templateSourceDir); + + loader.succeed(); + loader.start('Processing template'); + + changePlaceholderInTemplate(projectName, templateConfig.placeholderName); + + loader.succeed(); + const {postInitScript} = templateConfig; + if (postInitScript) { + // Leaving trailing space because there may be stdout from the script + loader.start('Executing post init script '); + await executePostInitScript(name, postInitScript, templateSourceDir); + loader.succeed(); + } + + await installDependencies({projectName, npm, loader}); + } catch (e) { + loader.fail(); + throw new Error(e); + } finally { + fs.removeSync(templateSourceDir); + } } -/** - * Add Jest-related stuff to package.json, which was created by the react-native-cli. - */ -function addJestToPackageJson(destinationRoot) { - const packageJSONPath = path.join(destinationRoot, 'package.json'); - const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath)); - - packageJSON.scripts.test = 'jest'; - packageJSON.jest = { - preset: 'react-native', - }; - fs.writeFileSync( - packageJSONPath, - `${JSON.stringify(packageJSON, null, 2)}\n` - ); +async function installDependencies({ + projectName, + npm, + loader, +}: { + projectName: string, + npm?: boolean, + loader: typeof Ora, +}) { + loader.start('Installing dependencies'); + + await PackageManager.installAll({ + preferYarn: !npm, + silent: true, + }); + + if (process.platform === 'darwin') { + await installPods({projectName, loader}); + } + + loader.succeed(); } -export default init; +async function createProject( + projectName: string, + directory: string, + version: string, + options: Options, +) { + const templateName = options.template || `react-native@${version}`; + + if ( + version !== DEFAULT_VERSION && + semver.valid(version) && + !semver.gte(version, '0.60.0-rc.0') + ) { + throw new Error( + 'Cannot use React Native CLI to initialize project with version lower than 0.60.0.', + ); + } + + return createFromTemplate({ + projectName, + templateName, + npm: options.npm, + directory, + }); +} + +export default (async function initialize( + [projectName]: Array, + context: ConfigT, + options: Options, +) { + const rootFolder = context.root; + + validateProjectName(projectName); + + /** + * Commander is stripping `version` from options automatically. + * We have to use `minimist` to take that directly from `process.argv` + */ + const version: string = minimist(process.argv).version || DEFAULT_VERSION; + + const directoryName = getProjectDirectory({ + projectName, + directory: options.directory || projectName, + }); + const directoryExists = doesDirectoryExist(directoryName); + + try { + await createProject(projectName, directoryName, version, options); + + const projectFolder = path.join(rootFolder, projectName); + printRunInstructions(projectFolder, projectName); + } catch (e) { + logger.error(e.message); + // Only remove project if it didn't exist before running `init` + if (!directoryExists) { + fs.removeSync(path.resolve(rootFolder, directoryName)); + } + } +}); diff --git a/packages/cli/src/commands/init/initCompat.js b/packages/cli/src/commands/init/initCompat.js new file mode 100644 index 0000000000..3116f130bf --- /dev/null +++ b/packages/cli/src/commands/init/initCompat.js @@ -0,0 +1,108 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import fs from 'fs'; +import minimist from 'minimist'; +import path from 'path'; +import process from 'process'; +import printRunInstructions from './printRunInstructions'; +import {createProjectFromTemplate} from '../../tools/generator/templates'; +import * as PackageManager from '../../tools/packageManager'; +import {logger} from '@react-native-community/cli-tools'; +import installPods from '../../tools/installPods'; + +/** + * Creates the template for a React Native project given the provided + * parameters: + * @param projectDir Templates will be copied here. + * @param argsOrName Project name or full list of custom arguments + * for the generator. + * @param options Command line options passed from the react-native-cli directly. + * E.g. `{ version: '0.43.0', template: 'navigation' }` + */ +async function initCompat(projectDir, argsOrName) { + const args = Array.isArray(argsOrName) + ? argsOrName // argsOrName was e.g. ['AwesomeApp', '--verbose'] + : [argsOrName].concat(process.argv.slice(4)); // argsOrName was e.g. 'AwesomeApp' + + // args array is e.g. ['AwesomeApp', '--verbose', '--template', 'navigation'] + if (!args || args.length === 0) { + logger.error('react-native init requires a project name.'); + return; + } + + const newProjectName = args[0]; + const options = minimist(args); + + logger.info(`Setting up new React Native app in ${projectDir}`); + await generateProject(projectDir, newProjectName, options); +} + +/** + * Generates a new React Native project based on the template. + * @param Absolute path at which the project folder should be created. + * @param options Command line arguments parsed by minimist. + */ +async function generateProject(destinationRoot, newProjectName, options) { + const pkgJson = require('react-native/package.json'); + const reactVersion = pkgJson.peerDependencies.react; + + await PackageManager.setProjectDir(destinationRoot); + await createProjectFromTemplate( + destinationRoot, + newProjectName, + options.template, + destinationRoot, + ); + + logger.info('Adding required dependencies'); + await PackageManager.install([`react@${reactVersion}`]); + + logger.info('Adding required dev dependencies'); + await PackageManager.installDev([ + '@babel/core', + '@babel/runtime', + '@react-native-community/eslint-config', + 'eslint', + 'jest', + 'babel-jest', + 'metro-react-native-babel-preset', + `react-test-renderer@${reactVersion}`, + ]); + + addJestToPackageJson(destinationRoot); + + if (process.platform === 'darwin') { + logger.info('Installing required CocoaPods dependencies'); + + await installPods({projectName: newProjectName}); + } + + printRunInstructions(destinationRoot, newProjectName); +} + +/** + * Add Jest-related stuff to package.json, which was created by the react-native-cli. + */ +function addJestToPackageJson(destinationRoot) { + const packageJSONPath = path.join(destinationRoot, 'package.json'); + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath)); + + packageJSON.scripts.test = 'jest'; + packageJSON.scripts.lint = 'eslint .'; + packageJSON.jest = { + preset: 'react-native', + }; + fs.writeFileSync( + packageJSONPath, + `${JSON.stringify(packageJSON, null, 2)}\n`, + ); +} + +export default initCompat; diff --git a/packages/cli/src/tools/generator/printRunInstructions.js b/packages/cli/src/commands/init/printRunInstructions.js similarity index 67% rename from packages/cli/src/tools/generator/printRunInstructions.js rename to packages/cli/src/commands/init/printRunInstructions.js index fa0ab52c5f..8d4b72446b 100644 --- a/packages/cli/src/tools/generator/printRunInstructions.js +++ b/packages/cli/src/commands/init/printRunInstructions.js @@ -9,26 +9,29 @@ */ import path from 'path'; +import fs from 'fs'; import chalk from 'chalk'; -import logger from '../logger'; +import {logger} from '@react-native-community/cli-tools'; function printRunInstructions(projectDir: string, projectName: string) { const absoluteProjectDir = path.resolve(projectDir); - const xcodeProjectPath = `${path.resolve( - projectDir, - 'ios', - projectName - )}.xcodeproj`; + const iosProjectDir = path.resolve(projectDir, 'ios'); + + const iosPodsFile = path.resolve(iosProjectDir, `${projectName}.xcworkspace`); + const isUsingPods = fs.existsSync(iosPodsFile); + const relativeXcodeProjectPath = path.relative( process.cwd(), - xcodeProjectPath + isUsingPods + ? iosPodsFile + : path.resolve(iosProjectDir, `${projectName}.xcodeproj`), ); logger.log(` ${chalk.cyan(`Run instructions for ${chalk.bold('iOS')}`)}: • cd ${absoluteProjectDir} && react-native run-ios - or - - • Open ${relativeXcodeProjectPath} in Xcode + • Open ${relativeXcodeProjectPath} in Xcode or run "xed -b ios" • Hit the Run button ${chalk.green(`Run instructions for ${chalk.bold('Android')}`)}: diff --git a/packages/cli/src/commands/init/template.js b/packages/cli/src/commands/init/template.js new file mode 100644 index 0000000000..918a40be6d --- /dev/null +++ b/packages/cli/src/commands/init/template.js @@ -0,0 +1,77 @@ +// @flow +import execa from 'execa'; +import path from 'path'; +import * as PackageManager from '../../tools/packageManager'; +import {logger} from '@react-native-community/cli-tools'; +import copyFiles from '../../tools/copyFiles'; + +export type TemplateConfig = { + placeholderName: string, + templateDir: string, + postInitScript?: string, +}; + +export function installTemplatePackage( + templateName: string, + cwd: string, + npm?: boolean, +) { + logger.debug(`Installing template from ${templateName}`); + return PackageManager.install([templateName], { + preferYarn: !npm, + silent: true, + cwd, + }); +} + +export function getTemplateConfig( + templateName: string, + templateSourceDir: string, +): TemplateConfig { + const configFilePath = path.resolve( + templateSourceDir, + 'node_modules', + templateName, + 'template.config', + ); + + logger.debug(`Getting config from ${configFilePath}.js`); + + return require(configFilePath); +} + +export async function copyTemplate( + templateName: string, + templateDir: string, + templateSourceDir: string, +) { + const templatePath = path.resolve( + templateSourceDir, + 'node_modules', + templateName, + templateDir, + ); + + logger.debug(`Copying template from ${templatePath}`); + + await copyFiles(templatePath, process.cwd(), { + exclude: [new RegExp(path.resolve(templatePath, 'node_modules'))], + }); +} + +export function executePostInitScript( + templateName: string, + postInitScript: string, + templateSourceDir: string, +) { + const scriptPath = path.resolve( + templateSourceDir, + 'node_modules', + templateName, + postInitScript, + ); + + logger.debug(`Executing post init script located ${scriptPath}`); + + return execa(scriptPath, {stdio: 'inherit'}); +} diff --git a/packages/cli/src/commands/init/templateName.js b/packages/cli/src/commands/init/templateName.js new file mode 100644 index 0000000000..42ff684a92 --- /dev/null +++ b/packages/cli/src/commands/init/templateName.js @@ -0,0 +1,64 @@ +// @flow +import path from 'path'; +import {URL} from 'url'; +import {fetch} from '../../tools/fetch'; + +const FILE_PROTOCOL = /file:/; +const HTTP_PROTOCOL = /https?:/; +const TARBALL = /\.tgz$/; +const VERSION_POSTFIX = /(.*)(-\d+\.\d+\.\d+)/; +const VERSIONED_PACKAGE = /(@?.+)(@)(.+)/; + +function handleFileProtocol(filePath: string) { + const uri = new URL(filePath).pathname; + + return { + uri, + name: require(path.join(uri, 'package.json')).name, + }; +} + +function handleTarball(filePath: string) { + const nameWithVersion = path.parse(path.basename(filePath)).name; + const tarballVersionMatch = nameWithVersion.match(VERSION_POSTFIX); + if (!tarballVersionMatch) { + throw new Error( + `Failed to retrieve tarball name. We expect the tarball to include package name and version, e.g.: "template-name-1.2.3-rc.0.tgz", but received: "${nameWithVersion}".`, + ); + } + + return { + uri: filePath, + name: tarballVersionMatch[1], + }; +} + +function handleVersionedPackage(versionedPackage: string) { + const versionedPackageMatch = versionedPackage.match(VERSIONED_PACKAGE); + if (!versionedPackageMatch) { + throw new Error( + `Failed to retrieve package name. We expect the package to include name and version, e.g.: "template-name@1.2.3-rc.0", but received: "${versionedPackage}".`, + ); + } + return { + uri: versionedPackage, + name: versionedPackageMatch[1], + }; +} + +export async function processTemplateName(templateName: string) { + if (templateName.match(TARBALL)) { + return handleTarball(templateName); + } + if (templateName.match(FILE_PROTOCOL)) { + return handleFileProtocol(templateName); + } + if (templateName.match(VERSIONED_PACKAGE)) { + return handleVersionedPackage(templateName); + } + + return { + uri: templateName, + name: templateName, + }; +} diff --git a/packages/cli/src/commands/init/validate.js b/packages/cli/src/commands/init/validate.js new file mode 100644 index 0000000000..9166c40267 --- /dev/null +++ b/packages/cli/src/commands/init/validate.js @@ -0,0 +1,15 @@ +// @flow +import InvalidNameError from './errors/InvalidNameError'; +import ReservedNameError from './errors/ReservedNameError'; + +const NAME_REGEX = /^[$A-Z_][0-9A-Z_$]*$/i; + +export function validateProjectName(name: string) { + if (!String(name).match(NAME_REGEX)) { + throw new InvalidNameError(name); + } + + if (name === 'React' || name === 'react') { + throw new ReservedNameError(); + } +} diff --git a/packages/cli/src/commands/install/install.js b/packages/cli/src/commands/install/install.js index ce575841e6..a15072ed18 100644 --- a/packages/cli/src/commands/install/install.js +++ b/packages/cli/src/commands/install/install.js @@ -7,20 +7,23 @@ * @flow */ -import type { ContextT } from '../../tools/types.flow'; -import logger from '../../tools/logger'; -import PackageManager from '../../tools/PackageManager'; +import type {ConfigT} from 'types'; +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}"...`); - new PackageManager({ projectDir: ctx.root }).install([name]); + await PackageManager.install([name]); + + // Reload configuration to see newly installed dependency + const newConfig = loadConfig(); logger.info(`Linking "${name}"...`); - // eslint-disable-next-line import/no-named-as-default-member - await link.func([name], ctx, { platforms: undefined }); + await link.func([name], newConfig, {platforms: undefined}); logger.success(`Successfully installed and linked "${name}"`); } diff --git a/packages/cli/src/commands/install/uninstall.js b/packages/cli/src/commands/install/uninstall.js index fb10f4754c..be22269c99 100644 --- a/packages/cli/src/commands/install/uninstall.js +++ b/packages/cli/src/commands/install/uninstall.js @@ -7,19 +7,19 @@ * @flow */ -import type { ContextT } from '../../tools/types.flow'; -import logger from '../../tools/logger'; -import PackageManager from '../../tools/PackageManager'; -import link from '../link/unlink'; +import type {ConfigT} from 'types'; +import {logger} from '@react-native-community/cli-tools'; +import * as PackageManager from '../../tools/packageManager'; +import unlink 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}"...`); - await link.func([name], ctx); + await unlink.func([name], ctx, {}); logger.info(`Uninstalling "${name}"...`); - new PackageManager({ projectDir: ctx.root }).uninstall([name]); + await PackageManager.uninstall([name]); logger.success(`Successfully uninstalled and unlinked "${name}"`); } diff --git a/packages/cli/src/commands/library/library.js b/packages/cli/src/commands/library/library.js deleted file mode 100644 index f98978f002..0000000000 --- a/packages/cli/src/commands/library/library.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import fs from 'fs'; -import path from 'path'; -import copyAndReplace from '../../tools/copyAndReplace'; -import isValidPackageName from '../../tools/isValidPackageName'; -import walk from '../../tools/walk'; -import logger from '../../tools/logger'; - -/** - * Creates a new native library with the given name - */ -async function library(argv, ctx, args) { - if (!isValidPackageName(args.name)) { - throw new Error( - `${args.name} is not a valid name for a project. Please use a valid ` + - `identifier name (alphanumeric).` - ); - } - - const libraries = path.resolve(ctx.root, 'Libraries'); - const libraryDest = path.resolve(libraries, args.name); - const source = path.resolve( - 'node_modules', - 'react-native', - 'Libraries', - 'Sample' - ); - - if (!fs.existsSync(libraries)) { - fs.mkdirSync(libraries); - } - - if (fs.existsSync(libraryDest)) { - throw new Error(`Library already exists in ${libraryDest}`); - } - - walk(source).forEach(f => { - if ( - f.indexOf('project.xcworkspace') !== -1 || - f.indexOf('.xcodeproj/xcuserdata') !== -1 - ) { - return; - } - - const dest = path.relative( - source, - f.replace(/Sample/g, args.name).replace(/^_/, '.') - ); - copyAndReplace(path.resolve(source, f), path.resolve(libraryDest, dest), { - Sample: args.name, - }); - }); - - logger.info(`Created library in ${libraryDest}. -Now it needs to be linked in Xcode: -https://facebook.github.io/react-native/docs/linking-libraries-ios.html#content`); -} - -export default { - name: 'new-library', - func: library, - description: 'generates a native library bridge', - options: [ - { - command: '--name ', - description: 'name of the library to generate', - default: null, - }, - ], -}; diff --git a/packages/cli/src/commands/link/__fixtures__/android/0.17/MainActivity.java b/packages/cli/src/commands/link/__fixtures__/android/0.17/MainActivity.java deleted file mode 100644 index d0794b72b8..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/0.17/MainActivity.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.basic; - -import android.app.Activity; -import android.os.Bundle; -import android.view.KeyEvent; - -import com.facebook.react.LifecycleState; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactRootView; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; - -public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { - - private ReactInstanceManager mReactInstanceManager; - private ReactRootView mReactRootView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mReactRootView = new ReactRootView(this); - - mReactInstanceManager = ReactInstanceManager.builder() - .setApplication(getApplication()) - .setBundleAssetName("index.android.bundle") - .setJSMainModuleName("index.android") - .addPackage(new MainReactPackage()) - .setUseDeveloperSupport(BuildConfig.DEBUG) - .setInitialLifecycleState(LifecycleState.RESUMED) - .build(); - - mReactRootView.startReactApplication(mReactInstanceManager, "Basic", null); - - setContentView(mReactRootView); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { - mReactInstanceManager.showDevOptionsDialog(); - return true; - } - return super.onKeyUp(keyCode, event); - } - - @Override - public void onBackPressed() { - if (mReactInstanceManager != null) { - mReactInstanceManager.onBackPressed(); - } else { - super.onBackPressed(); - } - } - - @Override - public void invokeDefaultOnBackPressed() { - super.onBackPressed(); - } - - @Override - protected void onPause() { - super.onPause(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onPause(); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onResume(this, this); - } - } -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/0.17/patchedMainActivity.java b/packages/cli/src/commands/link/__fixtures__/android/0.17/patchedMainActivity.java deleted file mode 100644 index 17c2b278d5..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/0.17/patchedMainActivity.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.basic; - -import android.app.Activity; -import com.oblador.vectoricons.VectorIconsPackage; -import android.os.Bundle; -import android.view.KeyEvent; - -import com.facebook.react.LifecycleState; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactRootView; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; - -public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { - - private ReactInstanceManager mReactInstanceManager; - private ReactRootView mReactRootView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mReactRootView = new ReactRootView(this); - - mReactInstanceManager = ReactInstanceManager.builder() - .setApplication(getApplication()) - .setBundleAssetName("index.android.bundle") - .setJSMainModuleName("index.android") - .addPackage(new MainReactPackage()) - .addPackage(new VectorIconsPackage()) - .setUseDeveloperSupport(BuildConfig.DEBUG) - .setInitialLifecycleState(LifecycleState.RESUMED) - .build(); - - mReactRootView.startReactApplication(mReactInstanceManager, "Basic", null); - - setContentView(mReactRootView); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { - mReactInstanceManager.showDevOptionsDialog(); - return true; - } - return super.onKeyUp(keyCode, event); - } - - @Override - public void onBackPressed() { - if (mReactInstanceManager != null) { - mReactInstanceManager.onBackPressed(); - } else { - super.onBackPressed(); - } - } - - @Override - public void invokeDefaultOnBackPressed() { - super.onBackPressed(); - } - - @Override - protected void onPause() { - super.onPause(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onPause(); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onResume(this, this); - } - } -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/0.18/MainActivity.java b/packages/cli/src/commands/link/__fixtures__/android/0.18/MainActivity.java deleted file mode 100644 index c630627442..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/0.18/MainActivity.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.testrn; - -import com.facebook.react.ReactActivity; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; - -import java.util.Arrays; -import java.util.List; - -public class MainActivity extends ReactActivity { - - /** - * Returns the name of the main component registered from JavaScript. - * This is used to schedule rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "TestRN"; - } - - /** - * Returns whether dev mode should be enabled. - * This enables e.g. the dev menu. - */ - @Override - protected boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - /** - * A list of packages used by the app. If the app uses additional views - * or modules besides the default ones, add more packages here. - */ - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage()); - } -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/0.18/patchedMainActivity.java b/packages/cli/src/commands/link/__fixtures__/android/0.18/patchedMainActivity.java deleted file mode 100644 index b099735c41..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/0.18/patchedMainActivity.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.testrn; - -import com.facebook.react.ReactActivity; -import com.oblador.vectoricons.VectorIconsPackage; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; - -import java.util.Arrays; -import java.util.List; - -public class MainActivity extends ReactActivity { - - /** - * Returns the name of the main component registered from JavaScript. - * This is used to schedule rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "TestRN"; - } - - /** - * Returns whether dev mode should be enabled. - * This enables e.g. the dev menu. - */ - @Override - protected boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - /** - * A list of packages used by the app. If the app uses additional views - * or modules besides the default ones, add more packages here. - */ - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new VectorIconsPackage()); - } -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/0.20/MainActivity.java b/packages/cli/src/commands/link/__fixtures__/android/0.20/MainActivity.java deleted file mode 100644 index 642f4259c1..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/0.20/MainActivity.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.myawesomeproject; - -import com.facebook.react.ReactActivity; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; - -import java.util.Arrays; -import java.util.List; - -public class MainActivity extends ReactActivity { - - /** - * Returns the name of the main component registered from JavaScript. - * This is used to schedule rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "TestRN"; - } - - /** - * Returns whether dev mode should be enabled. - * This enables e.g. the dev menu. - */ - @Override - protected boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - /** - * A list of packages used by the app. If the app uses additional views - * or modules besides the default ones, add more packages here. - */ - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage() - ); - } -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/build.gradle b/packages/cli/src/commands/link/__fixtures__/android/build.gradle deleted file mode 100644 index f206d053ec..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation "com.android.support:appcompat-v7:27.1.1" - implementation "com.facebook.react:react-native:+" -} diff --git a/packages/cli/src/commands/link/__fixtures__/android/patchedSettings.gradle b/packages/cli/src/commands/link/__fixtures__/android/patchedSettings.gradle deleted file mode 100644 index 2b311263ad..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/patchedSettings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -rootProject.name = 'TestRN' - -include ':app' -include ':test' -project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/test/android') diff --git a/packages/cli/src/commands/link/__fixtures__/android/settings.gradle b/packages/cli/src/commands/link/__fixtures__/android/settings.gradle deleted file mode 100644 index 5bb3d945cc..0000000000 --- a/packages/cli/src/commands/link/__fixtures__/android/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -rootProject.name = 'TestRN' - -include ':app' diff --git a/packages/cli/src/commands/link/__tests__/__snapshots__/getDependencyConfig-test.js.snap b/packages/cli/src/commands/link/__tests__/__snapshots__/getDependencyConfig-test.js.snap deleted file mode 100644 index 9fc3eecc93..0000000000 --- a/packages/cli/src/commands/link/__tests__/__snapshots__/getDependencyConfig-test.js.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`getDependencyConfig should return an array of dependencies' config 1`] = ` -Object { - "assets": Array [], - "commands": Object {}, - "config": Object { - "android": Object { - "sampleAndroidKey": "", - }, - "ios": Object { - "sampleiOSKey": "", - }, - }, - "name": "react-native-windows", - "params": Array [], - "path": "/root/node_modules/react-native-windows", -} -`; diff --git a/packages/cli/src/commands/link/__tests__/getDependencyConfig-test.js b/packages/cli/src/commands/link/__tests__/getDependencyConfig-test.js deleted file mode 100644 index 26f8eb4c1c..0000000000 --- a/packages/cli/src/commands/link/__tests__/getDependencyConfig-test.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -const platforms = { - ios: { - dependencyConfig: () => ({ sampleiOSKey: '' }), - }, - android: { - dependencyConfig: () => ({ sampleAndroidKey: '' }), - }, -}; - -jest.setMock('../../../tools/getPackageConfiguration', folder => { - if (folder === '/root/node_modules/abcd') { - throw new Error('Cannot require'); - } - return {}; -}); - -const getDependencyConfig = require('../getDependencyConfig').default; - -describe('getDependencyConfig', () => { - it("should return an array of dependencies' config", () => { - const dependencies = getDependencyConfig( - { root: '/root' }, - platforms, - 'react-native-windows' - ); - - expect(dependencies).toMatchSnapshot(); - }); - - it('should throw on invalid react-native dependency', () => { - expect(() => - getDependencyConfig({ root: '/root' }, platforms, 'abcd') - ).toThrowError(); - }); -}); diff --git a/packages/cli/src/commands/link/__tests__/getProjectDependencies-test.js b/packages/cli/src/commands/link/__tests__/getProjectDependencies-test.js deleted file mode 100644 index d1892eaf8b..0000000000 --- a/packages/cli/src/commands/link/__tests__/getProjectDependencies-test.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - * @format - */ - -import getProjectDependencies from '../getProjectDependencies'; - -const path = require('path'); - -const CWD = path.resolve(__dirname, '../../'); - -describe('getProjectDependencies', () => { - beforeEach(() => { - jest.resetModules(); - }); - it('should return an array of project dependencies', () => { - jest.doMock( - path.join(CWD, './package.json'), - () => ({ - dependencies: { - lodash: '^6.0.0', - 'react-native': '^16.0.0', - '@react-native-community/cli': '*', - }, - }), - { virtual: true } - ); - - expect(getProjectDependencies(CWD)).toEqual(['lodash']); - }); - - it('should return an empty array when no dependencies set', () => { - jest.doMock(path.join(CWD, './package.json'), () => ({}), { - virtual: true, - }); - expect(getProjectDependencies(CWD)).toEqual([]); - }); -}); diff --git a/packages/cli/src/commands/link/__tests__/link-test.js b/packages/cli/src/commands/link/__tests__/link-test.js index d8f2560dcd..02c537344b 100644 --- a/packages/cli/src/commands/link/__tests__/link-test.js +++ b/packages/cli/src/commands/link/__tests__/link-test.js @@ -1,18 +1,24 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ +import {func as link} from '../link'; +import loadConfig from '../../../tools/config'; +import makeHook from '../makeHook'; -jest.mock('chalk', () => ({ grey: str => str })); +jest.mock('chalk', () => ({grey: str => str, bold: str => str})); +jest.mock('../../../tools/config'); jest.mock('../../../tools/logger'); +jest.mock('../makeHook', () => { + return jest.fn(() => { + return jest.fn(() => Promise.resolve()); + }); +}); + +const baseConfig = loadConfig(); -const context = { - root: process.cwd(), +const baseDependencyConfig = { + name: 'react-native-gradient', + assets: [], + hooks: {}, + params: [], + platforms: {ios: {}, android: {}}, }; describe('link', () => { @@ -20,304 +26,234 @@ describe('link', () => { jest.resetModules(); }); - it('should reject when run in a folder without package.json', done => { - const link = require('../link').func; - link([], { root: '/' }, {}).catch(() => done()); - }); - - it('should accept a name of a dependency to link', done => { - const getDependencyConfig = jest.fn(() => ({ - config: { - ios: null, - android: null, + it('should accept a name of a dependency to link', async () => { + const config = { + ...baseConfig, + dependencies: { + get ['react-native-gradient']() { + return baseDependencyConfig; + }, }, - assets: [], - commands: {}, - })); + }; - jest.doMock('../getDependencyConfig', () => getDependencyConfig); + const spy = jest.spyOn(config.dependencies, 'react-native-gradient', 'get'); - const link = require('../link').func; - link(['react-native-gradient'], context, {}).then(() => { - expect(getDependencyConfig.mock.calls[0][2]).toEqual( - 'react-native-gradient' - ); - done(); - }); + await link(['react-native-gradient'], config, {}); + + expect(spy).toHaveBeenCalled(); }); it('should accept the name of a dependency with a scope / tag', async () => { - const getDependencyConfig = jest.fn(() => ({ - config: { - ios: null, - android: null, + const config = { + ...baseConfig, + dependencies: { + get ['@scope/something']() { + return baseDependencyConfig; + }, }, - assets: [], - commands: {}, - })); + }; - jest.doMock('../getDependencyConfig', () => getDependencyConfig); + const spy = jest.spyOn(config.dependencies, '@scope/something', 'get'); - const link = require('../link').func; - await link(['@scope/something@latest'], context, {}); + await link(['@scope/something@latest'], config, {}); - expect(getDependencyConfig.mock.calls[0][2]).toEqual('@scope/something'); + expect(spy).toHaveBeenCalled(); }); - it('should register native module when android/ios projects are present', done => { - const prelink = jest.fn().mockImplementation(cb => cb()); - const postlink = jest.fn().mockImplementation(cb => cb()); - - jest.doMock('../getProjectConfig', () => () => ({ - ios: {}, - android: {}, - })); + it('should register native module when android/ios projects are present', async () => { + const prelink = 'node prelink.js'; + const postlink = 'node postlink.js'; + const registerNativeModule = jest.fn(); - const getDependencyConfig = jest.fn(() => ({ - config: { + const config = { + ...baseConfig, + project: { ios: {}, android: {}, }, - assets: [], - commands: { prelink, postlink }, - })); - - jest.doMock('../getDependencyConfig', () => getDependencyConfig); - - const registerNativeModule = jest.fn(); - - jest.doMock('../android/isInstalled.js', () => - jest.fn().mockReturnValue(false) - ); - jest.doMock( - '../android/registerNativeModule.js', - () => registerNativeModule - ); - - jest.doMock('../ios/isInstalled.js', () => - jest.fn().mockReturnValue(false) - ); - jest.doMock('../ios/registerNativeModule.js', () => registerNativeModule); - - const link = require('../link').func; - registerNativeModule.mockClear(); - - link(['react-native-blur'], context, {}).then(() => { - expect(registerNativeModule.mock.calls).toHaveLength(2); - - expect(prelink.mock.invocationCallOrder[0]).toBeLessThan( - registerNativeModule.mock.invocationCallOrder[0] - ); - - expect(postlink.mock.invocationCallOrder[0]).toBeGreaterThan( - registerNativeModule.mock.invocationCallOrder[0] - ); + platforms: { + ios: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + android: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + }, + dependencies: { + 'react-native-blur': { + ...baseDependencyConfig, + hooks: {prelink, postlink}, + }, + }, + }; - done(); - }); + await link(['react-native-blur'], config, {}); + expect(registerNativeModule.mock.calls).toHaveLength(2); + expect(makeHook.mock.calls).toEqual([[prelink], [postlink]]); }); it('should copy assets only from the specific dependency that we are linking', done => { const dependencyAssets = ['Fonts/Font.ttf']; const projectAssets = ['Fonts/FontC.ttf']; - jest.doMock('../getProjectConfig', () => () => ({ - ios: {}, - android: {}, - })); + const copyAssets = jest.fn(); + const dependency = { + ...baseDependencyConfig, + assets: dependencyAssets, + }; - jest.doMock('../getDependencyConfig', () => () => ({ - config: { + const config = { + ...baseConfig, + project: { ios: {}, android: {}, }, - assets: dependencyAssets, - commands: {}, - })); - - jest.doMock('../android/isInstalled.js', () => - jest.fn().mockReturnValue(false) - ); - jest.doMock('../android/registerNativeModule.js', () => jest.fn()); - - jest.doMock('../ios/isInstalled.js', () => - jest.fn().mockReturnValue(false) - ); - jest.doMock('../ios/registerNativeModule.js', () => jest.fn()); - - jest.doMock('../../../tools/getAssets', () => projectAssets); - - const copyAssets = jest.fn(); - - jest.doMock('../ios/copyAssets.js', () => copyAssets); - jest.doMock('../android/copyAssets.js', () => copyAssets); - - const link = require('../link').func; + platforms: { + ios: { + linkConfig: () => ({ + register: jest.fn(), + copyAssets, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + android: { + linkConfig: () => ({ + register: jest.fn(), + copyAssets, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + }, + dependencies: { + 'react-native-blur': dependency, + }, + assets: projectAssets, + }; - link(['react-native-blur'], context, {}).then(() => { + link(['react-native-blur'], config, {}).then(() => { expect(copyAssets.mock.calls).toHaveLength(2); expect(copyAssets.mock.calls[0][0]).toEqual(dependencyAssets); - jest.unmock('../../../tools/getAssets'); done(); }); }); it('should not register modules when they are already installed', done => { - jest.doMock('../getProjectConfig', () => () => ({ - ios: {}, - android: {}, - })); + const registerNativeModule = jest.fn(); - const getDependencyConfig = jest.fn(() => ({ - config: { + const config = { + ...baseConfig, + project: { ios: {}, android: {}, }, - assets: [], - commands: {}, - })); - - jest.doMock('../getDependencyConfig', () => getDependencyConfig); - - const registerNativeModule = jest.fn(); - - jest.doMock('../android/isInstalled.js', () => - jest.fn().mockReturnValue(true) - ); - jest.doMock( - '../android/registerNativeModule.js', - () => registerNativeModule - ); - - jest.doMock('../ios/isInstalled.js', () => jest.fn().mockReturnValue(true)); - jest.doMock('../ios/registerNativeModule.js', () => registerNativeModule); - - const link = require('../link').func; + platforms: { + ios: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(true), + }), + }, + android: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(true), + }), + }, + }, + dependencies: { + 'react-native-blur': baseDependencyConfig, + }, + }; - link(['react-native-blur', {}], context, {}).then(() => { + link(['react-native-blur'], config, {}).then(() => { expect(registerNativeModule.mock.calls).toHaveLength(0); done(); }); }); it('should register native modules for additional platforms', done => { - jest.doMock('../getProjectConfig', () => () => ({ - ios: {}, - android: {}, - windows: {}, - })); - const registerNativeModule = jest.fn(); - const genericLinkConfig = () => ({ - isInstalled: () => false, - register: registerNativeModule, - }); - - const getDependencyConfig = jest.fn(() => ({ - config: { + const config = { + ...baseConfig, + project: { ios: {}, android: {}, windows: {}, }, - assets: [], - commands: {}, - })); - - jest.doMock('../../../tools/getPlatforms', () => { - const fn = () => ({ - ios: { linkConfig: require('../ios').default }, - android: { linkConfig: require('../android').default }, - windows: { linkConfig: genericLinkConfig }, - }); - fn.getPlatformName = jest.fn(); - return fn; - }); - - jest.doMock('../getDependencyConfig', () => getDependencyConfig); - - jest.doMock('../android/isInstalled.js', () => - jest.fn().mockReturnValue(true) - ); - jest.doMock( - '../android/registerNativeModule.js', - () => registerNativeModule - ); - - jest.doMock('../ios/isInstalled.js', () => jest.fn().mockReturnValue(true)); - jest.doMock('../ios/registerNativeModule.js', () => registerNativeModule); + platforms: { + ios: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(true), + }), + }, + android: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(true), + }), + }, + windows: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + }, + dependencies: { + 'react-native-blur': { + ...baseDependencyConfig, + platforms: { + ...baseDependencyConfig.platforms, + windows: {}, + }, + }, + }, + }; - const link = require('../link').func; - link(['react-native-blur'], context, {}).then(() => { + link(['react-native-blur'], config, {}).then(() => { expect(registerNativeModule.mock.calls).toHaveLength(1); done(); }); }); it('should link only for specific platforms if --platforms is used', async () => { - jest.doMock('../getProjectDependencies', () => () => ['react-native-maps']); - jest.doMock('../../../tools/getPackageConfiguration', () => () => ({ - assets: [], - })); - - const registerAndroidNativeModule = jest.fn(); - const registerIOSNativeModule = jest.fn(); - - const genericAndroidLinkConfig = () => ({ - isInstalled: () => false, - register: registerAndroidNativeModule, - }); - - const genericIOSLinkConfig = () => ({ - isInstalled: () => false, - register: registerIOSNativeModule, - }); - - jest.doMock('../../../tools/getPlatforms', () => { - const fn = () => ({ - android: { linkConfig: genericAndroidLinkConfig }, - ios: { linkConfig: genericIOSLinkConfig }, - }); - fn.getPlatformName = jest.fn(); - return fn; - }); - - jest.doMock( - '../android/registerNativeModule.js', - () => registerAndroidNativeModule - ); - jest.doMock( - '../ios/registerNativeModule.js', - () => registerIOSNativeModule - ); + const registerNativeModule = jest.fn(); - const link = require('../link').func; - const assertPlaftormsCalledTimes = (android, ios) => { - expect(registerAndroidNativeModule).toHaveBeenCalledTimes(android); - expect(registerIOSNativeModule).toHaveBeenCalledTimes(ios); - registerAndroidNativeModule.mockClear(); - registerIOSNativeModule.mockClear(); + const config = { + ...baseConfig, + project: { + ios: {}, + android: {}, + }, + platforms: { + ios: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + android: { + linkConfig: () => ({ + register: registerNativeModule, + isInstalled: jest.fn().mockReturnValue(false), + }), + }, + }, + dependencies: { + 'react-native-blur': baseDependencyConfig, + }, }; - await link( - ['react-native-gradient'], - { root: '/' }, - { platforms: ['android'] } - ); - assertPlaftormsCalledTimes(1, 0); - - await link( - ['react-native-gradient'], - { root: '/' }, - { platforms: ['ios'] } - ); - assertPlaftormsCalledTimes(0, 1); + await link(['react-native-blur'], config, {platforms: ['android']}); - await link( - ['react-native-gradient'], - { root: '/' }, - { platforms: ['android', 'ios'] } - ); - assertPlaftormsCalledTimes(1, 1); + expect(registerNativeModule.mock.calls).toHaveLength(1); }); }); diff --git a/packages/cli/src/commands/link/__tests__/makeHook-test.js b/packages/cli/src/commands/link/__tests__/makeHook-test.js new file mode 100644 index 0000000000..6114c1b713 --- /dev/null +++ b/packages/cli/src/commands/link/__tests__/makeHook-test.js @@ -0,0 +1,24 @@ +/** + * @flow + */ +import makeHook from '../makeHook'; + +afterAll(() => { + jest.restoreAllMocks(); +}); + +describe('makeHook', () => { + it('invokes the command', async () => { + const hook = makeHook('echo'); + // $FlowFixMe - execa weird Promise-like return value + const result = await hook(); + expect(result.cmd).toBe('echo'); + }); + + it('invokes the command with multiple arguments', async () => { + const hook = makeHook('node -p "1;"'); + // $FlowFixMe - execa weird Promise-like return value + const result = await hook(); + expect(result.cmd).toBe('node -p "1;"'); + }); +}); diff --git a/packages/cli/src/commands/link/__tests__/promiseWaterfall-test.js b/packages/cli/src/commands/link/__tests__/promiseWaterfall-test.js deleted file mode 100644 index 1056989c09..0000000000 --- a/packages/cli/src/commands/link/__tests__/promiseWaterfall-test.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -import promiseWaterfall from '../promiseWaterfall'; - -describe('promiseWaterfall', () => { - it('should run promises in a sequence', async () => { - const tasks = [jest.fn(), jest.fn()]; - - await promiseWaterfall(tasks); - - // Check that tasks[0] is executed before tasks[1]. - expect(tasks[0].mock.invocationCallOrder[0]).toBeLessThan( - tasks[1].mock.invocationCallOrder[0] - ); - }); - - it('should resolve with last promise value', async () => { - const tasks = [jest.fn().mockReturnValue(1), jest.fn().mockReturnValue(2)]; - - expect(await promiseWaterfall(tasks)).toEqual(2); - }); - - it('should stop the sequence when one of promises is rejected', done => { - const error = new Error(); - const tasks = [ - jest.fn().mockImplementation(() => { - throw error; - }), - jest.fn().mockReturnValue(2), - ]; - - promiseWaterfall(tasks).catch(err => { - expect(err).toEqual(error); - expect(tasks[1].mock.calls).toHaveLength(0); - done(); - }); - }); -}); diff --git a/packages/cli/src/commands/link/android/copyAssets.js b/packages/cli/src/commands/link/android/copyAssets.js deleted file mode 100644 index 08d184d1c4..0000000000 --- a/packages/cli/src/commands/link/android/copyAssets.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import fs from 'fs-extra'; -import path from 'path'; -import groupFilesByType from '../groupFilesByType'; - -/** - * Copies each file from an array of assets provided to targetPath directory - * - * For now, the only types of files that are handled are: - * - Fonts (otf, ttf) - copied to targetPath/fonts under original name - */ -export default function copyAssetsAndroid(files, project) { - const assets = groupFilesByType(files); - - (assets.font || []).forEach(asset => - fs.copySync( - asset, - path.join(project.assetsPath, 'fonts', path.basename(asset)) - ) - ); -} diff --git a/packages/cli/src/commands/link/android/fs.js b/packages/cli/src/commands/link/android/fs.js deleted file mode 100644 index 26ecbdae0b..0000000000 --- a/packages/cli/src/commands/link/android/fs.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import fs from 'fs-extra'; - -exports.readFile = file => () => fs.readFileSync(file, 'utf8'); - -exports.writeFile = (file, content) => - content - ? fs.writeFileSync(file, content, 'utf8') - : c => fs.writeFileSync(file, c, 'utf8'); diff --git a/packages/cli/src/commands/link/android/patches/makeBuildPatch.js b/packages/cli/src/commands/link/android/patches/makeBuildPatch.js deleted file mode 100644 index 9bdf224474..0000000000 --- a/packages/cli/src/commands/link/android/patches/makeBuildPatch.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import normalizeProjectName from './normalizeProjectName'; - -export default function makeBuildPatch(name) { - const normalizedProjectName = normalizeProjectName(name); - const installPattern = new RegExp( - `(implementation|api|compile)\\w*\\s*\\(*project\\(['"]:${normalizedProjectName}['"]\\)` - ); - - return { - installPattern, - pattern: /[^ \t]dependencies {(\r\n|\n)/, - patch: ` implementation project(':${normalizedProjectName}')\n`, - }; -} diff --git a/packages/cli/src/commands/link/getDependencyConfig.js b/packages/cli/src/commands/link/getDependencyConfig.js deleted file mode 100644 index 0588c4036d..0000000000 --- a/packages/cli/src/commands/link/getDependencyConfig.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @flow - */ - -import path from 'path'; -import type { - PlatformsT, - ContextT, - DependenciesConfig, -} from '../../tools/types.flow'; - -import getPackageConfiguration from '../../tools/getPackageConfiguration'; -import getParams from '../../tools/getParams'; -import getHooks from '../../tools/getHooks'; -import getAssets from '../../tools/getAssets'; - -export default function getDependencyConfig( - ctx: ContextT, - availablePlatforms: PlatformsT, - dependency: string -): DependenciesConfig { - try { - const folder = path.join(ctx.root, 'node_modules', dependency); - const config = getPackageConfiguration(folder); - - const platformConfigs = { ios: undefined, android: undefined }; - - Object.keys(availablePlatforms).forEach(platform => { - platformConfigs[platform] = availablePlatforms[platform].dependencyConfig( - folder, - config[platform] || {} - ); - }); - - return { - config: platformConfigs, - name: dependency, - path: folder, - commands: getHooks(folder), - assets: getAssets(folder), - params: getParams(folder), - }; - } catch (e) { - throw new Error('Failed to get dependency config'); - } -} diff --git a/packages/cli/src/commands/link/getPlatformName.js b/packages/cli/src/commands/link/getPlatformName.js new file mode 100644 index 0000000000..455d9c06ca --- /dev/null +++ b/packages/cli/src/commands/link/getPlatformName.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +const names = { + ios: 'iOS', + android: 'Android', +}; + +export default function getPlatformName(name: string) { + return names[name] || name; +} diff --git a/packages/cli/src/commands/link/getProjectConfig.js b/packages/cli/src/commands/link/getProjectConfig.js deleted file mode 100644 index b9305b2320..0000000000 --- a/packages/cli/src/commands/link/getProjectConfig.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @flow - */ - -import type { - PlatformsT, - ContextT, - ProjectConfigT, -} from '../../tools/types.flow'; - -import getPackageConfiguration from '../../tools/getPackageConfiguration'; - -export default function getProjectConfig( - ctx: ContextT, - availablePlatforms: PlatformsT -): ProjectConfigT { - const config = getPackageConfiguration(ctx.root); - - const platformConfigs = { ios: undefined, android: undefined }; - - Object.keys(availablePlatforms).forEach(platform => { - platformConfigs[platform] = availablePlatforms[platform].projectConfig( - ctx.root, - config[platform] || {} - ); - }); - - return platformConfigs; -} diff --git a/packages/cli/src/commands/link/getProjectDependencies.js b/packages/cli/src/commands/link/getProjectDependencies.js deleted file mode 100644 index 70cdb66592..0000000000 --- a/packages/cli/src/commands/link/getProjectDependencies.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -import path from 'path'; - -/** - * List of projects that should not be treated as projects to be linked. - * - * That includes `react-native` itself and the CLI project (under its real and staging npm package). - */ -const EXCLUDED_PROJECTS = [ - 'react-native', - '@react-native-community/cli', - 'react-native-local-cli-preview', -]; - -/** - * Returns an array of dependencies that should be linked/checked. - */ -export default function getProjectDependencies(cwd: string) { - const pkgJson = require(path.join(cwd, './package.json')); - return (Object.keys(pkgJson.dependencies || {}).filter( - name => EXCLUDED_PROJECTS.includes(name) === false - ): Array); -} diff --git a/packages/cli/src/commands/link/ios/common/registerNativeModule.js b/packages/cli/src/commands/link/ios/common/registerNativeModule.js deleted file mode 100644 index bddfd14b67..0000000000 --- a/packages/cli/src/commands/link/ios/common/registerNativeModule.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import registerDependencyIOS from '../registerNativeModule'; -import registerDependencyPods from '../../pods/registerNativeModule'; - -export default function registerNativeModule( - name, - dependencyConfig, - params, - projectConfig -) { - if (projectConfig.podfile && dependencyConfig.podspec) { - registerDependencyPods(name, dependencyConfig, projectConfig); - } else { - registerDependencyIOS(dependencyConfig, projectConfig); - } -} diff --git a/packages/cli/src/commands/link/link.js b/packages/cli/src/commands/link/link.js index 6be0b54843..d7e458e821 100644 --- a/packages/cli/src/commands/link/link.js +++ b/packages/cli/src/commands/link/link.js @@ -7,23 +7,19 @@ * @flow */ -import { pick } from 'lodash'; -import type { ContextT } from '../../tools/types.flow'; - -import promiseWaterfall from './promiseWaterfall'; -import logger from '../../tools/logger'; -import getDependencyConfig from './getDependencyConfig'; -import commandStub from './commandStub'; -import promisify from './promisify'; -import getProjectConfig from './getProjectConfig'; +import chalk from 'chalk'; +import {pick} from 'lodash'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import {type ConfigT} from 'types'; +import getPlatformName from './getPlatformName'; import linkDependency from './linkDependency'; import linkAssets from './linkAssets'; import linkAll from './linkAll'; -import findReactNativeScripts from '../../tools/findReactNativeScripts'; -import getPlatforms from '../../tools/getPlatforms'; +import makeHook from './makeHook'; type FlagsType = { platforms?: Array, + all?: boolean, }; /** @@ -32,74 +28,78 @@ type FlagsType = { * @param args If optional argument [packageName] is provided, * only that package is processed. */ -function link([rawPackageName]: Array, ctx: ContextT, opts: FlagsType) { - let platforms; - let project; - try { - platforms = getPlatforms(ctx.root); - if (opts.platforms) { - platforms = pick(platforms, opts.platforms); - } - project = getProjectConfig(ctx, platforms); - } catch (err) { - logger.error( - 'No package found. Are you sure this is a React Native project?' - ); - return Promise.reject(err); +async function link( + [rawPackageName]: Array, + ctx: ConfigT, + opts: FlagsType, +) { + let platforms = ctx.platforms; + let project = ctx.project; + + if (opts.platforms) { + platforms = pick(platforms, opts.platforms); + logger.debug('Skipping selected platforms'); } - const hasProjectConfig = Object.keys(platforms).reduce( - (acc, key) => acc || key in project, - false + + logger.debug( + 'Available platforms: ' + + `${Object.keys(platforms) + .map(getPlatformName) + .join(', ')}`, ); - if (!hasProjectConfig && findReactNativeScripts()) { - throw new Error( - '`react-native link [package]` can not be used in Create React Native App projects. ' + - 'If you need to include a library that relies on custom native code, ' + - 'you might have to eject first. ' + - 'See https://github.com/react-community/create-react-native-app/blob/master/EJECTING.md ' + - 'for more information.' - ); - } if (rawPackageName === undefined) { - return linkAll(ctx, platforms, project); + logger.debug('No package name provided, will linking all possible assets.'); + return linkAll(ctx, {linkDeps: opts.all, linkAssets: true}); } // Trim the version / tag out of the package name (eg. package@latest) const packageName = rawPackageName.replace(/^(.+?)(@.+?)$/gi, '$1'); - const dependencyConfig = getDependencyConfig(ctx, platforms, packageName); + if (!Object.keys(ctx.dependencies).includes(packageName)) { + throw new CLIError(` + Unknown dependency. Make sure that the package you are trying to link is + already installed in your "node_modules" and present in your "package.json" dependencies. + `); + } + + const {[packageName]: dependency} = ctx.dependencies; - const tasks = [ - () => promisify(dependencyConfig.commands.prelink || commandStub), - () => linkDependency(platforms, project, dependencyConfig), - () => promisify(dependencyConfig.commands.postlink || commandStub), - () => linkAssets(platforms, project, dependencyConfig.assets), - ]; + logger.debug(`Package to link: ${rawPackageName}`); - return promiseWaterfall(tasks).catch(err => { - logger.error( - `Something went wrong while linking. Error: ${err.message} \n` + - 'Please file an issue here: https://github.com/react-native-community/react-native-cli/issues' + try { + if (dependency.hooks.prelink) { + await makeHook(dependency.hooks.prelink)(); + } + await linkDependency(platforms, project, dependency); + if (dependency.hooks.postlink) { + await makeHook(dependency.hooks.postlink)(); + } + await linkAssets(platforms, project, dependency.assets); + } catch (error) { + throw new CLIError( + `Linking "${chalk.bold(dependency.name)}" failed.`, + error, ); - throw err; - }); + } } export const func = link; export default { func: link, - description: 'scope link command to certain platforms (comma-separated)', + description: 'links assets and optionally native modules', name: 'link [packageName]', options: [ { - command: '--platforms [list]', - description: - 'If you want to link dependencies only for specific platforms', + name: '--platforms [list]', + description: 'Scope linking to specified platforms', + parse: (val: string) => val.toLowerCase().split(','), + }, + { + name: '--all [boolean]', + description: 'Link all native modules and assets', parse: (val: string) => val.toLowerCase().split(','), }, ], }; - -// link; diff --git a/packages/cli/src/commands/link/linkAll.js b/packages/cli/src/commands/link/linkAll.js index 4a14d13fd1..97ce27adec 100644 --- a/packages/cli/src/commands/link/linkAll.js +++ b/packages/cli/src/commands/link/linkAll.js @@ -1,65 +1,70 @@ -// @flow +/** + * @flow + */ -import { uniqBy, flatten } from 'lodash'; +import {uniqBy} from 'lodash'; import path from 'path'; -import type { - ContextT, - PlatformsT, - ProjectConfigT, -} from '../../tools/types.flow'; -import logger from '../../tools/logger'; -import getAssets from '../../tools/getAssets'; -import getProjectDependencies from './getProjectDependencies'; -import getDependencyConfig from './getDependencyConfig'; -import promiseWaterfall from './promiseWaterfall'; -import commandStub from './commandStub'; -import promisify from './promisify'; +import chalk from 'chalk'; +import {CLIError, logger} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; import linkAssets from './linkAssets'; import linkDependency from './linkDependency'; +import makeHook from './makeHook'; const dedupeAssets = (assets: Array): Array => uniqBy(assets, asset => path.basename(asset)); -function linkAll( - context: ContextT, - platforms: PlatformsT, - project: ProjectConfigT -) { - logger.warn( - 'Running `react-native link` without package name is deprecated and will be removed ' + - 'in next release. If you use this command to link your project assets, ' + - 'please let us know about your use case here: https://goo.gl/RKTeoc' - ); +type Options = { + linkDeps?: boolean, + linkAssets?: boolean, +}; - const projectAssets = getAssets(context.root); - const dependencies = getProjectDependencies(context.root); - const depenendenciesConfig = dependencies.map(dependnecy => - getDependencyConfig(context, platforms, dependnecy) - ); - - const assets = dedupeAssets( - depenendenciesConfig.reduce( - (acc, dependency) => acc.concat(dependency.assets), - projectAssets - ) - ); - - const tasks = flatten( - depenendenciesConfig.map(config => [ - () => promisify(config.commands.prelink || commandStub), - () => linkDependency(platforms, project, config), - () => promisify(config.commands.postlink || commandStub), - () => linkAssets(platforms, project, assets), - ]) - ); +async function linkAll(config: ConfigT, options: Options) { + if (options.linkDeps) { + logger.debug('Linking all dependencies'); + logger.info( + `Linking dependencies using "${chalk.bold( + 'link', + )}" command is now legacy and likely unnecessary. We encourage you to try ${chalk.bold( + 'autolinking', + )} that comes with React Native v0.60 default template. Autolinking happens at build time – during CocoaPods install or Gradle install phase. More information: ${chalk.dim.underline( + 'https://github.com/react-native-community/cli/blob/master/docs/autolinking.md', + )}`, + ); - return promiseWaterfall(tasks).catch(err => { - logger.error( - `Something went wrong while linking. Error: ${err.message} \n` + - 'Please file an issue here: https://github.com/react-native-community/react-native-cli/issues' + for (let key in config.dependencies) { + const dependency = config.dependencies[key]; + try { + if (dependency.hooks.prelink) { + await makeHook(dependency.hooks.prelink)(); + } + await linkDependency(config.platforms, config.project, dependency); + if (dependency.hooks.postlink) { + await makeHook(dependency.hooks.postlink)(); + } + } catch (error) { + throw new CLIError( + `Linking "${chalk.bold(dependency.name)}" failed.`, + error, + ); + } + } + } + if (options.linkAssets) { + logger.debug('Linking all assets'); + const projectAssets = config.assets; + const assets = dedupeAssets( + Object.keys(config.dependencies).reduce( + (acc, dependency) => acc.concat(config.dependencies[dependency].assets), + projectAssets, + ), ); - throw err; - }); + try { + await linkAssets(config.platforms, config.project, assets); + } catch (error) { + throw new CLIError('Linking assets failed.', error); + } + } } export default linkAll; diff --git a/packages/cli/src/commands/link/linkAssets.js b/packages/cli/src/commands/link/linkAssets.js index 6b36c37968..700893724e 100644 --- a/packages/cli/src/commands/link/linkAssets.js +++ b/packages/cli/src/commands/link/linkAssets.js @@ -1,14 +1,14 @@ // @flow -import { isEmpty } from 'lodash'; -import type { PlatformsT, ProjectConfigT } from '../../tools/types.flow'; +import {isEmpty} from 'lodash'; +import type {PlatformsT, ProjectConfigT} from 'types'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; const linkAssets = ( platforms: PlatformsT, project: ProjectConfigT, - assets: Array + assets: Array, ) => { if (isEmpty(assets)) { return; @@ -29,7 +29,7 @@ const linkAssets = ( linkConfig.copyAssets(assets, project[platform]); }); - logger.info('Assets have been successfully linked to your project'); + logger.success('Assets have been successfully linked to your project'); }; export default linkAssets; diff --git a/packages/cli/src/commands/link/linkDependency.js b/packages/cli/src/commands/link/linkDependency.js index 60efb7ac96..a893076a86 100644 --- a/packages/cli/src/commands/link/linkDependency.js +++ b/packages/cli/src/commands/link/linkDependency.js @@ -1,26 +1,25 @@ // @flow - -import type { - PlatformsT, - ProjectConfigT, - DependenciesConfig, -} from '../../tools/types.flow'; -import logger from '../../tools/logger'; +import chalk from 'chalk'; +import type {DependencyConfigT, ProjectConfigT, PlatformsT} from 'types'; +import {logger} from '@react-native-community/cli-tools'; import pollParams from './pollParams'; -import { getPlatformName } from '../../tools/getPlatforms'; +import getPlatformName from './getPlatformName'; const linkDependency = async ( platforms: PlatformsT, project: ProjectConfigT, - dependency: DependenciesConfig + dependency: DependencyConfigT, ) => { const params = await pollParams(dependency.params); Object.keys(platforms || {}).forEach(platform => { - if (!project[platform] || !dependency.config[platform]) { + const projectConfig = project[platform]; + const dependencyConfig = dependency.platforms[platform]; + + if (!projectConfig || !dependencyConfig) { return; } - + const {name} = dependency; const linkConfig = platforms[platform] && platforms[platform].linkConfig && @@ -31,36 +30,32 @@ const linkDependency = async ( } const isInstalled = linkConfig.isInstalled( - project[platform], - dependency.name, - dependency.config[platform] + // $FlowFixMe + projectConfig, + name, + // $FlowFixMe + dependencyConfig, ); if (isInstalled) { logger.info( - `${getPlatformName(platform)} module "${ - dependency.name - }" is already linked` + `${getPlatformName(platform)} module "${chalk.bold( + name, + )}" is already linked`, ); return; } logger.info( - `Linking "${dependency.name}" ${getPlatformName(platform)} dependency` - ); - - linkConfig.register( - dependency.name, - dependency.config[platform] || {}, - params, - // $FlowFixMe: We check if project[platform] exists on line 42 - project[platform] + `Linking "${chalk.bold(name)}" ${getPlatformName(platform)} dependency`, ); + // $FlowFixMe + linkConfig.register(name, dependencyConfig, params, projectConfig); logger.info( - `${getPlatformName(platform)} module "${ - dependency.name - }" has been successfully linked` + `${getPlatformName(platform)} module "${chalk.bold( + dependency.name, + )}" has been successfully linked`, ); }); }; diff --git a/packages/cli/src/commands/link/makeHook.js b/packages/cli/src/commands/link/makeHook.js new file mode 100644 index 0000000000..29b23489cf --- /dev/null +++ b/packages/cli/src/commands/link/makeHook.js @@ -0,0 +1,14 @@ +/** + * @flow + */ + +import execa from 'execa'; + +export default function makeHook(command: string) { + return () => { + const args = command.split(' '); + const cmd = args.shift(); + + return execa(cmd, args, {stdio: 'inherit'}); + }; +} diff --git a/packages/cli/src/commands/link/pollParams.js b/packages/cli/src/commands/link/pollParams.js index 3ee296195f..ed93ac8135 100644 --- a/packages/cli/src/commands/link/pollParams.js +++ b/packages/cli/src/commands/link/pollParams.js @@ -5,12 +5,14 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ import inquirer from 'inquirer'; +import type {InquirerPromptT} from 'types'; -export default questions => - new Promise((resolve, reject) => { +export default (questions: InquirerPromptT) => + new Promise((resolve, reject) => { if (!questions) { resolve({}); return; diff --git a/packages/cli/src/commands/link/promiseWaterfall.js b/packages/cli/src/commands/link/promiseWaterfall.js deleted file mode 100644 index 78f471b376..0000000000 --- a/packages/cli/src/commands/link/promiseWaterfall.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -/** - * Given an array of promise creators, executes them in a sequence. - * - * If any of the promises in the chain fails, all subsequent promises - * will be skipped - * - * Returns the value last promise from a sequence resolved - */ -export default function promiseWaterfall(tasks) { - return tasks.reduce( - (prevTaskPromise, task) => prevTaskPromise.then(task), - Promise.resolve() - ); -} diff --git a/packages/cli/src/commands/link/promisify.js b/packages/cli/src/commands/link/promisify.js deleted file mode 100644 index 62b234d2bf..0000000000 --- a/packages/cli/src/commands/link/promisify.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -export default func => - new Promise((resolve, reject) => - func((err, res) => (err ? reject(err) : resolve(res))) - ); diff --git a/packages/cli/src/commands/link/unlink.js b/packages/cli/src/commands/link/unlink.js index 219121141e..d19d5321a5 100644 --- a/packages/cli/src/commands/link/unlink.js +++ b/packages/cli/src/commands/link/unlink.js @@ -7,26 +7,27 @@ * @flow */ -import { flatten, isEmpty, difference } from 'lodash'; -import type { ContextT } from '../../tools/types.flow'; -import logger from '../../tools/logger'; -import getProjectConfig from './getProjectConfig'; -import getDependencyConfig from './getDependencyConfig'; -import getProjectDependencies from './getProjectDependencies'; -import promiseWaterfall from './promiseWaterfall'; -import commandStub from './commandStub'; -import promisify from './promisify'; -import getPlatforms, { getPlatformName } from '../../tools/getPlatforms'; +import {flatMap, values, difference, pick} from 'lodash'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; +import getPlatformName from './getPlatformName'; +import makeHook from './makeHook'; + +type Flags = { + platforms?: Array, +}; const unlinkDependency = ( platforms, project, dependency, packageName, - otherDependencies + otherDependencies, ) => { Object.keys(platforms || {}).forEach(platform => { - if (!project[platform] || !dependency.config[platform]) { + const projectConfig = project[platform]; + const dependencyConfig = dependency.platforms[platform]; + if (!projectConfig || !dependencyConfig) { return; } @@ -40,35 +41,37 @@ const unlinkDependency = ( } const isInstalled = linkConfig.isInstalled( - project[platform], + // $FlowFixMe + projectConfig, packageName, - dependency.config[platform] + // $FlowFixMe + dependencyConfig, ); if (!isInstalled) { logger.info( - `${getPlatformName(platform)} module "${packageName}" is not installed` + `${getPlatformName(platform)} module "${packageName}" is not installed`, ); return; } logger.info( - `Unlinking "${packageName}" ${getPlatformName(platform)} dependency` + `Unlinking "${packageName}" ${getPlatformName(platform)} dependency`, ); linkConfig.unregister( packageName, - // $FlowFixMe: We check for existence on line 38 - dependency.config[platform], - // $FlowFixMe: We check for existence on line 38 - project[platform], - otherDependencies + // $FlowFixMe + dependencyConfig, + // $FlowFixMe + projectConfig, + otherDependencies, ); logger.info( `${getPlatformName(platform)} module "${ dependency.name - }" has been successfully unlinked` + }" has been successfully unlinked`, ); }); }; @@ -79,95 +82,91 @@ const unlinkDependency = ( * If optional argument [packageName] is provided, it's the only one * that's checked */ -function unlink(args: Array, ctx: ContextT) { +async function unlink(args: Array, ctx: ConfigT, opts: Flags) { const packageName = args[0]; + let platforms = ctx.platforms; - let platforms; - - try { - platforms = getPlatforms(ctx.root); - } catch (err) { - logger.error( - "No package.json found. Are you sure it's a React Native project?" - ); - return Promise.reject(err); + if (opts.platforms) { + platforms = pick(platforms, opts.platforms); + logger.debug('Skipping selected platforms'); } - const allDependencies = getProjectDependencies(ctx.root).map(dependency => - getDependencyConfig(ctx, platforms, dependency) + logger.debug( + `Available platforms: ${Object.keys(platforms) + .map(getPlatformName) + .join(', ')}`, ); - let otherDependencies; - let dependency; - try { - const idx = allDependencies.findIndex(p => p.name === packageName); + const {[packageName]: dependency, ...otherDependencies} = ctx.dependencies; - if (idx === -1) { - throw new Error(`Project "${packageName}" is not a react-native library`); - } + if (!dependency) { + throw new CLIError(` + Failed to unlink "${packageName}". It appears that the project is not linked yet. + `); + } - otherDependencies = [...allDependencies]; - dependency = otherDependencies.splice(idx, 1)[0]; // eslint-disable-line prefer-destructuring - } catch (err) { - return Promise.reject(err); + const dependencies = values(otherDependencies); + try { + if (dependency.hooks.preulink) { + await makeHook(dependency.hooks.preulink)(); + } + unlinkDependency( + platforms, + ctx.project, + dependency, + packageName, + dependencies, + ); + if (dependency.hooks.postunlink) { + await makeHook(dependency.hooks.postunlink)(); + } + } catch (error) { + throw new CLIError( + `Something went wrong while unlinking. Reason ${error.message}`, + error, + ); } - const project = getProjectConfig(ctx, platforms); - - const tasks = [ - () => promisify(dependency.commands.preunlink || commandStub), - () => - unlinkDependency( - platforms, - project, - dependency, - packageName, - otherDependencies - ), - () => promisify(dependency.commands.postunlink || commandStub), - ]; - - return promiseWaterfall(tasks) - .then(() => { - // @todo move all these to `tasks` array, just like in - // link - const assets = difference( - dependency.assets, - flatten(allDependencies, d => d.assets) - ); + // @todo move all these to above try/catch + // @todo it is possible we could be unlinking some project assets in case of duplicate + const assets = difference( + dependency.assets, + flatMap(dependencies, d => d.assets), + ); - if (isEmpty(assets)) { - return; - } + if (assets.length === 0) { + return; + } - Object.keys(platforms || {}).forEach(platform => { - const linkConfig = - platforms[platform] && - platforms[platform].linkConfig && - platforms[platform].linkConfig(); - if (!linkConfig || !linkConfig.unlinkAssets || !project[platform]) { - return; - } + Object.keys(platforms || {}).forEach(platform => { + const projectConfig = ctx.project[platform]; + const linkConfig = + platforms[platform] && + platforms[platform].linkConfig && + platforms[platform].linkConfig(); + if (!linkConfig || !linkConfig.unlinkAssets || !projectConfig) { + return; + } - logger.info(`Unlinking assets from ${platform} project`); - // $FlowFixMe: We check for platorm existence on line 150 - linkConfig.unlinkAssets(assets, project[platform]); - }); + logger.info(`Unlinking assets from ${platform} project`); + // $FlowFixMe + linkConfig.unlinkAssets(assets, projectConfig); + }); - logger.info( - `${packageName} assets has been successfully unlinked from your project` - ); - }) - .catch(err => { - logger.error( - `It seems something went wrong while unlinking. Error:\n${err.message}` - ); - throw err; - }); + logger.info( + `${packageName} assets has been successfully unlinked from your project`, + ); } export default { func: unlink, description: 'unlink native dependency', name: 'unlink ', + options: [ + { + name: '--platforms [list]', + description: 'Scope unlinking to specified platforms', + parse: (val: string) => val.toLowerCase().split(','), + }, + ], }; diff --git a/packages/cli/src/commands/logAndroid/logAndroid.js b/packages/cli/src/commands/logAndroid/logAndroid.js deleted file mode 100644 index e2d722b63b..0000000000 --- a/packages/cli/src/commands/logAndroid/logAndroid.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { spawnSync } from 'child_process'; -import logger from '../../tools/logger'; - -/** - * Starts adb logcat - */ -async function logAndroid() { - const adbPath = process.env.ANDROID_HOME - ? `${process.env.ANDROID_HOME}/platform-tools/adb` - : 'adb'; - - const adbArgs = ['logcat', '*:S', 'ReactNative:V', 'ReactNativeJS:V']; - - logger.info(`Starting the logger (${adbPath} ${adbArgs.join(' ')})...`); - - const log = spawnSync(adbPath, adbArgs, { stdio: 'inherit' }); - - if (log.error !== null) { - throw log.error; - } -} - -export default { - name: 'log-android', - description: 'starts adb logcat', - func: logAndroid, -}; diff --git a/packages/cli/src/commands/runAndroid/runOnAllDevices.js b/packages/cli/src/commands/runAndroid/runOnAllDevices.js deleted file mode 100644 index 48956701c6..0000000000 --- a/packages/cli/src/commands/runAndroid/runOnAllDevices.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -/* eslint-disable consistent-return */ - -import { spawnSync, execFileSync } from 'child_process'; -import logger from '../../tools/logger'; -import adb from './adb'; -import tryRunAdbReverse from './tryRunAdbReverse'; -import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; - -function getCommand(appFolder, command) { - return appFolder ? `${appFolder}:${command}` : command; -} - -function runOnAllDevices( - // eslint-disable-next-line flowtype/no-weak-types - args: Object, - cmd: string, - packageNameWithSuffix: string, - packageName: string, - adbPath: string -) { - try { - const gradleArgs = []; - - if (args.installDebug) { - gradleArgs.push(getCommand(args.appFolder, args.installDebug)); - } else if (args.variant) { - gradleArgs.push( - `${getCommand( - args.appFolder, - 'install' - )}${args.variant[0].toUpperCase()}${args.variant.slice(1)}` - ); - } else if (args.flavor) { - logger.warn('--flavor has been deprecated. Use --variant instead'); - gradleArgs.push( - `${getCommand( - args.appFolder, - 'install' - )}${args.flavor[0].toUpperCase()}${args.flavor.slice(1)}` - ); - } else { - gradleArgs.push(getCommand(args.appFolder, 'installDebug')); - } - - logger.info( - `Building and installing the app on the device (cd android && ${cmd} ${gradleArgs.join( - ' ' - )})...` - ); - - execFileSync(cmd, gradleArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); - } catch (e) { - logger.error( - 'Could not install the app on the device, read the error above for details.\n' + - 'Make sure you have an Android emulator running or a device connected and have\n' + - 'set up your Android development environment:\n' + - 'https://facebook.github.io/react-native/docs/getting-started.html' - ); - // stderr is automatically piped from the gradle process, so the user - // should see the error already, there is no need to do - // `logger.info(e.stderr)` - return Promise.reject(e); - } - const devices = adb.getDevices(adbPath); - if (devices && devices.length > 0) { - devices.forEach(device => { - tryRunAdbReverse(args.port, device); - tryLaunchAppOnDevice( - device, - packageNameWithSuffix, - packageName, - adbPath, - args.mainActivity - ); - }); - } else { - try { - // If we cannot execute based on adb devices output, fall back to - // shell am start - const fallbackAdbArgs = [ - 'shell', - 'am', - 'start', - '-n', - `${packageNameWithSuffix}/${packageName}.MainActivity`, - ]; - logger.info( - `Starting the app (${adbPath} ${fallbackAdbArgs.join(' ')}...` - ); - spawnSync(adbPath, fallbackAdbArgs, { stdio: 'inherit' }); - } catch (e) { - logger.error('adb invocation failed. Do you have adb in your PATH?'); - // stderr is automatically piped from the gradle process, so the user - // should see the error already, there is no need to do - // `logger.info(e.stderr)` - return Promise.reject(e); - } - } -} - -export default runOnAllDevices; diff --git a/packages/cli/src/commands/runAndroid/tryLaunchAppOnDevice.js b/packages/cli/src/commands/runAndroid/tryLaunchAppOnDevice.js deleted file mode 100644 index b8916530f9..0000000000 --- a/packages/cli/src/commands/runAndroid/tryLaunchAppOnDevice.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -import { spawnSync } from 'child_process'; -import logger from '../../tools/logger'; - -function tryLaunchAppOnDevice( - device: string, - packageNameWithSuffix: string, - packageName: string, - adbPath: string, - mainActivity: string -) { - try { - const adbArgs = [ - '-s', - device, - 'shell', - 'am', - 'start', - '-n', - `${packageNameWithSuffix}/${packageName}.${mainActivity}`, - ]; - logger.info( - `Starting the app on ${device} (${adbPath} ${adbArgs.join(' ')})...` - ); - spawnSync(adbPath, adbArgs, { stdio: 'inherit' }); - } catch (e) { - logger.error('adb invocation failed. Do you have adb in your PATH?'); - } -} - -export default tryLaunchAppOnDevice; diff --git a/packages/cli/src/commands/server/copyToClipBoard.js b/packages/cli/src/commands/server/copyToClipBoard.js index 0017b5c46d..4cfc82fbc0 100644 --- a/packages/cli/src/commands/server/copyToClipBoard.js +++ b/packages/cli/src/commands/server/copyToClipBoard.js @@ -7,7 +7,7 @@ * @format */ -import { spawn } from 'child_process'; +import {spawn} from 'child_process'; import path from 'path'; import fs from 'fs'; diff --git a/packages/cli/src/commands/server/debugger-ui/DeltaPatcher.js b/packages/cli/src/commands/server/debugger-ui/DeltaPatcher.js index 7793792f40..25c9f36900 100644 --- a/packages/cli/src/commands/server/debugger-ui/DeltaPatcher.js +++ b/packages/cli/src/commands/server/debugger-ui/DeltaPatcher.js @@ -55,7 +55,7 @@ // Make sure that the first received bundle is a base. if (!this._initialized && !bundle.base) { throw new Error( - 'DeltaPatcher should receive a base Bundle when being initialized' + 'DeltaPatcher should receive a base Bundle when being initialized', ); } @@ -119,8 +119,11 @@ getAllModules() { return [].concat( [this._lastBundle.pre], - Array.from(this._lastBundle.modules.values()), - [this._lastBundle.post] + // Sort modules so they match the source map emitted by Metro >= 0.51.0 + Array.from(this._lastBundle.modules.entries()) + .sort(([id1], [id2]) => id1 - id2) + .map(([id, contents]) => contents), + [this._lastBundle.post], ); } } diff --git a/packages/cli/src/commands/server/debugger-ui/__tests__/DeltaPatcher-test.js b/packages/cli/src/commands/server/debugger-ui/__tests__/DeltaPatcher-test.js index 2bd9db3396..caae8e599c 100644 --- a/packages/cli/src/commands/server/debugger-ui/__tests__/DeltaPatcher-test.js +++ b/packages/cli/src/commands/server/debugger-ui/__tests__/DeltaPatcher-test.js @@ -108,4 +108,55 @@ describe('DeltaPatcher', () => { expect(dp.getLastNumModifiedFiles()).toBe(2); expect(dp.getAllModules()).toEqual(['pre2', '__d(4);', '__d(5);', 'post2']); }); + + it('should sort modules after receiving an unsorted base bundle', () => { + const dp = new window.DeltaPatcher(); + global.Date = jest.fn(); + dp.applyDelta({ + base: true, + revisionId: 'rev0', + pre: 'pre0', + post: 'post0', + modules: [[2, '__d(2);'], [3, '__d(3);'], [0, '__d(0);'], [1, '__d(1);']], + }); + expect(dp.getLastRevisionId()).toBe('rev0'); + expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]); + expect(dp.getLastNumModifiedFiles()).toBe(4); + expect(dp.getAllModules()).toEqual([ + 'pre0', + '__d(0);', + '__d(1);', + '__d(2);', + '__d(3);', + 'post0', + ]); + }); + + it('should sort modules after receiving an unsorted delta bundle', () => { + const dp = new window.DeltaPatcher(); + dp.applyDelta({ + base: true, + revisionId: 'rev0', + pre: 'pre0', + post: 'post0', + modules: [[2, '__d(2);'], [1, '__d(1);'], [0, '__d(0);']], + }); + global.Date = jest.fn(); + dp.applyDelta({ + base: false, + revisionId: 'rev1', + modules: [[3, '__d(3);'], [1, '__d(1.1);']], + deleted: [0], + }); + expect(dp.getLastRevisionId()).toBe('rev1'); + expect(dp.getLastModifiedDate()).toBe(global.Date.mock.instances[0]); + expect(dp.getLastNumModifiedFiles()).toBe(3); + expect(dp.getAllModules()).toEqual([ + 'pre0', + '__d(1.1);', + '__d(2);', + '__d(3);', + 'post0', + ]); + }); }); diff --git a/packages/cli/src/commands/server/debugger-ui/debuggerWorker.js b/packages/cli/src/commands/server/debugger-ui/debuggerWorker.js index 4873b41934..070d753b71 100644 --- a/packages/cli/src/commands/server/debugger-ui/debuggerWorker.js +++ b/packages/cli/src/commands/server/debugger-ui/debuggerWorker.js @@ -25,7 +25,7 @@ onmessage = (function() { console.warn( 'Remote debugger is in a background tab which may cause apps to ' + 'perform slowly. Fix this by foregrounding the tab (or opening it in ' + - 'a separate window).' + 'a separate window).', ); }; })(); @@ -56,7 +56,7 @@ onmessage = (function() { var object = message.data; var sendReply = function(result, error) { - postMessage({ replyID: object.id, result: result, error: error }); + postMessage({replyID: object.id, result: result, error: error}); }; var handler = messageHandlers[object.method]; @@ -71,7 +71,7 @@ onmessage = (function() { if (typeof __fbBatchedBridge === 'object') { returnValue = __fbBatchedBridge[object.method].apply( null, - object.arguments + object.arguments, ); } else { error = 'Failed to call function, __fbBatchedBridge is undefined'; diff --git a/packages/cli/src/commands/server/debugger-ui/index.html b/packages/cli/src/commands/server/debugger-ui/index.html index 320b482899..a0ebbbd692 100644 --- a/packages/cli/src/commands/server/debugger-ui/index.html +++ b/packages/cli/src/commands/server/debugger-ui/index.html @@ -219,7 +219,15 @@ connectToDebuggerProxy(); async function getBlobUrl(url) { - return await window.deltaUrlToBlobUrl(url.replace('.bundle', '.delta')); + // Ensure that the bundle URL has the same origin as this webpage so that + // the same-origin policy lets us fetch it + const urlObject = new URL(url, location); + const relativeUrl = urlObject.pathname.replace('.bundle', '.delta') + + urlObject.search + + urlObject.hash; + const localUrl = new URL(relativeUrl, location).toString(); + + return await window.deltaUrlToBlobUrl(localUrl); } })(); diff --git a/packages/cli/src/commands/server/jsPackagerClient.js b/packages/cli/src/commands/server/jsPackagerClient.js deleted file mode 100644 index 9387a49c48..0000000000 --- a/packages/cli/src/commands/server/jsPackagerClient.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import WebSocket from 'ws'; -import logger from '../../tools/logger'; -import MessageSocket from './messageSocket'; - -const PROTOCOL_VERSION = 2; -const TARGET_SERVER = 'server'; - -function getMessageId() { - return `${Date.now()}:${Math.random()}`; -} - -class JsPackagerClient { - constructor(url) { - this.ws = new WebSocket(url); - this.msgCallbacks = new Map(); - - this.openPromise = new Promise((resolve, reject) => { - this.ws.on('error', error => reject(error)); - this.ws.on('open', resolve); - }); - - this.ws.on('message', (data, flags) => { - const message = MessageSocket.parseMessage(data, flags.binary); - const msgCallback = this.msgCallbacks.get(message.id); - if (message === undefined || message.id === undefined) { - // gracefully ignore wrong messages or broadcasts - } else if (msgCallback === undefined) { - logger.warn(`Response with non-existing message id: '${message.id}'`); - } else if (message.error === undefined) { - msgCallback.resolve(message.result); - } else { - msgCallback.reject(message.error); - } - }); - } - - sendRequest(method, target, params) { - return this.openPromise.then( - () => - new Promise((resolve, reject) => { - const messageId = getMessageId(); - this.msgCallbacks.set(messageId, { resolve, reject }); - this.ws.send( - JSON.stringify({ - version: PROTOCOL_VERSION, - target, - method, - id: messageId, - params, - }), - error => { - if (error !== undefined) { - this.msgCallbacks.delete(messageId); - reject(error); - } - } - ); - }) - ); - } - - sendNotification(method, target, params) { - return this.openPromise.then( - () => - new Promise((resolve, reject) => { - this.ws.send( - JSON.stringify({ - version: PROTOCOL_VERSION, - target, - method, - params, - }), - error => { - if (error !== undefined) { - reject(error); - } else { - resolve(); - } - } - ); - }) - ); - } - - sendBroadcast(method, params) { - return this.sendNotification(method, undefined, params); - } - - getPeers() { - return new Promise((resolve, reject) => { - this.sendRequest('getpeers', TARGET_SERVER, undefined).then(response => { - if (!(response instanceof Map)) { - reject( - new Error( - `Results received from server are of wrong format:\n${JSON.stringify( - response - )}` - ) - ); - } else { - resolve(response); - } - }, reject); - }); - } - - getId() { - return this.sendRequest('getid', TARGET_SERVER, undefined); - } -} - -export default JsPackagerClient; diff --git a/packages/cli/src/commands/server/launchBrowser.js b/packages/cli/src/commands/server/launchBrowser.js new file mode 100644 index 0000000000..06152765d9 --- /dev/null +++ b/packages/cli/src/commands/server/launchBrowser.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +import open from 'open'; +import {logger} from '@react-native-community/cli-tools'; + +function launchBrowser(url: string) { + open(url, err => { + if (err) { + logger.error('Browser exited with error:', err); + } + }); +} + +export default launchBrowser; diff --git a/packages/cli/src/commands/server/launchChrome.js b/packages/cli/src/commands/server/launchChrome.js index 5dbf1feec7..87d880a935 100644 --- a/packages/cli/src/commands/server/launchChrome.js +++ b/packages/cli/src/commands/server/launchChrome.js @@ -8,15 +8,15 @@ * @flow */ -import opn from 'opn'; -import { execSync } from 'child_process'; -import logger from '../../tools/logger'; +import open from 'open'; +import {execSync} from 'child_process'; +import {logger} from '@react-native-community/cli-tools'; function commandExistsUnixSync(commandName) { try { const stdout = execSync( `command -v ${commandName} 2>/dev/null` + - ` && { echo >&1 '${commandName} found'; exit 0; }` + ` && { echo >&1 '${commandName} found'; exit 0; }`, ); return !!stdout; } catch (error) { @@ -45,7 +45,7 @@ function getChromeAppName(): string { } function launchChrome(url: string) { - opn(url, { app: [getChromeAppName()] }, err => { + open(url, {app: [getChromeAppName()]}, err => { if (err) { logger.error('Google Chrome exited with error:', err); } diff --git a/packages/cli/src/commands/server/launchEditor.js b/packages/cli/src/commands/server/launchEditor.js index 7dc85fe025..e3e61afe95 100644 --- a/packages/cli/src/commands/server/launchEditor.js +++ b/packages/cli/src/commands/server/launchEditor.js @@ -10,9 +10,9 @@ import chalk from 'chalk'; import fs from 'fs'; import path from 'path'; -import { execSync, spawn } from 'child_process'; +import {execSync, spawn} from 'child_process'; import shellQuote from 'shell-quote'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; function isTerminalEditor(editor) { switch (editor) { @@ -80,7 +80,7 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) { case 'code': return addWorkspaceToArgumentsIfExists( ['-g', `${fileName}:${lineNumber}`], - workspace + workspace, ); // For all others, drop the lineNumber until we have // a mapping above, since providing the lineNumber incorrectly @@ -136,7 +136,7 @@ function printInstructions(title) { ' export REACT_EDITOR=atom to your ~/.bashrc or ~/.zshrc depending on ', ' which shell you use.', '', - ].join('\n') + ].join('\n'), ); } @@ -167,7 +167,7 @@ function launchEditor(fileName, lineNumber, projectRoots) { return; } - let [editor, ...args] = guessEditor(); // eslint-disable-line prefer-const + let [editor, ...args] = guessEditor(); if (!editor) { printInstructions('PRO TIP'); return; @@ -176,7 +176,7 @@ function launchEditor(fileName, lineNumber, projectRoots) { const workspace = findRootForFile(projectRoots, fileName); if (lineNumber) { args = args.concat( - getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) + getArgumentsForLineNumber(editor, fileName, lineNumber, workspace), ); } else { args.push(fileName); @@ -195,13 +195,13 @@ function launchEditor(fileName, lineNumber, projectRoots) { 'When running on Windows, file names are checked against a whitelist ' + 'to protect against remote code execution attacks. File names may ' + 'consist only of alphanumeric characters (all languages), periods, ' + - 'dashes, slashes, and underscores.' + 'dashes, slashes, and underscores.', ); return; } logger.info( - `Opening ${chalk.underline(fileName)} with ${chalk.bold(editor)}` + `Opening ${chalk.underline(fileName)} with ${chalk.bold(editor)}`, ); if (_childProcess && isTerminalEditor(editor)) { @@ -218,7 +218,7 @@ function launchEditor(fileName, lineNumber, projectRoots) { stdio: 'inherit', }); } else { - _childProcess = spawn(editor, args, { stdio: 'inherit' }); + _childProcess = spawn(editor, args, {stdio: 'inherit'}); } _childProcess.on('exit', errorCode => { _childProcess = null; diff --git a/packages/cli/src/commands/server/messageSocket.js b/packages/cli/src/commands/server/messageSocket.js index def0193eb1..a60ea21056 100644 --- a/packages/cli/src/commands/server/messageSocket.js +++ b/packages/cli/src/commands/server/messageSocket.js @@ -6,9 +6,9 @@ */ import url from 'url'; -import { Server as WebSocketServer } from 'ws'; +import {Server as WebSocketServer} from 'ws'; import notifier from 'node-notifier'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; const PROTOCOL_VERSION = 2; @@ -23,7 +23,7 @@ function parseMessage(data, binary) { return message; } logger.error( - `Received message had wrong protocol version: ${message.version}` + `Received message had wrong protocol version: ${message.version}`, ); } catch (e) { logger.error(`Failed to parse the message as JSON:\n${data}`); @@ -66,7 +66,7 @@ function attachToServer(server, path) { const clientWs = clients.get(clientId); if (clientWs === undefined) { throw new Error( - `could not find id "${clientId}" while forwarding request` + `could not find id "${clientId}" while forwarding request`, ); } return clientWs; @@ -94,7 +94,7 @@ function attachToServer(server, path) { } catch (e) { logger.error( `Failed to send broadcast to client: '${otherId}' ` + - `due to:\n ${e.toString()}` + `due to:\n ${e.toString()}`, ); } } @@ -117,7 +117,7 @@ function attachToServer(server, path) { if (message.id === undefined) { logger.error( `Handling message from ${clientId} failed with:\n${error}\n` + - `message:\n${JSON.stringify(errorMessage)}` + `message:\n${JSON.stringify(errorMessage)}`, ); } else { try { @@ -126,13 +126,13 @@ function attachToServer(server, path) { version: PROTOCOL_VERSION, error, id: message.id, - }) + }), ); } catch (e) { logger.error( `Failed to reply to ${clientId} with error:\n${error}` + `\nmessage:\n${JSON.stringify(errorMessage)}` + - `\ndue to error: ${e.toString()}` + `\ndue to error: ${e.toString()}`, ); } } @@ -161,7 +161,7 @@ function attachToServer(server, path) { version: PROTOCOL_VERSION, result, id: message.id, - }) + }), ); } @@ -174,8 +174,8 @@ function attachToServer(server, path) { id: message.id === undefined ? undefined - : { requestId: message.id, clientId }, - }) + : {requestId: message.id, clientId}, + }), ); } @@ -186,18 +186,17 @@ function attachToServer(server, path) { result: message.result, error: message.error, id: message.id.requestId, - }) + }), ); } clients.set(clientId, clientWs); const onCloseHandler = () => { - clientWs.onmessage = null; // eslint-disable-line no-param-reassign + clientWs.onmessage = null; clients.delete(clientId); }; - clientWs.onclose = onCloseHandler; // eslint-disable-line no-param-reassign - clientWs.onerror = onCloseHandler; // eslint-disable-line no-param-reassign - // eslint-disable-next-line no-param-reassign + clientWs.onclose = onCloseHandler; + clientWs.onerror = onCloseHandler; clientWs.onmessage = event => { const message = parseMessage(event.data, event.binary); if (message === undefined) { @@ -227,9 +226,9 @@ function attachToServer(server, path) { return { broadcast: (method, params) => { - handleSendBroadcast(null, { method, params }); + handleSendBroadcast(null, {method, params}); }, }; } -export default { attachToServer, parseMessage }; +export default {attachToServer, parseMessage}; diff --git a/packages/cli/src/commands/server/middleware/MiddlewareManager.js b/packages/cli/src/commands/server/middleware/MiddlewareManager.js index 696a04d08a..d3c222a97d 100644 --- a/packages/cli/src/commands/server/middleware/MiddlewareManager.js +++ b/packages/cli/src/commands/server/middleware/MiddlewareManager.js @@ -13,13 +13,15 @@ import connect from 'connect'; import errorhandler from 'errorhandler'; import path from 'path'; import serveStatic from 'serve-static'; -import { Server as WebSocketServer } from 'ws'; +import {Server as WebSocketServer} from 'ws'; import indexPageMiddleware from './indexPage'; import copyToClipBoardMiddleware from './copyToClipBoardMiddleware'; import getSecurityHeadersMiddleware from './getSecurityHeadersMiddleware'; import loadRawBodyMiddleware from './loadRawBodyMiddleware'; import openStackFrameInEditorMiddleware from './openStackFrameInEditorMiddleware'; +import openURLMiddleware from './openURLMiddleware'; +import logToConsoleMiddleware from './logToConsoleMiddleware'; import statusPageMiddleware from './statusPageMiddleware'; import systraceProfileMiddleware from './systraceProfileMiddleware'; import getDevToolsMiddleware from './getDevToolsMiddleware'; @@ -42,7 +44,7 @@ export default class MiddlewareManager { options: Options; constructor(options: Options) { - const debuggerUIFolder = path.join(__dirname, '..', 'util', 'debugger-ui'); + const debuggerUIFolder = path.join(__dirname, '..', 'debugger-ui'); this.options = options; this.app = connect() @@ -51,6 +53,8 @@ export default class MiddlewareManager { .use(compression()) .use('/debugger-ui', serveStatic(debuggerUIFolder)) .use(openStackFrameInEditorMiddleware(this.options)) + .use(openURLMiddleware) + .use(logToConsoleMiddleware) .use(copyToClipBoardMiddleware) .use(statusPageMiddleware) .use(systraceProfileMiddleware) @@ -68,7 +72,7 @@ export default class MiddlewareManager { attachDevToolsSocket(socket: WebSocketProxy) { this.app.use( - getDevToolsMiddleware(this.options, () => socket.isChromeConnected()) + getDevToolsMiddleware(this.options, () => socket.isChromeConnected()), ); } } diff --git a/packages/cli/src/commands/server/middleware/copyToClipBoardMiddleware.js b/packages/cli/src/commands/server/middleware/copyToClipBoardMiddleware.js index 882f747dc5..ab369efdbd 100644 --- a/packages/cli/src/commands/server/middleware/copyToClipBoardMiddleware.js +++ b/packages/cli/src/commands/server/middleware/copyToClipBoardMiddleware.js @@ -8,7 +8,7 @@ */ import copyToClipBoard from '../copyToClipBoard'; -import logger from '../../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; /** * Handle the request from JS to copy contents onto host system clipboard. diff --git a/packages/cli/src/commands/server/middleware/getDevToolsMiddleware.js b/packages/cli/src/commands/server/middleware/getDevToolsMiddleware.js index 4b2b293e2c..aacd32b228 100644 --- a/packages/cli/src/commands/server/middleware/getDevToolsMiddleware.js +++ b/packages/cli/src/commands/server/middleware/getDevToolsMiddleware.js @@ -7,7 +7,8 @@ * @format */ import launchChrome from '../launchChrome'; -import logger from '../../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; +import {exec} from 'child_process'; function launchChromeDevTools(port, args = '') { const debuggerURL = `http://localhost:${port}/debugger-ui${args}`; @@ -15,36 +16,36 @@ function launchChromeDevTools(port, args = '') { launchChrome(debuggerURL); } -function launchDevTools({ port, watchFolders }, isChromeConnected) { +function escapePath(pathname) { + // " Can escape paths with spaces in OS X, Windows, and *nix + return `"${pathname}"`; +} + +function launchDevTools({port, watchFolders}, isChromeConnected) { // Explicit config always wins const customDebugger = process.env.REACT_DEBUGGER; if (customDebugger) { - customDebugger({ watchFolders, customDebugger }); + startCustomDebugger({watchFolders, customDebugger}); } else if (!isChromeConnected()) { // Dev tools are not yet open; we need to open a session launchChromeDevTools(port); } } +function startCustomDebugger({watchFolders, customDebugger}) { + const folders = watchFolders.map(escapePath).join(' '); + const command = `${customDebugger} ${folders}`; + logger.info('Starting custom debugger by executing:', command); + exec(command, function(error, stdout, stderr) { + if (error !== null) { + logger.error('Error while starting custom debugger:', error); + } + }); +} + export default function getDevToolsMiddleware(options, isChromeConnected) { return function devToolsMiddleware(req, res, next) { - if (req.url === '/launch-safari-devtools') { - // TODO: remove `logger.info` and dev tools binary - logger.info( - 'We removed support for Safari dev-tools. ' + - 'If you still need this, please let us know.' - ); - } else if (req.url === '/launch-chrome-devtools') { - // TODO: Remove this case in the future - logger.info( - 'The method /launch-chrome-devtools is deprecated. You are ' + - ' probably using an application created with an older CLI with the ' + - ' packager of a newer CLI. Please upgrade your application: ' + - 'https://facebook.github.io/react-native/docs/upgrading.html' - ); - launchDevTools(options, isChromeConnected); - res.end('OK'); - } else if (req.url === '/launch-js-devtools') { + if (req.url === '/launch-js-devtools') { launchDevTools(options, isChromeConnected); res.end('OK'); } else { diff --git a/packages/cli/src/commands/server/middleware/getSecurityHeadersMiddleware.js b/packages/cli/src/commands/server/middleware/getSecurityHeadersMiddleware.js index d5cf6b1452..38de1c2324 100644 --- a/packages/cli/src/commands/server/middleware/getSecurityHeadersMiddleware.js +++ b/packages/cli/src/commands/server/middleware/getSecurityHeadersMiddleware.js @@ -16,7 +16,13 @@ export default function getSecurityHeadersMiddleware(req, res, next) { req.headers.origin && req.headers.origin !== `http://localhost:${address.port}` ) { - next(new Error('Unauthorized')); + next( + new Error( + 'Unauthorized request from ' + + req.headers.origin + + '. This may happen because of a conflicting browser extension. Please try to disable it and try again.', + ), + ); return; } diff --git a/packages/cli/src/commands/server/middleware/logToConsoleMiddleware.js b/packages/cli/src/commands/server/middleware/logToConsoleMiddleware.js new file mode 100644 index 0000000000..e1e245b15a --- /dev/null +++ b/packages/cli/src/commands/server/middleware/logToConsoleMiddleware.js @@ -0,0 +1,37 @@ +'use strict'; + +import chalk from 'chalk'; + +let cache = []; +let timer; + +const log = ({level, data, id}) => { + const logFunction = level !== 'trace' && console[level] ? level : 'log'; + const color = + level === 'error' ? 'red' : level === 'warn' ? 'yellow' : 'white'; + + console[logFunction].apply(console, [ + chalk.inverse[color].bold(` ${level.toUpperCase()} `), + ...data, + ]); +}; + +// Hold messages and flush them to reduce the amount of out-of-order logs +const flush = () => { + timer = null; + cache.sort((a, b) => a.id - b.id).forEach(log); + cache = []; +}; + +export default (req, res, next) => { + if (req.url === '/log-to-console') { + cache.push(JSON.parse(req.rawBody)); + if (!timer) { + timer = setTimeout(flush, 200); + } + + res.end('OK'); + } else { + next(); + } +}; diff --git a/packages/cli/src/commands/server/middleware/openStackFrameInEditorMiddleware.js b/packages/cli/src/commands/server/middleware/openStackFrameInEditorMiddleware.js index 8162bb4585..676ddd49a0 100644 --- a/packages/cli/src/commands/server/middleware/openStackFrameInEditorMiddleware.js +++ b/packages/cli/src/commands/server/middleware/openStackFrameInEditorMiddleware.js @@ -9,7 +9,7 @@ import launchEditor from '../launchEditor'; -export default function getOpenStackFrameInEditorMiddleware({ watchFolders }) { +export default function getOpenStackFrameInEditorMiddleware({watchFolders}) { return (req, res, next) => { if (req.url === '/open-stack-frame') { const frame = JSON.parse(req.rawBody); diff --git a/packages/cli/src/commands/server/middleware/openURLMiddleware.js b/packages/cli/src/commands/server/middleware/openURLMiddleware.js new file mode 100644 index 0000000000..fa0f716b35 --- /dev/null +++ b/packages/cli/src/commands/server/middleware/openURLMiddleware.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import launchBrowser from '../launchBrowser'; +import {logger} from '@react-native-community/cli-tools'; + +/** + * Handle request from JS to open an arbitrary URL in Chrome + */ +export default function openURLMiddleware(req, res, next) { + if (req.url === '/open-url') { + const {url} = JSON.parse(req.rawBody); + logger.info(`Opening ${url}...`); + launchBrowser(url); + res.end('OK'); + } else { + next(); + } +} diff --git a/packages/cli/src/commands/server/middleware/systraceProfileMiddleware.js b/packages/cli/src/commands/server/middleware/systraceProfileMiddleware.js index 5948ab205d..0a54d06872 100644 --- a/packages/cli/src/commands/server/middleware/systraceProfileMiddleware.js +++ b/packages/cli/src/commands/server/middleware/systraceProfileMiddleware.js @@ -8,7 +8,7 @@ */ import fs from 'fs'; -import logger from '../../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; export default function systraceProfileMiddleware(req, res, next) { if (req.url !== '/systrace') { @@ -21,9 +21,9 @@ export default function systraceProfileMiddleware(req, res, next) { fs.writeFileSync(dumpName, req.rawBody); const response = `Your profile was saved at:\n${dumpName}\n\n` + - `On Google Chrome navigate to chrome://tracing and then click on "load" ` + - `to load and visualise your profile.\n\n` + - `This message is also printed to your console by the packager so you can copy it :)`; + 'On Google Chrome navigate to chrome://tracing and then click on "load" ' + + 'to load and visualise your profile.\n\n' + + 'This message is also printed to your console by the packager so you can copy it :)'; logger.info(response); res.end(response); } diff --git a/packages/cli/src/commands/server/runServer.js b/packages/cli/src/commands/server/runServer.js index f1436ed4a4..24e9821a1c 100644 --- a/packages/cli/src/commands/server/runServer.js +++ b/packages/cli/src/commands/server/runServer.js @@ -8,30 +8,27 @@ */ import Metro from 'metro'; - -import { Terminal } from 'metro-core'; - +import {Terminal} from 'metro-core'; import morgan from 'morgan'; import path from 'path'; -import type { ContextT } from '../../tools/types.flow'; +import {logger} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; import messageSocket from './messageSocket'; import webSocketProxy from './webSocketProxy'; import MiddlewareManager from './middleware/MiddlewareManager'; - import loadMetroConfig from '../../tools/loadMetroConfig'; +import releaseChecker from '../../tools/releaseChecker'; export type Args = {| - assetExts?: string[], + assetPlugins?: string[], cert?: string, customLogReporterPath?: string, host?: string, https?: boolean, maxWorkers?: number, key?: string, - nonPersistent?: boolean, platforms?: string[], port?: number, - providesModuleNodeModules?: string[], resetCache?: boolean, sourceExts?: string[], transformer?: string, @@ -40,7 +37,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); @@ -55,16 +52,29 @@ async function runServer(argv: Array, ctx: ContextT, args: Args) { reporter, }); + if (args.assetPlugins) { + metroConfig.transformer.assetPlugins = args.assetPlugins.map(plugin => + require.resolve(plugin), + ); + } + const middlewareManager = new MiddlewareManager({ host: args.host, port: metroConfig.server.port, watchFolders: metroConfig.watchFolders, }); - middlewareManager.getConnectInstance().use(morgan('combined')); + middlewareManager.getConnectInstance().use( + morgan( + 'combined', + !logger.isVerbose() && { + skip: (req, res) => res.statusCode < 400, + }, + ), + ); metroConfig.watchFolders.forEach( - middlewareManager.serveStatic.bind(middlewareManager) + middlewareManager.serveStatic.bind(middlewareManager), ); metroConfig.server.enhanceMiddleware = middleware => @@ -80,7 +90,7 @@ async function runServer(argv: Array, ctx: ContextT, args: Args) { const wsProxy = webSocketProxy.attachToServer( serverInstance, - '/debugger-proxy' + '/debugger-proxy', ); const ms = messageSocket.attachToServer(serverInstance, '/message'); middlewareManager.attachDevToolsSocket(wsProxy); @@ -97,6 +107,8 @@ async function runServer(argv: Array, ctx: ContextT, args: Args) { // For more info: https://github.com/nodejs/node/issues/13391 // serverInstance.keepAliveTimeout = 30000; + + await releaseChecker(ctx.root); } function getReporterImpl(customLogReporterPath: ?string) { diff --git a/packages/cli/src/commands/server/server.js b/packages/cli/src/commands/server/server.js index 6fe1adbb83..ad2deeb7ed 100644 --- a/packages/cli/src/commands/server/server.js +++ b/packages/cli/src/commands/server/server.js @@ -17,45 +17,51 @@ export default { description: 'starts the webserver', options: [ { - command: '--port [number]', + name: '--port [number]', parse: (val: string) => Number(val), }, { - command: '--host [string]', + name: '--host [string]', default: '', }, { - command: '--watchFolders [list]', + name: '--watchFolders [list]', description: 'Specify any additional folders to be added to the watch list', parse: (val: string) => val.split(','), }, { - command: '--assetExts [list]', + name: '--assetPlugins [list]', + description: + 'Specify any additional asset plugins to be used by the packager by full filepath', + parse: (val: string) => val.split(','), + }, + { + name: '--assetExts [list]', description: 'Specify any additional asset extensions to be used by the packager', parse: (val: string) => val.split(','), }, { - command: '--sourceExts [list]', + name: '--sourceExts [list]', description: 'Specify any additional source extensions to be used by the packager', parse: (val: string) => val.split(','), }, { - command: '--platforms [list]', + name: '--platforms [list]', description: 'Specify any additional platforms to be used by the packager', parse: (val: string) => val.split(','), }, { - command: '--providesModuleNodeModules [list]', + name: '--providesModuleNodeModules [list]', description: 'Specify any npm packages that import dependencies with providesModule', parse: (val: string) => val.split(','), }, { - command: '--max-workers [number]', + name: '--max-workers [number]', description: 'Specifies the maximum number of workers the worker-pool ' + 'will spawn for transforming files. This defaults to the number of the ' + @@ -63,44 +69,36 @@ export default { parse: (workers: string) => Number(workers), }, { - command: '--skipflow', - description: 'Disable flow checks', - }, - { - command: '--nonPersistent', - description: 'Disable file watcher', - }, - { - command: '--transformer [string]', + name: '--transformer [string]', description: 'Specify a custom transformer to be used', }, { - command: '--reset-cache, --resetCache', + name: '--reset-cache, --resetCache', description: 'Removes cached files', }, { - command: '--custom-log-reporter-path, --customLogReporterPath [string]', + name: '--custom-log-reporter-path, --customLogReporterPath [string]', description: 'Path to a JavaScript file that exports a log reporter as a replacement for TerminalReporter', }, { - command: '--verbose', + name: '--verbose', description: 'Enables logging', }, { - command: '--https', + name: '--https', description: 'Enables https connections to the server', }, { - command: '--key [path]', + name: '--key [path]', description: 'Path to custom SSL key', }, { - command: '--cert [path]', + name: '--cert [path]', description: 'Path to custom SSL cert', }, { - command: '--config [string]', + name: '--config [string]', description: 'Path to the CLI configuration file', parse: (val: string) => path.resolve(val), }, diff --git a/packages/cli/src/commands/server/webSocketProxy.js b/packages/cli/src/commands/server/webSocketProxy.js index 4d904022cd..d333bbac23 100644 --- a/packages/cli/src/commands/server/webSocketProxy.js +++ b/packages/cli/src/commands/server/webSocketProxy.js @@ -8,7 +8,7 @@ */ import ws from 'ws'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; function attachToServer(server, path) { const WebSocketServer = ws.Server; @@ -42,11 +42,11 @@ function attachToServer(server, path) { const clientSocketCloseHandler = () => { clientSocket = null; - send(debuggerSocket, JSON.stringify({ method: '$disconnected' })); + send(debuggerSocket, JSON.stringify({method: '$disconnected'})); }; wss.on('connection', connection => { - const { url } = connection.upgradeReq; + const {url} = connection.upgradeReq; if (url.indexOf('role=debugger') > -1) { if (debuggerSocket) { @@ -56,7 +56,7 @@ function attachToServer(server, path) { debuggerSocket = connection; debuggerSocket.onerror = debuggerSocketCloseHandler; debuggerSocket.onclose = debuggerSocketCloseHandler; - debuggerSocket.onmessage = ({ data }) => send(clientSocket, data); + debuggerSocket.onmessage = ({data}) => send(clientSocket, data); } else if (url.indexOf('role=client') > -1) { if (clientSocket) { clientSocket.onerror = null; @@ -67,7 +67,7 @@ function attachToServer(server, path) { clientSocket = connection; clientSocket.onerror = clientSocketCloseHandler; clientSocket.onclose = clientSocketCloseHandler; - clientSocket.onmessage = ({ data }) => send(debuggerSocket, data); + clientSocket.onmessage = ({data}) => send(debuggerSocket, data); } else { connection.close(1011, 'Missing role param'); } diff --git a/packages/cli/src/commands/upgrade/__tests__/__snapshots__/upgrade.test.js.snap b/packages/cli/src/commands/upgrade/__tests__/__snapshots__/upgrade.test.js.snap index 13c7caaa89..81f75152a0 100644 --- a/packages/cli/src/commands/upgrade/__tests__/__snapshots__/upgrade.test.js.snap +++ b/packages/cli/src/commands/upgrade/__tests__/__snapshots__/upgrade.test.js.snap @@ -1,27 +1,85 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`fetches regular patch, adds remote, applies patch, installs deps, removes remote,: RnDiffApp is replaced with app name (TestApp) 1`] = ` +exports[`fetches regular patch, adds remote, applies patch, installs deps, removes remote,: RnDiffApp is replaced with app name (TestApp and com.testapp) 1`] = ` "Snapshot Diff: - First value + Second value -@@ -1,5 +1,5 @@ -- diff --git a/RnDiffApp/android/build.gradle b/RnDiffApp/android/build.gradle -+ diff --git a/TestApp/android/build.gradle b/TestApp/android/build.gradle - index 85d8f2f8..a1e80854 100644 -- --- a/RnDiffApp/android/build.gradle -- +++ b/RnDiffApp/android/build.gradle -+ --- a/TestApp/android/build.gradle -+ +++ b/TestApp/android/build.gradle - @@ -9,8 +9,8 @@ buildscript { -@@ -28,6 +28,6 @@ +@@ -1,9 +1,9 @@ +- diff --git a/RnDiffApp/android/app/src/main/AndroidManifest.xml b/RnDiffApp/android/app/src/main/AndroidManifest.xml ++ diff --git a/TestApp/android/app/src/main/AndroidManifest.xml b/TestApp/android/app/src/main/AndroidManifest.xml + index bc3a9310..f3e0d155 100644 +- --- a/RnDiffApp/android/app/src/main/AndroidManifest.xml +- +++ b/RnDiffApp/android/app/src/main/AndroidManifest.xml ++ --- a/TestApp/android/app/src/main/AndroidManifest.xml ++ +++ b/TestApp/android/app/src/main/AndroidManifest.xml + @@ -1,8 +1,7 @@ + +- + package=\\"com.rndiffapp\\"> ++ - package=\\"com.testapp\\"> ++ + package=\\"com.testapp\\"> -- diff --git a/RnDiffApp/package.json b/RnDiffApp/package.json -+ diff --git a/TestApp/package.json b/TestApp/package.json - index 4e617645..c82829bd 100644 -- --- a/RnDiffApp/package.json -- +++ b/RnDiffApp/package.json -+ --- a/TestApp/package.json -+ +++ b/TestApp/package.json - @@ -7,14 +7,14 @@" +@@ -14,6 +14,6 @@ + android:name=\\".MainApplication\\" +- diff --git a/RnDiffApp/ios/RnDiffApp/AppDelegate.h b/RnDiffApp/ios/RnDiffApp/AppDelegate.h ++ diff --git a/TestApp/ios/TestApp/AppDelegate.h b/TestApp/ios/TestApp/AppDelegate.h + index 4b5644f2..2726d5e1 100644 +- --- a/RnDiffApp/ios/RnDiffApp/AppDelegate.h +- +++ b/RnDiffApp/ios/RnDiffApp/AppDelegate.h ++ --- a/TestApp/ios/TestApp/AppDelegate.h ++ +++ b/TestApp/ios/TestApp/AppDelegate.h + @@ -5,9 +5,10 @@ +@@ -29,6 +29,6 @@ + @property (nonatomic, strong) UIWindow *window; +- diff --git a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java ++ diff --git a/TestApp/android/app/src/main/java/com/testapp/MainApplication.java b/TestApp/android/app/src/main/java/com/testapp/MainApplication.java + index bc3a9310..f3e0d155 100644 +- --- a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java +- +++ b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java ++ --- a/TestApp/android/app/src/main/java/com/testapp/MainApplication.java ++ +++ b/TestApp/android/app/src/main/java/com/testapp/MainApplication.java + " +`; + +exports[`works with --name-ios and --name-android: RnDiffApp is replaced with app name (CustomIos and co.uk.customandroid.app) 1`] = ` +"Snapshot Diff: +- First value ++ Second value + +@@ -1,9 +1,9 @@ +- diff --git a/RnDiffApp/android/app/src/main/AndroidManifest.xml b/RnDiffApp/android/app/src/main/AndroidManifest.xml ++ diff --git a/CustomIos/android/app/src/main/AndroidManifest.xml b/CustomIos/android/app/src/main/AndroidManifest.xml + index bc3a9310..f3e0d155 100644 +- --- a/RnDiffApp/android/app/src/main/AndroidManifest.xml +- +++ b/RnDiffApp/android/app/src/main/AndroidManifest.xml ++ --- a/CustomIos/android/app/src/main/AndroidManifest.xml ++ +++ b/CustomIos/android/app/src/main/AndroidManifest.xml + @@ -1,8 +1,7 @@ + +- + package=\\"com.rndiffapp\\"> ++ - package=\\"co.uk.customandroid.app\\"> ++ + package=\\"co.uk.customandroid.app\\"> + +@@ -14,6 +14,6 @@ + android:name=\\".MainApplication\\" +- diff --git a/RnDiffApp/ios/RnDiffApp/AppDelegate.h b/RnDiffApp/ios/RnDiffApp/AppDelegate.h ++ diff --git a/CustomIos/ios/CustomIos/AppDelegate.h b/CustomIos/ios/CustomIos/AppDelegate.h + index 4b5644f2..2726d5e1 100644 +- --- a/RnDiffApp/ios/RnDiffApp/AppDelegate.h +- +++ b/RnDiffApp/ios/RnDiffApp/AppDelegate.h ++ --- a/CustomIos/ios/CustomIos/AppDelegate.h ++ +++ b/CustomIos/ios/CustomIos/AppDelegate.h + @@ -5,9 +5,10 @@ +@@ -29,6 +29,6 @@ + @property (nonatomic, strong) UIWindow *window; +- diff --git a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java ++ diff --git a/CustomIos/android/app/src/main/java/co/uk/customandroid/app/MainApplication.java b/CustomIos/android/app/src/main/java/co/uk/customandroid/app/MainApplication.java + index bc3a9310..f3e0d155 100644 +- --- a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java +- +++ b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java ++ --- a/CustomIos/android/app/src/main/java/co/uk/customandroid/app/MainApplication.java ++ +++ b/CustomIos/android/app/src/main/java/co/uk/customandroid/app/MainApplication.java + " `; diff --git a/packages/cli/src/commands/upgrade/__tests__/sample.patch b/packages/cli/src/commands/upgrade/__tests__/sample.patch index f5f8ef6851..42c5efce44 100644 --- a/packages/cli/src/commands/upgrade/__tests__/sample.patch +++ b/packages/cli/src/commands/upgrade/__tests__/sample.patch @@ -1,51 +1,33 @@ -diff --git a/RnDiffApp/android/build.gradle b/RnDiffApp/android/build.gradle -index 85d8f2f8..a1e80854 100644 ---- a/RnDiffApp/android/build.gradle -+++ b/RnDiffApp/android/build.gradle -@@ -9,8 +9,8 @@ buildscript { - supportLibVersion = "27.1.1" - } - repositories { -- jcenter() - google() -+ jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' -@@ -23,12 +23,12 @@ buildscript { - allprojects { - repositories { - mavenLocal() -+ google() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } -- google() - } - } +diff --git a/RnDiffApp/android/app/src/main/AndroidManifest.xml b/RnDiffApp/android/app/src/main/AndroidManifest.xml +index bc3a9310..f3e0d155 100644 +--- a/RnDiffApp/android/app/src/main/AndroidManifest.xml ++++ b/RnDiffApp/android/app/src/main/AndroidManifest.xml +@@ -1,8 +1,7 @@ + ++ package="com.rndiffapp"> -diff --git a/RnDiffApp/package.json b/RnDiffApp/package.json -index 4e617645..c82829bd 100644 ---- a/RnDiffApp/package.json -+++ b/RnDiffApp/package.json -@@ -7,14 +7,14 @@ - "test": "jest" - }, - "dependencies": { -- "react": "16.5.0", -- "react-native": "0.57.0" -+ "react": "16.6.1", -+ "react-native": "0.57.7" - }, - "devDependencies": { - "babel-jest": "23.6.0", - "jest": "23.6.0", -- "metro-react-native-babel-preset": "0.47.1", -- "react-test-renderer": "16.5.0" -+ "metro-react-native-babel-preset": "0.49.2", -+ "react-test-renderer": "16.6.1" - }, - "jest": { - "preset": "react-native" + +- + + + #import + +-@interface AppDelegate : UIResponder ++@interface AppDelegate : UIResponder + + @property (nonatomic, strong) UIWindow *window; +diff --git a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java +index bc3a9310..f3e0d155 100644 +--- a/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java ++++ b/RnDiffApp/android/app/src/main/java/com/rndiffapp/MainApplication.java diff --git a/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js b/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js index 5a987a6cb1..9f5e11826a 100644 --- a/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js +++ b/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js @@ -3,61 +3,87 @@ import execa from 'execa'; import path from 'path'; import fs from 'fs'; import snapshotDiff from 'snapshot-diff'; +import stripAnsi from 'strip-ansi'; import upgrade from '../upgrade'; -import { fetch } from '../helpers'; +import {fetch} from '../../../tools/fetch'; import logger from '../../../tools/logger'; +import loadConfig from '../../../tools/config'; +import merge from '../../../tools/merge'; jest.mock('https'); jest.mock('fs'); jest.mock('path'); -jest.mock('execa', () => { - const module = jest.fn((command, args) => { - mockPushLog('$', 'execa', command, args); - if (command === 'npm' && args[3] === '--json') { - return Promise.resolve({ - stdout: '{"react": "16.6.3"}', - }); - } - return Promise.resolve({ stdout: '' }); - }); - return module; -}); +jest.mock('execa'); jest.mock( '/project/root/node_modules/react-native/package.json', - () => ({ name: 'react-native', version: '0.57.8' }), - { virtual: true } + () => ({name: 'react-native', version: '0.57.8'}), + {virtual: true}, ); jest.mock( '/project/root/package.json', - () => ({ name: 'TestApp', dependencies: { 'react-native': '^0.57.8' } }), - { virtual: true } + () => ({name: 'TestApp', dependencies: {'react-native': '^0.57.8'}}), + {virtual: true}, +); +jest.mock( + '/project/root/NestedApp/node_modules/react-native/package.json', + () => ({name: 'react-native', version: '0.57.8'}), + {virtual: true}, ); -jest.mock('../../../tools/PackageManager', () => - jest.fn(() => ({ - install: args => { - mockPushLog('$ yarn add', ...args); - }, - })) +jest.mock( + '/project/root/NestedApp/package.json', + () => ({ + name: 'TestAppNested', + dependencies: {'react-native': '^0.57.8'}, + }), + {virtual: true}, ); -jest.mock('../helpers', () => ({ - ...jest.requireActual('../helpers'), +jest.mock('../../../tools/config'); +jest.mock('../../../tools/packageManager', () => ({ + install: args => { + mockPushLog('$ yarn add', ...args); + }, +})); +jest.mock('../../../tools/fetch', () => ({ fetch: jest.fn(() => Promise.resolve('patch')), })); -jest.mock('../../../tools/logger', () => ({ - info: jest.fn((...args) => mockPushLog('info', args)), - error: jest.fn((...args) => mockPushLog('error', args)), - warn: jest.fn((...args) => mockPushLog('warn', args)), - success: jest.fn((...args) => mockPushLog('success', args)), - log: jest.fn((...args) => mockPushLog(args)), +jest.mock('@react-native-community/cli-tools', () => ({ + ...jest.requireActual('@react-native-community/cli-tools'), + logger: { + info: jest.fn((...args) => mockPushLog('info', args)), + error: jest.fn((...args) => mockPushLog('error', args)), + warn: jest.fn((...args) => mockPushLog('warn', args)), + success: jest.fn((...args) => mockPushLog('success', args)), + debug: jest.fn((...args) => mockPushLog('debug', args)), + log: jest.fn((...args) => mockPushLog(args)), + }, })); +const mockExecaDefault = (command, args) => { + mockPushLog('$', 'execa', command, args); + if (command === 'npm' && args[3] === '--json') { + return Promise.resolve({stdout: '{"react": "16.6.3"}'}); + } + if (command === 'git' && args[0] === 'rev-parse') { + return Promise.resolve({stdout: ''}); + } + return Promise.resolve({stdout: ''}); +}; + +const mockExecaNested = (command, args) => { + mockPushLog('$', 'execa', command, args); + if (command === 'npm' && args[3] === '--json') { + return Promise.resolve({stdout: '{"react": "16.6.3"}'}); + } + if (command === 'git' && args[0] === 'rev-parse') { + return Promise.resolve({stdout: 'NestedApp/'}); + } + return Promise.resolve({stdout: ''}); +}; + const currentVersion = '0.57.8'; const newVersion = '0.58.4'; const olderVersion = '0.56.0'; -const ctx = { - root: '/project/root', - reactNativePath: '', -}; +const ctx = loadConfig(); const opts = { legacy: false, }; @@ -69,91 +95,152 @@ const samplePatch = jest let logs = []; const mockPushLog = (...args) => logs.push(args.map(x => (Array.isArray(x) ? x.join(' ') : x)).join(' ')); -const flushOutput = () => logs.join('\n'); +const flushOutput = () => stripAnsi(logs.join('\n')); beforeEach(() => { jest.clearAllMocks(); + jest.restoreAllMocks(); // $FlowFixMe fs.writeFileSync = jest.fn(filename => mockPushLog('[fs] write', filename)); // $FlowFixMe fs.unlinkSync = jest.fn((...args) => mockPushLog('[fs] unlink', args)); logs = []; + (execa: any).mockImplementation(mockExecaDefault); +}); + +afterEach(() => { + // $FlowFixMe + fs.writeFileSync = jest.requireMock('fs').writeFileSync; + // $FlowFixMe + fs.unlinkSync = jest.requireMock('fs').unlinkSync; }); test('uses latest version of react-native when none passed', async () => { await upgrade.func([], ctx, opts); expect(execa).toBeCalledWith('npm', ['info', 'react-native', 'version']); +}, 60000); + +test('applies patch in current working directory when nested', async () => { + (fetch: any).mockImplementation(() => Promise.resolve(samplePatch)); + (execa: any).mockImplementation(mockExecaNested); + const config = {...ctx, root: '/project/root/NestedApp'}; + await upgrade.func([newVersion], config, opts); + + expect(execa).toBeCalledWith('git', [ + 'apply', + 'tmp-upgrade-rn.patch', + '--exclude=NestedApp/package.json', + '-p2', + '--3way', + '--directory=NestedApp/', + ]); }); test('errors when invalid version passed', async () => { await upgrade.func(['next'], ctx, opts); expect(logger.error).toBeCalledWith( - 'Provided version "next" is not allowed. Please pass a valid semver version' + 'Provided version "next" is not allowed. Please pass a valid semver version', ); -}); +}, 60000); test('errors when older version passed', async () => { await upgrade.func([olderVersion], ctx, opts); expect(logger.error).toBeCalledWith( - `Trying to upgrade from newer version "${currentVersion}" to older "${olderVersion}"` + `Trying to upgrade from newer version "${currentVersion}" to older "${olderVersion}"`, ); -}); + await upgrade.func(['0.57.10'], ctx, opts); + expect(logger.error).not.toBeCalledWith( + `Trying to upgrade from newer version "${currentVersion}" to older "0.57.10"`, + ); +}, 60000); test('warns when dependency upgrade version is in semver range', async () => { await upgrade.func([currentVersion], ctx, opts); expect(logger.warn).toBeCalledWith( - `Specified version "${currentVersion}" is already installed in node_modules and it satisfies "^0.57.8" semver range. No need to upgrade` + `Specified version "${currentVersion}" is already installed in node_modules and it satisfies "^0.57.8" semver range. No need to upgrade`, ); -}); +}, 60000); test('fetches empty patch and installs deps', async () => { (fetch: any).mockImplementation(() => Promise.resolve('')); await upgrade.func([newVersion], ctx, opts); expect(flushOutput()).toMatchInlineSnapshot(` -"info Fetching diff between v0.57.8 and v0.58.4... -info Diff has no changes to apply, proceeding further -warn Continuing after failure. Most of the files are upgraded but you will need to deal with some conflicts manually -info Installing react-native@0.58.4 and its peer dependencies... -$ execa npm info react-native@0.58.4 peerDependencies --json -$ yarn add react-native@0.58.4 react@16.6.3 -$ execa git add package.json -$ execa git add yarn.lock -$ execa git add package-lock.json -success Upgraded React Native to v0.58.4 🎉. Now you can review and commit the changes" -`); -}); + "info Fetching diff between v0.57.8 and v0.58.4... + info Diff has no changes to apply, proceeding further + info Installing \\"react-native@0.58.4\\" and its peer dependencies... + $ execa npm info react-native@0.58.4 peerDependencies --json + $ yarn add react-native@0.58.4 react@16.6.3 + $ execa git add package.json + $ execa git add yarn.lock + $ execa git add package-lock.json + success Upgraded React Native to v0.58.4 🎉. Now you can review and commit the changes" + `); +}, 60000); test('fetches regular patch, adds remote, applies patch, installs deps, removes remote,', async () => { (fetch: any).mockImplementation(() => Promise.resolve(samplePatch)); - await upgrade.func([newVersion], ctx, opts); + await upgrade.func( + [newVersion], + merge(ctx, { + project: { + ios: {projectName: 'TestApp.xcodeproj'}, + android: {packageName: 'com.testapp'}, + }, + }), + opts, + ); expect(flushOutput()).toMatchInlineSnapshot(` -"info Fetching diff between v0.57.8 and v0.58.4... -[fs] write tmp-upgrade-rn.patch -$ execa git remote add tmp-rn-diff-purge https://github.com/pvinis/rn-diff-purge.git -$ execa git fetch --no-tags tmp-rn-diff-purge -$ execa git apply --check tmp-upgrade-rn.patch --exclude=package.json -p2 --3way -info Applying diff... -$ execa git apply tmp-upgrade-rn.patch --exclude=package.json -p2 --3way -[fs] unlink tmp-upgrade-rn.patch -info Installing react-native@0.58.4 and its peer dependencies... -$ execa npm info react-native@0.58.4 peerDependencies --json -$ yarn add react-native@0.58.4 react@16.6.3 -$ execa git add package.json -$ execa git add yarn.lock -$ execa git add package-lock.json -info Running \\"git status\\" to check what changed... -$ execa git status -$ execa git remote remove tmp-rn-diff-purge -success Upgraded React Native to v0.58.4 🎉. Now you can review and commit the changes" -`); - + "info Fetching diff between v0.57.8 and v0.58.4... + [fs] write tmp-upgrade-rn.patch + $ execa git rev-parse --show-prefix + $ execa git apply --binary --check tmp-upgrade-rn.patch --exclude=package.json -p2 --3way --directory= + info Applying diff... + $ execa git apply tmp-upgrade-rn.patch --exclude=package.json -p2 --3way --directory= + [fs] unlink tmp-upgrade-rn.patch + $ execa git status -s + info Installing \\"react-native@0.58.4\\" and its peer dependencies... + $ execa npm info react-native@0.58.4 peerDependencies --json + $ yarn add react-native@0.58.4 react@16.6.3 + $ execa git add package.json + $ execa git add yarn.lock + $ execa git add package-lock.json + info Running \\"git status\\" to check what changed... + $ execa git status + success Upgraded React Native to v0.58.4 🎉. Now you can review and commit the changes" + `); expect( - snapshotDiff(samplePatch, fs.writeFileSync.mock.calls[0][1], { + snapshotDiff(samplePatch, (fs.writeFileSync: any).mock.calls[0][1], { contextLines: 1, - }) - ).toMatchSnapshot('RnDiffApp is replaced with app name (TestApp)'); -}); - + }), + ).toMatchSnapshot( + 'RnDiffApp is replaced with app name (TestApp and com.testapp)', + ); +}, 60000); +test('fetches regular patch, adds remote, applies patch, installs deps, removes remote when updated from nested directory', async () => { + (fetch: any).mockImplementation(() => Promise.resolve(samplePatch)); + (execa: any).mockImplementation(mockExecaNested); + const config = {...ctx, root: '/project/root/NestedApp'}; + await upgrade.func([newVersion], config, opts); + expect(flushOutput()).toMatchInlineSnapshot(` + "info Fetching diff between v0.57.8 and v0.58.4... + [fs] write tmp-upgrade-rn.patch + $ execa git rev-parse --show-prefix + $ execa git apply --binary --check tmp-upgrade-rn.patch --exclude=NestedApp/package.json -p2 --3way --directory=NestedApp/ + info Applying diff... + $ execa git apply tmp-upgrade-rn.patch --exclude=NestedApp/package.json -p2 --3way --directory=NestedApp/ + [fs] unlink tmp-upgrade-rn.patch + $ execa git status -s + info Installing \\"react-native@0.58.4\\" and its peer dependencies... + $ execa npm info react-native@0.58.4 peerDependencies --json + $ yarn add react-native@0.58.4 react@16.6.3 + $ execa git add package.json + $ execa git add yarn.lock + $ execa git add package-lock.json + info Running \\"git status\\" to check what changed... + $ execa git status + success Upgraded React Native to v0.58.4 🎉. Now you can review and commit the changes" + `); +}, 60000); test('cleans up if patching fails,', async () => { (fetch: any).mockImplementation(() => Promise.resolve(samplePatch)); (execa: any).mockImplementation((command, args) => { @@ -164,46 +251,67 @@ test('cleans up if patching fails,', async () => { }); } if (command === 'git' && args[0] === 'apply') { - // eslint-disable-next-line prefer-promise-reject-errors return Promise.reject({ code: 1, - stderr: 'error: .flowconfig: does not exist in index\n', + stderr: + 'error: .flowconfig: does not exist in index\nerror: ios/MyApp.xcodeproj/project.pbxproj: patch does not apply', }); } - return Promise.resolve({ stdout: '' }); + if (command === 'git' && args[0] === 'rev-parse') { + return Promise.resolve({stdout: ''}); + } + return Promise.resolve({stdout: ''}); }); - try { await upgrade.func([newVersion], ctx, opts); } catch (error) { expect(error.message).toBe( - 'Upgrade failed. Please see the messages above for details' + 'Upgrade failed. Please see the messages above for details', ); } - expect(flushOutput()).toMatchInlineSnapshot(` -"info Fetching diff between v0.57.8 and v0.58.4... -[fs] write tmp-upgrade-rn.patch -$ execa git remote add tmp-rn-diff-purge https://github.com/pvinis/rn-diff-purge.git -$ execa git fetch --no-tags tmp-rn-diff-purge -$ execa git apply --check tmp-upgrade-rn.patch --exclude=package.json -p2 --3way -info Applying diff (excluding: package.json, .flowconfig)... -$ execa git apply tmp-upgrade-rn.patch --exclude=package.json --exclude=.flowconfig -p2 --3way -error: .flowconfig: does not exist in index -error Automatically applying diff failed -info Here's the diff we tried to apply: https://github.com/pvinis/rn-diff-purge/compare/version/0.57.8...version/0.58.4 -info You may find release notes helpful: https://github.com/facebook/react-native/releases/tag/v0.58.4 -[fs] unlink tmp-upgrade-rn.patch -warn Continuing after failure. Most of the files are upgraded but you will need to deal with some conflicts manually -info Installing react-native@0.58.4 and its peer dependencies... -$ execa npm info react-native@0.58.4 peerDependencies --json -$ yarn add react-native@0.58.4 react@16.6.3 -$ execa git add package.json -$ execa git add yarn.lock -$ execa git add package-lock.json -info Running \\"git status\\" to check what changed... -$ execa git status -$ execa git remote remove tmp-rn-diff-purge -warn Please run \\"git diff\\" to review the conflicts and resolve them" -`); -}); + "info Fetching diff between v0.57.8 and v0.58.4... + [fs] write tmp-upgrade-rn.patch + $ execa git rev-parse --show-prefix + $ execa git apply --binary --check tmp-upgrade-rn.patch --exclude=package.json -p2 --3way --directory= + info Applying diff... + warn Excluding files that exist in the template, but not in your project: + - .flowconfig + error Excluding files that failed to apply the diff: + - ios/MyApp.xcodeproj/project.pbxproj + Please make sure to check the actual changes after the upgrade command is finished. + You can find them in our Upgrade Helper web app: https://react-native-community.github.io/upgrade-helper/?from=0.57.8&to=0.58.4 + $ execa git apply tmp-upgrade-rn.patch --exclude=package.json --exclude=.flowconfig --exclude=ios/MyApp.xcodeproj/project.pbxproj -p2 --3way --directory= + debug \\"git apply\\" failed. Error output: + error: .flowconfig: does not exist in index + error: ios/MyApp.xcodeproj/project.pbxproj: patch does not apply + error Automatically applying diff failed. We did our best to automatically upgrade as many files as possible + [fs] unlink tmp-upgrade-rn.patch + $ execa git status -s + error Patch failed to apply for unknown reason. Please fall back to manual way of upgrading + info You may find these resources helpful: + • Release notes: https://github.com/facebook/react-native/releases/tag/v0.58.4 + • Manual Upgrade Helper: https://react-native-community.github.io/upgrade-helper/?from=0.57.8&to=0.58.4 + • Git diff: https://raw.githubusercontent.com/react-native-community/rn-diff-purge/diffs/diffs/0.57.8..0.58.4.diff" + `); +}, 60000); +test('works with --name-ios and --name-android', async () => { + (fetch: any).mockImplementation(() => Promise.resolve(samplePatch)); + await upgrade.func( + [newVersion], + merge(ctx, { + project: { + ios: {projectName: 'CustomIos.xcodeproj'}, + android: {packageName: 'co.uk.customandroid.app'}, + }, + }), + opts, + ); + expect( + snapshotDiff(samplePatch, (fs.writeFileSync: any).mock.calls[0][1], { + contextLines: 1, + }), + ).toMatchSnapshot( + 'RnDiffApp is replaced with app name (CustomIos and co.uk.customandroid.app)', + ); +}, 60000); diff --git a/packages/cli/src/commands/upgrade/legacyUpgrade.js b/packages/cli/src/commands/upgrade/legacyUpgrade.js index 64d9912342..679e7a44b9 100644 --- a/packages/cli/src/commands/upgrade/legacyUpgrade.js +++ b/packages/cli/src/commands/upgrade/legacyUpgrade.js @@ -11,19 +11,19 @@ import fs from 'fs'; import path from 'path'; import semver from 'semver'; -import type { ContextT } from '../../tools/types.flow'; -import logger from '../../tools/logger'; +import type {ConfigT} from 'types'; +import {logger} from '@react-native-community/cli-tools'; import copyProjectTemplateAndReplace from '../../tools/generator/copyProjectTemplateAndReplace'; /** * 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( - fs.readFileSync(path.resolve(projectDir, 'package.json'), 'utf8') + fs.readFileSync(path.resolve(projectDir, 'package.json'), 'utf8'), ); warn( @@ -33,14 +33,14 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { '- Go back to the old version of React Native\n' + '- Run "npm install -g react-native-git-upgrade"\n' + '- Run "react-native-git-upgrade"\n' + - 'See https://facebook.github.io/react-native/docs/upgrading.html' + 'See https://facebook.github.io/react-native/docs/upgrading.html', ); const projectName = packageJSON.name; if (!projectName) { warn( 'Your project needs to have a name, declared in package.json, ' + - 'such as "name": "AwesomeApp". Please add a project name. Aborting.' + 'such as "name": "AwesomeApp". Please add a project name. Aborting.', ); return; } @@ -49,7 +49,7 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { if (!version) { warn( 'Your "package.json" file doesn\'t seem to declare "react-native" as ' + - 'a dependency. Nothing to upgrade. Aborting.' + 'a dependency. Nothing to upgrade. Aborting.', ); return; } @@ -58,7 +58,7 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { warn( 'Some major releases introduce breaking changes.\n' + 'Please use a caret version number in your "package.json" file \n' + - 'to avoid breakage. Use e.g. react-native: ^0.38.0. Aborting.' + 'to avoid breakage. Use e.g. react-native: ^0.38.0. Aborting.', ); return; } @@ -66,15 +66,15 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { const installed = JSON.parse( fs.readFileSync( path.resolve(projectDir, 'node_modules/react-native/package.json'), - 'utf8' - ) + 'utf8', + ), ); if (!semver.satisfies(installed.version, version)) { warn( 'react-native version in "package.json" doesn\'t match ' + 'the installed version in "node_modules".\n' + - 'Try running "npm install" to fix this. Aborting.' + 'Try running "npm install" to fix this. Aborting.', ); return; } @@ -84,17 +84,17 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { if (!semver.valid(v)) { warn( "A valid version number for 'react-native' is not specified in your " + - "'package.json' file. Aborting." + "'package.json' file. Aborting.", ); return; } logger.info( `Upgrading project to react-native v${installed.version}\n` + - `Check out the release notes and breaking changes: ` + + 'Check out the release notes and breaking changes: ' + `https://github.com/facebook/react-native/releases/tag/v${semver.major( - v - )}.${semver.minor(v)}.0` + v, + )}.${semver.minor(v)}.0`, ); // >= v0.21.0, we require react to be a peer dependency @@ -103,7 +103,7 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { 'Your "package.json" file doesn\'t seem to have "react" as a dependency.\n' + '"react" was changed from a dependency to a peer dependency in react-native v0.21.0.\n' + 'Therefore, it\'s necessary to include "react" in your project\'s dependencies.\n' + - 'Please run "npm install --save react", then re-run "react-native upgrade".\n' + 'Please run "npm install --save react", then re-run "react-native upgrade".\n', ); return; } @@ -115,14 +115,14 @@ function validateAndUpgrade(argv: Array, ctx: ContextT) { 'to do it automatically.\n' + 'Just run:\n' + '"npm install -g rnpm && npm install rnpm-plugin-upgrade@0.26 --save-dev", ' + - 'then run "rnpm upgrade".' + 'then run "rnpm upgrade".', ); } upgradeProjectFiles(projectDir, projectName); logger.info( - `Successfully upgraded this project to react-native v${installed.version}` + `Successfully upgraded this project to react-native v${installed.version}`, ); } @@ -135,7 +135,7 @@ function upgradeProjectFiles(projectDir, projectName) { path.dirname(require.resolve('react-native/template')), projectDir, projectName, - { upgrade: true } + {upgrade: true}, ); } diff --git a/packages/cli/src/commands/upgrade/upgrade.js b/packages/cli/src/commands/upgrade/upgrade.js index 00db8441d2..d3cbb50851 100644 --- a/packages/cli/src/commands/upgrade/upgrade.js +++ b/packages/cli/src/commands/upgrade/upgrade.js @@ -1,32 +1,36 @@ // @flow -/* eslint-disable consistent-return */ import path from 'path'; import fs from 'fs'; import chalk from 'chalk'; import semver from 'semver'; import execa from 'execa'; -import type { ContextT } from '../../tools/types.flow'; -import logger from '../../tools/logger'; -import PackageManager from '../../tools/PackageManager'; -import { fetch } from './helpers'; +import type {ConfigT} from 'types'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import * as PackageManager from '../../tools/packageManager'; +import {fetch} from '../../tools/fetch'; import legacyUpgrade from './legacyUpgrade'; type FlagsT = { - legacy: boolean, + legacy: boolean | void, }; -const rnDiffPurgeUrl = 'https://github.com/pvinis/rn-diff-purge'; +// https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.0-rc.3 +const webDiffUrl = 'https://react-native-community.github.io/upgrade-helper'; +const rawDiffUrl = + 'https://raw.githubusercontent.com/react-native-community/rn-diff-purge/diffs/diffs'; const getLatestRNVersion = async (): Promise => { logger.info('No version passed. Fetching latest...'); - const { stdout } = await execa('npm', ['info', 'react-native', 'version']); + // $FlowFixMe - this is public API + const {stdout} = await execa('npm', ['info', 'react-native', 'version']); return stdout; }; const getRNPeerDeps = async ( - version: string -): Promise<{ [key: string]: string }> => { - const { stdout } = await execa('npm', [ + version: string, +): Promise<{[key: string]: string}> => { + // $FlowFixMe - this is public API + const {stdout} = await execa('npm', [ 'info', `react-native@${version}`, 'peerDependencies', @@ -36,31 +40,57 @@ const getRNPeerDeps = async ( return JSON.parse(stdout); }; -const getPatch = async (currentVersion, newVersion, projectDir) => { +const getPatch = async (currentVersion, newVersion, config) => { let patch; - const rnDiffAppName = 'RnDiffApp'; - const { name } = require(path.join(projectDir, 'package.json')); - logger.info(`Fetching diff between v${currentVersion} and v${newVersion}...`); try { - patch = await fetch( - `${rnDiffPurgeUrl}/compare/version/${currentVersion}...version/${newVersion}.diff` - ); + patch = await fetch(`${rawDiffUrl}/${currentVersion}..${newVersion}.diff`); } catch (error) { logger.error( - `Failed to fetch diff for react-native@${newVersion}. Maybe it's not released yet?` + `Failed to fetch diff for react-native@${newVersion}. Maybe it's not released yet?`, ); logger.info( - `For available releases to diff see: https://github.com/pvinis/rn-diff-purge#version-changes` + `For available releases to diff see: ${chalk.underline.dim( + 'https://github.com/react-native-community/rn-diff-purge#diff-table-full-table-here', + )}`, ); return null; } - return patch - .replace(new RegExp(rnDiffAppName, 'g'), name) - .replace(new RegExp(rnDiffAppName.toLowerCase(), 'g'), name.toLowerCase()); + let patchWithRenamedProjects = patch; + + Object.keys(config.project).forEach(platform => { + if (!config.project[platform]) { + return; + } + if (platform === 'ios') { + patchWithRenamedProjects = patchWithRenamedProjects.replace( + new RegExp('RnDiffApp', 'g'), + // $FlowFixMe - poor typings of ProjectConfigIOST + config.project[platform].projectName.replace('.xcodeproj', ''), + ); + } else if (platform === 'android') { + patchWithRenamedProjects = patchWithRenamedProjects + .replace( + new RegExp('com\\.rndiffapp', 'g'), + // $FlowFixMe - poor typings of ProjectConfigAndroidT + config.project[platform].packageName, + ) + .replace( + new RegExp('com\\.rndiffapp'.split('.').join('/'), 'g'), + // $FlowFixMe - poor typings of ProjectConfigAndroidT + config.project[platform].packageName.split('.').join('/'), + ); + } else { + logger.warn( + `Unsupported platform: "${platform}". \`upgrade\` only supports iOS and Android.`, + ); + } + }); + + return patchWithRenamedProjects; }; const getVersionToUpgradeTo = async (argv, currentVersion, projectDir) => { @@ -73,30 +103,30 @@ const getVersionToUpgradeTo = async (argv, currentVersion, projectDir) => { logger.error( `Provided version "${ argv[0] - }" is not allowed. Please pass a valid semver version` + }" is not allowed. Please pass a valid semver version`, ); return null; } - if (currentVersion > newVersion) { + if (semver.gt(currentVersion, newVersion)) { logger.error( - `Trying to upgrade from newer version "${currentVersion}" to older "${newVersion}"` + `Trying to upgrade from newer version "${currentVersion}" to older "${newVersion}"`, ); return null; } - if (currentVersion === newVersion) { + if (semver.eq(currentVersion, newVersion)) { const { - dependencies: { 'react-native': version }, + dependencies: {'react-native': version}, } = require(path.join(projectDir, 'package.json')); if (semver.satisfies(newVersion, version)) { logger.warn( - `Specified version "${newVersion}" is already installed in node_modules and it satisfies "${version}" semver range. No need to upgrade` + `Specified version "${newVersion}" is already installed in node_modules and it satisfies "${version}" semver range. No need to upgrade`, ); return null; } logger.error( - `Dependency mismatch. Specified version "${newVersion}" is already installed in node_modules and it doesn't satisfy "${version}" semver range of your "react-native" dependency. Please re-install your dependencies` + `Dependency mismatch. Specified version "${newVersion}" is already installed in node_modules and it doesn't satisfy "${version}" semver range of your "react-native" dependency. Please re-install your dependencies`, ); return null; } @@ -104,22 +134,18 @@ const getVersionToUpgradeTo = async (argv, currentVersion, projectDir) => { return newVersion; }; -const installDeps = async (newVersion, projectDir, patchSuccess) => { - if (!patchSuccess) { - logger.warn( - 'Continuing after failure. Most of the files are upgraded but you will need to deal with some conflicts manually' - ); - } +const installDeps = async (newVersion, projectDir) => { logger.info( - `Installing react-native@${newVersion} and its peer dependencies...` + `Installing "react-native@${newVersion}" and its peer dependencies...`, ); const peerDeps = await getRNPeerDeps(newVersion); - const pm = new PackageManager({ projectDir }); const deps = [ `react-native@${newVersion}`, ...Object.keys(peerDeps).map(module => `${module}@${peerDeps[module]}`), ]; - await pm.install(deps, { silent: true }); + await PackageManager.install(deps, { + silent: true, + }); await execa('git', ['add', 'package.json']); try { await execa('git', ['add', 'yarn.lock']); @@ -136,45 +162,86 @@ const installDeps = async (newVersion, projectDir, patchSuccess) => { const applyPatch = async ( currentVersion: string, newVersion: string, - tmpPatchFile: string + tmpPatchFile: string, ) => { - let filesToExclude = ['package.json']; + const defaultExcludes = ['package.json']; + let filesThatDontExist = []; + let filesThatFailedToApply = []; + // $FlowFixMe ThenableChildProcess is incompatible with Promise + const {stdout: relativePathFromRoot} = await execa('git', [ + 'rev-parse', + '--show-prefix', + ]); try { try { - const excludes = filesToExclude.map(e => `--exclude=${e}`); + const excludes = defaultExcludes.map( + e => `--exclude=${path.join(relativePathFromRoot, e)}`, + ); await execa('git', [ 'apply', + // According to git documentation, `--binary` flag is turned on by + // default. However it's necessary when running `git apply --check` to + // actually accept binary files, maybe a bug in git? + '--binary', '--check', tmpPatchFile, ...excludes, '-p2', '--3way', + `--directory=${relativePathFromRoot}`, ]); - logger.info(`Applying diff...`); + logger.info('Applying diff...'); } catch (error) { - filesToExclude = [ - ...filesToExclude, - ...error.stderr - .split('\n') + const errorLines = error.stderr.split('\n'); + filesThatDontExist = [ + ...errorLines .filter(x => x.includes('does not exist in index')) .map(x => x.replace(/^error: (.*): does not exist in index$/, '$1')), ].filter(Boolean); - logger.info(`Applying diff (excluding: ${filesToExclude.join(', ')})...`); + filesThatFailedToApply = errorLines + .filter(x => x.includes('patch does not apply')) + .map(x => x.replace(/^error: (.*): patch does not apply$/, '$1')) + .filter(Boolean); + + logger.info('Applying diff...'); + logger.warn( + `Excluding files that exist in the template, but not in your project:\n${filesThatDontExist + .map(file => ` - ${chalk.bold(file)}`) + .join('\n')}`, + ); + if (filesThatFailedToApply.length) { + logger.error( + `Excluding files that failed to apply the diff:\n${filesThatFailedToApply + .map(file => ` - ${chalk.bold(file)}`) + .join( + '\n', + )}\nPlease make sure to check the actual changes after the upgrade command is finished.\nYou can find them in our Upgrade Helper web app: ${chalk.underline.dim( + `${webDiffUrl}/?from=${currentVersion}&to=${newVersion}`, + )}`, + ); + } } finally { - const excludes = filesToExclude.map(e => `--exclude=${e}`); - await execa('git', ['apply', tmpPatchFile, ...excludes, '-p2', '--3way']); + const excludes = [ + ...defaultExcludes, + ...filesThatDontExist, + ...filesThatFailedToApply, + ].map(e => `--exclude=${path.join(relativePathFromRoot, e)}`); + await execa('git', [ + 'apply', + tmpPatchFile, + ...excludes, + '-p2', + '--3way', + `--directory=${relativePathFromRoot}`, + ]); } } catch (error) { if (error.stderr) { - logger.log(`${chalk.dim(error.stderr.trim())}`); + logger.debug(`"git apply" failed. Error output:\n${error.stderr}`); } - logger.error('Automatically applying diff failed'); - logger.info( - `Here's the diff we tried to apply: ${rnDiffPurgeUrl}/compare/version/${currentVersion}...version/${newVersion}` - ); - logger.info( - `You may find release notes helpful: https://github.com/facebook/react-native/releases/tag/v${newVersion}` + logger.error( + 'Automatically applying diff failed. We did our best to automatically upgrade as many files as possible', ); return false; } @@ -184,30 +251,28 @@ 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); } - const rnDiffGitAddress = `https://github.com/pvinis/rn-diff-purge.git`; - const tmpRemote = 'tmp-rn-diff-purge'; const tmpPatchFile = 'tmp-upgrade-rn.patch'; const projectDir = ctx.root; - const { version: currentVersion } = require(path.join( + const {version: currentVersion} = require(path.join( projectDir, - 'node_modules/react-native/package.json' + 'node_modules/react-native/package.json', )); const newVersion = await getVersionToUpgradeTo( argv, currentVersion, - projectDir + projectDir, ); if (!newVersion) { return; } - const patch = await getPatch(currentVersion, newVersion, projectDir); + const patch = await getPatch(currentVersion, newVersion, ctx); if (patch === null) { return; @@ -217,21 +282,15 @@ async function upgrade(argv: Array, ctx: ContextT, args: FlagsT) { logger.info('Diff has no changes to apply, proceeding further'); await installDeps(newVersion, projectDir); logger.success( - `Upgraded React Native to v${newVersion} 🎉. Now you can review and commit the changes` + `Upgraded React Native to v${newVersion} 🎉. Now you can review and commit the changes`, ); return; } - let patchSuccess; try { fs.writeFileSync(tmpPatchFile, patch); - await execa('git', ['remote', 'add', tmpRemote, rnDiffGitAddress]); - await execa('git', ['fetch', '--no-tags', tmpRemote]); patchSuccess = await applyPatch(currentVersion, newVersion, tmpPatchFile); - if (!patchSuccess) { - return; - } } catch (error) { throw new Error(error.stderr || error); } finally { @@ -240,27 +299,51 @@ async function upgrade(argv: Array, ctx: ContextT, args: FlagsT) { } catch (e) { // ignore } - await installDeps(newVersion, projectDir, patchSuccess); - logger.info('Running "git status" to check what changed...'); - await execa('git', ['status'], { stdio: 'inherit' }); - await execa('git', ['remote', 'remove', tmpRemote]); - + const {stdout} = await execa('git', ['status', '-s']); if (!patchSuccess) { - logger.warn( - 'Please run "git diff" to review the conflicts and resolve them' - ); - // eslint-disable-next-line no-unsafe-finally - throw new Error( - 'Upgrade failed. Please see the messages above for details' + if (stdout) { + logger.warn( + 'Continuing after failure. Some of the files are upgraded but you will need to deal with conflicts manually', + ); + await installDeps(newVersion, projectDir); + logger.info('Running "git status" to check what changed...'); + await execa('git', ['status'], {stdio: 'inherit'}); + } else { + logger.error( + 'Patch failed to apply for unknown reason. Please fall back to manual way of upgrading', + ); + } + } else { + await installDeps(newVersion, projectDir); + logger.info('Running "git status" to check what changed...'); + await execa('git', ['status'], {stdio: 'inherit'}); + } + if (!patchSuccess) { + if (stdout) { + logger.warn( + 'Please run "git diff" to review the conflicts and resolve them', + ); + } + logger.info(`You may find these resources helpful: +• Release notes: ${chalk.underline.dim( + `https://github.com/facebook/react-native/releases/tag/v${newVersion}`, + )} +• Manual Upgrade Helper: ${chalk.underline.dim( + `${webDiffUrl}/?from=${currentVersion}&to=${newVersion}`, + )} +• Git diff: ${chalk.underline.dim( + `${rawDiffUrl}/${currentVersion}..${newVersion}.diff`, + )}`); + + throw new CLIError( + 'Upgrade failed. Please see the messages above for details', ); } } - logger.success( - `Upgraded React Native to v${newVersion} 🎉. Now you can review and commit the changes` + `Upgraded React Native to v${newVersion} 🎉. Now you can review and commit the changes`, ); } - const upgradeCommand = { name: 'upgrade [version]', description: @@ -268,12 +351,11 @@ const upgradeCommand = { func: upgrade, options: [ { - command: '--legacy', + name: '--legacy [boolean]', description: "Legacy implementation. 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', }, ], }; - export default upgradeCommand; diff --git a/packages/cli/src/tools/PackageManager.js b/packages/cli/src/tools/PackageManager.js deleted file mode 100644 index a586dd3c9f..0000000000 --- a/packages/cli/src/tools/PackageManager.js +++ /dev/null @@ -1,53 +0,0 @@ -// @flow -import { execSync } from 'child_process'; -import yarn from './yarn'; - -type PackageManagerOptions = { - forceNpm?: boolean, - projectDir: string, -}; - -export default class PackageManager { - options: PackageManagerOptions; - - constructor(options: PackageManagerOptions) { - this.options = options; - } - - executeCommand(command: string, options?: { silent: boolean }) { - return execSync(command, { - stdio: options && options.silent ? 'pipe' : 'inherit', - }); - } - - shouldCallYarn() { - return ( - !this.options.forceNpm && - yarn.getYarnVersionIfAvailable() && - yarn.isGlobalCliUsingYarn(this.options.projectDir) - ); - } - - install(packageNames: Array, options?: { silent: boolean }) { - return this.shouldCallYarn() - ? this.executeCommand(`yarn add ${packageNames.join(' ')}`, options) - : this.executeCommand( - `npm install ${packageNames.join(' ')} --save --save-exact`, - options - ); - } - - installDev(packageNames: Array) { - return this.shouldCallYarn() - ? this.executeCommand(`yarn add -D ${packageNames.join(' ')}`) - : this.executeCommand( - `npm install ${packageNames.join(' ')} --save-dev --save-exact` - ); - } - - uninstall(packageNames: Array) { - return this.shouldCallYarn() - ? this.executeCommand(`yarn remove ${packageNames.join(' ')}`) - : this.executeCommand(`npm uninstall ${packageNames.join(' ')} --save`); - } -} diff --git a/packages/cli/src/tools/__fixtures__/commands.js b/packages/cli/src/tools/__fixtures__/commands.js deleted file mode 100644 index 5331649a7b..0000000000 --- a/packages/cli/src/tools/__fixtures__/commands.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -exports.single = { - func: () => {}, - description: 'Test action', - name: 'test', -}; - -exports.multiple = [ - { - func: () => {}, - description: 'Test action #1', - name: 'test1', - }, - { - func: () => {}, - description: 'Test action #2', - name: 'test2', - }, -]; diff --git a/packages/cli/src/tools/__fixtures__/dependencies.js b/packages/cli/src/tools/__fixtures__/dependencies.js deleted file mode 100644 index 73de8974ca..0000000000 --- a/packages/cli/src/tools/__fixtures__/dependencies.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import path from 'path'; -import android from './android'; - -const fs = jest.requireActual('fs'); - -const pjson = fs.readFileSync(path.join(__dirname, 'files', 'package.json')); - -export default { - valid: { - 'package.json': pjson, - android: android.valid, - }, - withAssets: { - 'package.json': pjson, - android: android.valid, - fonts: { - 'A.ttf': '', - 'B.ttf': '', - }, - images: { - 'C.jpg': '', - }, - }, - noPackage: { - 'package.json': pjson, - android: android.noPackage, - }, -}; diff --git a/packages/cli/src/tools/__fixtures__/ios.js b/packages/cli/src/tools/__fixtures__/ios.js deleted file mode 100644 index 9e4ac610fd..0000000000 --- a/packages/cli/src/tools/__fixtures__/ios.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import path from 'path'; - -const fs = jest.requireActual('fs'); - -exports.valid = { - 'demoProject.xcodeproj': { - 'project.pbxproj': fs.readFileSync( - path.join(__dirname, './files/project.pbxproj') - ), - }, - 'TestPod.podspec': 'empty', -}; - -exports.validTestName = { - 'MyTestProject.xcodeproj': { - 'project.pbxproj': fs.readFileSync( - path.join(__dirname, './files/project.pbxproj') - ), - }, -}; - -exports.pod = { - 'TestPod.podspec': 'empty', -}; diff --git a/packages/cli/src/tools/__fixtures__/projects.js b/packages/cli/src/tools/__fixtures__/projects.js deleted file mode 100644 index 321d50cb00..0000000000 --- a/packages/cli/src/tools/__fixtures__/projects.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import android from './android'; -import ios from './ios'; - -const flat = { - android: android.valid, - ios: ios.valid, - Podfile: 'empty', -}; - -const nested = { - android: { - app: android.valid, - }, - ios: ios.valid, -}; - -const withExamples = { - Examples: flat, - ios: ios.valid, - android: android.valid, -}; - -const withPods = { - Podfile: 'content', - ios: ios.pod, -}; - -export default { flat, nested, withExamples, withPods }; - -// export { flat, nested, withExamples, withPods }; diff --git a/packages/cli/src/tools/__tests__/PackageManager-test.js b/packages/cli/src/tools/__tests__/PackageManager-test.js deleted file mode 100644 index 522bd9b6dd..0000000000 --- a/packages/cli/src/tools/__tests__/PackageManager-test.js +++ /dev/null @@ -1,122 +0,0 @@ -// @flow -import ChildProcess from 'child_process'; -import PackageManager from '../PackageManager'; -import yarn from '../yarn'; - -const PROJECT_DIR = '/project/directory'; -const PACKAGES = ['react', 'react-native']; -const EXEC_OPTS = { stdio: 'inherit' }; - -beforeEach(() => { - jest.spyOn(ChildProcess, 'execSync').mockImplementation(() => {}); -}); - -describe('yarn', () => { - beforeEach(() => { - jest - .spyOn(yarn, 'getYarnVersionIfAvailable') - .mockImplementation(() => true); - jest.spyOn(yarn, 'isGlobalCliUsingYarn').mockImplementation(() => true); - }); - - it('should install', () => { - const packageManager = new PackageManager({ projectDir: PROJECT_DIR }); - - packageManager.install(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - 'yarn add react react-native', - EXEC_OPTS - ); - }); - - it('should installDev', () => { - const packageManager = new PackageManager({ projectDir: PROJECT_DIR }); - - packageManager.installDev(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - 'yarn add -D react react-native', - EXEC_OPTS - ); - }); - - it('should uninstall', () => { - const packageManager = new PackageManager({ projectDir: PROJECT_DIR }); - - packageManager.uninstall(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - `yarn remove react react-native`, - EXEC_OPTS - ); - }); -}); - -describe('npm', () => { - it('should install', () => { - const packageManager = new PackageManager({ - projectDir: PROJECT_DIR, - forceNpm: true, - }); - - packageManager.install(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - 'npm install react react-native --save --save-exact', - EXEC_OPTS - ); - }); - - it('should installDev', () => { - const packageManager = new PackageManager({ - projectDir: PROJECT_DIR, - forceNpm: true, - }); - - packageManager.installDev(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - 'npm install react react-native --save-dev --save-exact', - EXEC_OPTS - ); - }); - - it('should uninstall', () => { - const packageManager = new PackageManager({ - projectDir: PROJECT_DIR, - forceNpm: true, - }); - - packageManager.uninstall(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - `npm uninstall react react-native --save`, - EXEC_OPTS - ); - }); -}); - -it('should use npm if yarn is not available', () => { - jest.spyOn(yarn, 'getYarnVersionIfAvailable').mockImplementation(() => false); - const packageManager = new PackageManager({ projectDir: PROJECT_DIR }); - - packageManager.install(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - `npm install react react-native --save --save-exact`, - EXEC_OPTS - ); -}); - -it('should use npm if global cli is not using yarn', () => { - jest.spyOn(yarn, 'isGlobalCliUsingYarn').mockImplementation(() => false); - const packageManager = new PackageManager({ projectDir: PROJECT_DIR }); - - packageManager.install(PACKAGES); - - expect(ChildProcess.execSync).toHaveBeenCalledWith( - `npm install react react-native --save --save-exact`, - EXEC_OPTS - ); -}); diff --git a/packages/cli/src/tools/__tests__/__fixtures__/binary.keystore b/packages/cli/src/tools/__tests__/__fixtures__/binary.keystore new file mode 100644 index 0000000000..364e105ed3 Binary files /dev/null and b/packages/cli/src/tools/__tests__/__fixtures__/binary.keystore differ diff --git a/packages/cli/src/tools/__tests__/__fixtures__/extraDir/file3 b/packages/cli/src/tools/__tests__/__fixtures__/extraDir/file3 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/tools/__tests__/__fixtures__/file1.js b/packages/cli/src/tools/__tests__/__fixtures__/file1.js new file mode 100644 index 0000000000..bd816eaba4 --- /dev/null +++ b/packages/cli/src/tools/__tests__/__fixtures__/file1.js @@ -0,0 +1 @@ +module.exports = 1; diff --git a/packages/cli/src/tools/__tests__/__fixtures__/file2.txt b/packages/cli/src/tools/__tests__/__fixtures__/file2.txt new file mode 100644 index 0000000000..6c493ff740 --- /dev/null +++ b/packages/cli/src/tools/__tests__/__fixtures__/file2.txt @@ -0,0 +1 @@ +file2 diff --git a/packages/cli/src/tools/__tests__/copyFiles.test.js b/packages/cli/src/tools/__tests__/copyFiles.test.js new file mode 100644 index 0000000000..477d4721d8 --- /dev/null +++ b/packages/cli/src/tools/__tests__/copyFiles.test.js @@ -0,0 +1,61 @@ +// @flow +import fs from 'fs'; +import path from 'path'; +import copyFiles from '../copyFiles'; +import {cleanup, getTempDirectory} from '../../../../../jest/helpers'; + +const DIR = getTempDirectory('copyFiles-test'); + +beforeEach(() => { + cleanup(DIR); + fs.mkdirSync(DIR); +}); + +afterEach(() => { + cleanup(DIR); +}); + +test('copies text and binary files from source to destination', async () => { + const src = path.resolve(__dirname, './__fixtures__'); + await copyFiles(src, DIR); + + expect(fs.readdirSync(DIR)).toMatchInlineSnapshot(` + Array [ + "binary.keystore", + "extraDir", + "file1.js", + "file2.txt", + ] + `); + + ['binary.keystore', 'file1.js', 'file2.txt'].forEach(file => { + expect(fs.readFileSync(path.join(src, file))).toEqual( + fs.readFileSync(path.join(DIR, file)), + ); + }); + + expect(fs.readdirSync(path.join(DIR, 'extraDir'))).toMatchInlineSnapshot(` + Array [ + "file3", + ] + `); + + expect(fs.readFileSync(path.join(src, 'extraDir', 'file3'))).toEqual( + fs.readFileSync(path.join(DIR, 'extraDir', 'file3')), + ); +}); + +test('copies files from source to destination excluding directory', async () => { + const src = path.resolve(__dirname, './__fixtures__'); + await copyFiles(src, DIR, { + exclude: [new RegExp(path.join(src, 'extraDir'))], + }); + + expect(fs.readdirSync(DIR)).toMatchInlineSnapshot(` + Array [ + "binary.keystore", + "file1.js", + "file2.txt", + ] + `); +}); diff --git a/packages/cli/src/tools/__tests__/findPlugins-test.js b/packages/cli/src/tools/__tests__/findPlugins-test.js deleted file mode 100644 index 464165d1be..0000000000 --- a/packages/cli/src/tools/__tests__/findPlugins-test.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -import findPlugins from '../findPlugins'; - -const path = require('path'); - -const ROOT = path.join(__dirname, '..', '..'); -const pjsonPath = path.join(ROOT, './package.json'); - -describe('findPlugins', () => { - beforeEach(() => { - jest.resetModules(); - }); - - it('returns an array of dependencies', () => { - jest.doMock( - pjsonPath, - () => ({ - dependencies: { 'rnpm-plugin-test': '*' }, - }), - { virtual: true } - ); - - expect(findPlugins(ROOT)).toHaveProperty('commands'); - expect(findPlugins(ROOT)).toHaveProperty('platforms'); - expect(findPlugins(ROOT).commands).toHaveLength(1); - expect(findPlugins(ROOT).commands[0]).toBe('rnpm-plugin-test'); - expect(findPlugins(ROOT).platforms).toHaveLength(0); - }); - - it('returns an empty array if there are no plugins in this folder', () => { - jest.doMock(pjsonPath, () => ({}), { virtual: true }); - expect(findPlugins(ROOT)).toHaveProperty('commands'); - expect(findPlugins(ROOT)).toHaveProperty('platforms'); - expect(findPlugins(ROOT).commands).toHaveLength(0); - expect(findPlugins(ROOT).platforms).toHaveLength(0); - }); - - it('returns an object with empty arrays if there is no package.json in the supplied folder', () => { - expect(findPlugins('fake-path')).toHaveProperty('commands'); - expect(findPlugins('fake-path')).toHaveProperty('platforms'); - expect(findPlugins('fake-path').commands).toHaveLength(0); - expect(findPlugins('fake-path').platforms).toHaveLength(0); - }); - - it('returns plugins from both dependencies and dev dependencies', () => { - jest.doMock( - pjsonPath, - () => ({ - dependencies: { 'rnpm-plugin-test': '*' }, - devDependencies: { 'rnpm-plugin-test-2': '*' }, - }), - { virtual: true } - ); - expect(findPlugins(ROOT)).toHaveProperty('commands'); - expect(findPlugins(ROOT)).toHaveProperty('platforms'); - expect(findPlugins(ROOT).commands).toHaveLength(2); - expect(findPlugins(ROOT).platforms).toHaveLength(0); - }); - - it('returns unique list of plugins', () => { - jest.doMock( - pjsonPath, - () => ({ - dependencies: { 'rnpm-plugin-test': '*' }, - devDependencies: { 'rnpm-plugin-test': '*' }, - }), - { virtual: true } - ); - expect(findPlugins(ROOT).commands).toHaveLength(1); - }); - - it('returns plugins in scoped modules', () => { - jest.doMock( - pjsonPath, - () => ({ - dependencies: { - '@org/rnpm-plugin-test': '*', - '@org/react-native-test': '*', - '@react-native/test': '*', - '@react-native-org/test': '*', - }, - }), - { virtual: true } - ); - - expect(findPlugins(ROOT)).toHaveProperty('commands'); - expect(findPlugins(ROOT)).toHaveProperty('platforms'); - expect(findPlugins(ROOT).commands[0]).toBe('@org/rnpm-plugin-test'); - }); -}); diff --git a/packages/cli/src/tools/__tests__/ios/findPodfilePath-test.js b/packages/cli/src/tools/__tests__/ios/findPodfilePath-test.js deleted file mode 100644 index c7cd37ded1..0000000000 --- a/packages/cli/src/tools/__tests__/ios/findPodfilePath-test.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -import findPodfilePath from '../../ios/findPodfilePath'; -import projects from '../../__fixtures__/projects'; -import ios from '../../__fixtures__/ios'; - -jest.mock('path'); -jest.mock('fs'); - -const fs = require('fs'); - -describe('ios::findPodfilePath', () => { - it('returns null if there is no Podfile', () => { - fs.__setMockFilesystem(ios.valid); - expect(findPodfilePath('')).toBeNull(); - }); - - it('returns Podfile path if it exists', () => { - fs.__setMockFilesystem(projects.withPods); - expect(findPodfilePath('/ios')).toContain('Podfile'); - }); -}); diff --git a/packages/cli/src/tools/__tests__/makeCommand-test.js b/packages/cli/src/tools/__tests__/makeCommand-test.js deleted file mode 100644 index 38a076a306..0000000000 --- a/packages/cli/src/tools/__tests__/makeCommand-test.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -let spawnError = false; - -jest.setMock('child_process', { - spawn: () => ({ - on: (event, cb) => cb(spawnError), - }), -}); - -const { makeCommand } = require('../getHooks'); - -describe('makeCommand', () => { - const command = makeCommand('echo'); - - it('generates a function around shell command', () => { - expect(typeof command).toBe('function'); - }); - - it('throws an error if there is no callback provided', () => { - expect(command).toThrow(); - }); - - it('invokes a callback after command execution', () => { - const spy = jest.fn(); - command(spy); - expect(spy.mock.calls).toHaveLength(1); - }); - - it('throws an error if spawn ended up with error', () => { - spawnError = true; - const cb = jest.fn(); - expect(() => { - command(cb); - }).toThrow(); - }); -}); diff --git a/packages/cli/src/tools/__tests__/packageManager-test.js b/packages/cli/src/tools/__tests__/packageManager-test.js new file mode 100644 index 0000000000..4527091b5b --- /dev/null +++ b/packages/cli/src/tools/__tests__/packageManager-test.js @@ -0,0 +1,135 @@ +// @flow +jest.mock('execa', () => jest.fn()); +import execa from 'execa'; +import * as yarn from '../yarn'; +import {logger} from '@react-native-community/cli-tools'; +import * as PackageManager from '../packageManager'; + +const PACKAGES = ['react', 'react-native']; +const EXEC_OPTS = {stdio: 'inherit'}; +const PROJECT_ROOT = '/some/dir'; + +afterEach(() => { + jest.resetAllMocks(); +}); + +describe('yarn', () => { + beforeEach(() => { + jest + .spyOn(yarn, 'getYarnVersionIfAvailable') + .mockImplementation(() => true); + + jest.spyOn(logger, 'isVerbose').mockImplementation(() => false); + }); + + it('should install', () => { + PackageManager.install(PACKAGES, {preferYarn: true}); + + expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], EXEC_OPTS); + }); + + it('should installDev', () => { + PackageManager.installDev(PACKAGES, {preferYarn: true}); + + expect(execa).toHaveBeenCalledWith( + 'yarn', + ['add', '-D', ...PACKAGES], + EXEC_OPTS, + ); + }); + + it('should uninstall', () => { + PackageManager.uninstall(PACKAGES, {preferYarn: true}); + + expect(execa).toHaveBeenCalledWith( + 'yarn', + ['remove', ...PACKAGES], + EXEC_OPTS, + ); + }); +}); + +describe('npm', () => { + it('should install', () => { + PackageManager.install(PACKAGES, {preferYarn: false}); + + expect(execa).toHaveBeenCalledWith( + 'npm', + ['install', '--save', '--save-exact', ...PACKAGES], + EXEC_OPTS, + ); + }); + + it('should installDev', () => { + PackageManager.installDev(PACKAGES, {preferYarn: false}); + + expect(execa).toHaveBeenCalledWith( + 'npm', + ['install', '--save-dev', '--save-exact', ...PACKAGES], + EXEC_OPTS, + ); + }); + + it('should uninstall', () => { + PackageManager.uninstall(PACKAGES, {preferYarn: false}); + + expect(execa).toHaveBeenCalledWith( + 'npm', + ['uninstall', '--save', ...PACKAGES], + EXEC_OPTS, + ); + }); +}); + +it('should use npm if yarn is not available', () => { + jest.spyOn(yarn, 'getYarnVersionIfAvailable').mockImplementation(() => false); + PackageManager.install(PACKAGES, {preferYarn: true}); + + expect(execa).toHaveBeenCalledWith( + 'npm', + ['install', '--save', '--save-exact', ...PACKAGES], + EXEC_OPTS, + ); +}); + +it('should use npm if project is not using yarn', () => { + jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => false); + + PackageManager.setProjectDir(PROJECT_ROOT); + PackageManager.install(PACKAGES); + + expect(execa).toHaveBeenCalledWith( + 'npm', + ['install', '--save', '--save-exact', ...PACKAGES], + EXEC_OPTS, + ); + expect(yarn.isProjectUsingYarn).toHaveBeenCalledWith(PROJECT_ROOT); +}); + +it('should use yarn if project is using yarn', () => { + jest.spyOn(yarn, 'getYarnVersionIfAvailable').mockImplementation(() => true); + jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => true); + + PackageManager.setProjectDir(PROJECT_ROOT); + PackageManager.install(PACKAGES); + + expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], EXEC_OPTS); + expect(yarn.isProjectUsingYarn).toHaveBeenCalledWith(PROJECT_ROOT); +}); + +test.each([[false, 'pipe'], [true, 'inherit']])( + 'when verbose is set to %s should use "%s" stdio', + (isVerbose: boolean, stdioType: string) => { + jest + .spyOn(yarn, 'getYarnVersionIfAvailable') + .mockImplementation(() => true); + jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => true); + jest.spyOn(logger, 'isVerbose').mockImplementation(() => isVerbose); + + PackageManager.install(PACKAGES, {silent: true}); + + expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], { + stdio: stdioType, + }); + }, +); diff --git a/packages/cli/src/tools/assertRequiredOptions.js b/packages/cli/src/tools/assertRequiredOptions.js index 509c37178a..fb5a941ad3 100644 --- a/packages/cli/src/tools/assertRequiredOptions.js +++ b/packages/cli/src/tools/assertRequiredOptions.js @@ -7,15 +7,15 @@ * @format */ -import { Option } from 'commander'; -import { camelCase } from 'lodash'; +import {Option} from 'commander'; +import {camelCase} from 'lodash'; // Commander.js has a 2 years old open issue to support <...> syntax // for options. Until that gets merged, we run the checks manually // https://github.com/tj/commander.js/issues/230 export default function assertRequiredOptions(options, passedOptions) { options.forEach(opt => { - const option = new Option(opt.command); + const option = new Option(opt.name); if (!option.required) { return; diff --git a/packages/cli/src/tools/assign.js b/packages/cli/src/tools/assign.js new file mode 100644 index 0000000000..18f061712b --- /dev/null +++ b/packages/cli/src/tools/assign.js @@ -0,0 +1,25 @@ +/** + * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign + * + * Similar to Object.assign(), but it doesn't execute getters. This allows us to have + * lazy properties on an object and still be able to merge them together + * + * @flow + */ +export default function assign(target: Object, ...sources: Object[]) { + sources.forEach(source => { + let descriptors = Object.keys(source).reduce((acc, key) => { + acc[key] = Object.getOwnPropertyDescriptor(source, key); + return acc; + }, {}); + // by default, Object.assign copies enumerable Symbols too + Object.getOwnPropertySymbols(source).forEach(sym => { + let descriptor = Object.getOwnPropertyDescriptor(source, sym); + if (descriptor && descriptor.enumerable) { + descriptors[sym.toString()] = descriptor; + } + }); + Object.defineProperties(target, descriptors); + }); + return target; +} diff --git a/packages/cli/src/tools/config/__mocks__/index.js b/packages/cli/src/tools/config/__mocks__/index.js new file mode 100644 index 0000000000..78f27628ac --- /dev/null +++ b/packages/cli/src/tools/config/__mocks__/index.js @@ -0,0 +1,25 @@ +/** + * @flow + */ + +export default function mockedLoadConfig() { + return { + root: '/project/root', + reactNativePath: '', + commands: [], + platforms: { + ios: {projectConfig: () => null, dependencyConfig: () => null}, + android: {projectConfig: () => null, dependencyConfig: () => null}, + }, + project: { + ios: null, + android: null, + }, + dependencies: {}, + assets: [], + haste: { + providesModuleNodeModules: [], + platforms: [], + }, + }; +} diff --git a/packages/cli/src/tools/config/__mocks__/resolveNodeModuleDir.js b/packages/cli/src/tools/config/__mocks__/resolveNodeModuleDir.js new file mode 100644 index 0000000000..d85dee2ae1 --- /dev/null +++ b/packages/cli/src/tools/config/__mocks__/resolveNodeModuleDir.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +const path = require('path'); + +export default function resolveNodeModuleDir( + root: string, + packageName: string, +): string { + return path.join(root, 'node_modules', packageName); +} 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 new file mode 100644 index 0000000000..36eb206090 --- /dev/null +++ b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap @@ -0,0 +1,214 @@ +// 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 handle deprecated "rnpm" in project root: returns valid config 1`] = ` +Object { + "assets": Array [ + "<>/fonts/SampleFont.ttf", + ], + "commands": Array [], + "dependencies": Object {}, + "haste": Object { + "platforms": Array [], + "providesModuleNodeModules": Array [], + }, + "platforms": Object {}, + "project": Object {}, + "reactNativePath": "<>/node_modules/react-native", + "root": "<>", +} +`; + +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 { + "func": [Function], + "name": "foo-command", + }, + Object { + "func": [Function], + "name": "bar-command", + }, +] +`; + +exports[`should merge project configuration with default values: snapshoting \`react-native-test\` config 1`] = ` +Object { + "assets": Array [ + "foo", + ], + "hooks": Object {}, + "name": "react-native-test", + "params": Array [], + "platforms": Object { + "android": null, + "ios": Object { + "folder": "<>/node_modules/react-native-test", + "libraryFolder": "Libraries", + "pbxprojPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj", + "plist": Array [], + "podfile": null, + "podspecPath": null, + "projectName": "HelloWorld.xcodeproj", + "projectPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj", + "sharedLibraries": Array [], + "sourceDir": "./abc", + }, + }, + "root": "<>/node_modules/react-native-test", +} +`; + +exports[`should not add default React Native config when one present 1`] = ` +Array [ + Object { + "func": [Function], + "name": "test", + }, +] +`; + +exports[`should read \`rnpm\` config from a dependency and transform it to a new format: foo config 1`] = ` +Object { + "assets": Array [], + "hooks": Object {}, + "name": "react-native-foo", + "params": Array [], + "platforms": Object { + "android": null, + "ios": Object { + "folder": "<>/node_modules/react-native-foo", + "libraryFolder": "Libraries", + "pbxprojPath": "<>/node_modules/react-native-foo/customLocation/customProject.xcodeproj/project.pbxproj", + "plist": Array [], + "podfile": null, + "podspecPath": null, + "projectName": "customProject.xcodeproj", + "projectPath": "<>/node_modules/react-native-foo/customLocation/customProject.xcodeproj", + "sharedLibraries": Array [], + "sourceDir": "<>/node_modules/react-native-foo/customLocation", + }, + }, + "root": "<>/node_modules/react-native-foo", +} +`; + +exports[`should read \`rnpm\` config from a dependency and transform it to a new format: haste config 1`] = ` +Object { + "platforms": Array [ + "ios", + "android", + "dummy", + ], + "providesModuleNodeModules": Array [ + "react-native", + "react-native-dummy", + ], +} +`; + +exports[`should read a config of a dependency and use it to load other settings 1`] = ` +Object { + "assets": Array [], + "hooks": Object {}, + "name": "react-native-test", + "params": Array [], + "platforms": Object { + "android": null, + "ios": Object { + "folder": "<>/node_modules/react-native-test", + "libraryFolder": "Libraries", + "pbxprojPath": "<>/node_modules/react-native-test/customLocation/customProject.xcodeproj/project.pbxproj", + "plist": Array [], + "podfile": null, + "podspecPath": "<>/node_modules/react-native-test/ReactNativeTest.podspec", + "projectName": "customProject.xcodeproj", + "projectPath": "<>/node_modules/react-native-test/customLocation/customProject.xcodeproj", + "sharedLibraries": Array [], + "sourceDir": "<>/node_modules/react-native-test/customLocation", + }, + }, + "root": "<>/node_modules/react-native-test", +} +`; + +exports[`should return dependencies from package.json 1`] = ` +Object { + "react-native": Object { + "assets": Array [], + "hooks": Object {}, + "name": "react-native", + "params": Array [], + "platforms": Object { + "android": null, + "ios": null, + }, + "root": "<>/node_modules/react-native", + }, + "react-native-test": Object { + "assets": Array [], + "hooks": Object {}, + "name": "react-native-test", + "params": Array [], + "platforms": Object { + "android": null, + "ios": Object { + "folder": "<>/node_modules/react-native-test", + "libraryFolder": "Libraries", + "pbxprojPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj", + "plist": Array [], + "podfile": null, + "podspecPath": null, + "projectName": "HelloWorld.xcodeproj", + "projectPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj", + "sharedLibraries": Array [], + "sourceDir": "<>/node_modules/react-native-test/ios", + }, + }, + "root": "<>/node_modules/react-native-test", + }, +} +`; diff --git a/packages/cli/src/tools/__tests__/findAssets-test.js b/packages/cli/src/tools/config/__tests__/findAssets-test.js similarity index 80% rename from packages/cli/src/tools/__tests__/findAssets-test.js rename to packages/cli/src/tools/config/__tests__/findAssets-test.js index 240b8a07e8..a6387ce8fb 100644 --- a/packages/cli/src/tools/__tests__/findAssets-test.js +++ b/packages/cli/src/tools/config/__tests__/findAssets-test.js @@ -8,18 +8,26 @@ * @emails oncall+javascript_foundation */ -import dependencies from '../__fixtures__/dependencies'; +import findAssets from '../findAssets'; jest.mock('path'); jest.mock('fs'); const fs = require('fs'); -const { findAssets } = require('../getAssets'); - describe('findAssets', () => { beforeEach(() => { - fs.__setMockFilesystem({ testDir: dependencies.withAssets }); + fs.__setMockFilesystem({ + testDir: { + fonts: { + 'A.ttf': '', + 'B.ttf': '', + }, + images: { + 'C.jpg': '', + }, + }, + }); }); it('returns an array of all files in given folders', () => { diff --git a/packages/cli/src/tools/config/__tests__/findDependencies-test.js b/packages/cli/src/tools/config/__tests__/findDependencies-test.js new file mode 100644 index 0000000000..779aeeb190 --- /dev/null +++ b/packages/cli/src/tools/config/__tests__/findDependencies-test.js @@ -0,0 +1,34 @@ +/** + * @flow + */ + +import findDependencies from '../findDependencies'; + +import { + cleanup, + writeFiles, + getTempDirectory, +} from '../../../../../../jest/helpers'; + +jest.mock('../resolveNodeModuleDir'); + +beforeEach(() => { + cleanup(DIR); + jest.resetModules(); +}); + +afterEach(() => cleanup(DIR)); + +const DIR = getTempDirectory('find_dependencies_test'); + +test('returns plugins from both dependencies and dev dependencies', () => { + writeFiles(DIR, { + 'package.json': ` + { + "dependencies": {"rnpm-plugin-test": "*"}, + "devDependencies": {"rnpm-plugin-test-2": "*"} + } + `, + }); + expect(findDependencies(DIR)).toHaveLength(2); +}); diff --git a/packages/cli/src/tools/config/__tests__/index-test.js b/packages/cli/src/tools/config/__tests__/index-test.js new file mode 100644 index 0000000000..c65f138e2e --- /dev/null +++ b/packages/cli/src/tools/config/__tests__/index-test.js @@ -0,0 +1,352 @@ +/** + * @flow + */ + +import loadConfig from '..'; + +import { + cleanup, + writeFiles, + getTempDirectory, +} from '../../../../../../jest/helpers'; + +import {logger} from '@react-native-community/cli-tools'; + +jest.mock('../resolveNodeModuleDir'); + +const DIR = getTempDirectory('resolve_config_path_test'); + +// Removes string from all key/values within an object +const removeString = (config, str) => + JSON.parse( + JSON.stringify(config).replace(new RegExp(str, 'g'), '<>'), + ); + +beforeEach(() => { + cleanup(DIR); + jest.resetModules(); + jest.clearAllMocks(); +}); + +afterEach(() => cleanup(DIR)); + +test('should have a valid structure by default', () => { + writeFiles(DIR, { + 'react-native.config.js': `module.exports = { + reactNativePath: "." + }`, + }); + const config = loadConfig(DIR); + expect(removeString(config, DIR)).toMatchSnapshot(); +}); + +test('should handle deprecated "rnpm" in project root', () => { + writeFiles(DIR, { + 'package.json': `{ + "rnpm": { + "assets": ["./fonts"] + } + }`, + 'fonts/SampleFont.ttf': '', + }); + const config = loadConfig(DIR); + + expect(removeString(config, DIR)).toMatchSnapshot('returns valid config'); + expect(logger.warn).toBeCalledWith( + expect.stringMatching(/Your project is using deprecated/), + ); +}); + +test('should return dependencies from package.json', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native-test/package.json': '{}', + 'node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj': + '', + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1", + "react-native-test": "0.0.1" + } + }`, + }); + const {dependencies} = loadConfig(DIR); + expect(removeString(dependencies, DIR)).toMatchSnapshot(); +}); + +test('should read a config of a dependency and use it to load other settings', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native-test/package.json': '{}', + 'node_modules/react-native-test/ReactNativeTest.podspec': '', + 'node_modules/react-native-test/react-native.config.js': `module.exports = { + dependency: { + platforms: { + ios: { + project: "./customLocation/customProject.xcodeproj" + } + } + } + }`, + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1", + "react-native-test": "0.0.1" + } + }`, + }); + const {dependencies} = loadConfig(DIR); + expect( + removeString(dependencies['react-native-test'], DIR), + ).toMatchSnapshot(); +}); + +test('should merge project configuration with default values', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native-test/package.json': '{}', + 'node_modules/react-native-test/react-native.config.js': `module.exports = { + dependency: { + assets: ["foo", "baz"] + } + }`, + 'node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj': + '', + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1", + "react-native-test": "0.0.1" + } + }`, + 'react-native.config.js': `module.exports = { + reactNativePath: ".", + dependencies: { + "react-native-test": { + platforms: { + ios: { + sourceDir: "./abc" + } + }, + assets: ["foo"] + } + } + }`, + }); + const {dependencies} = loadConfig(DIR); + expect(removeString(dependencies['react-native-test'], DIR)).toMatchSnapshot( + 'snapshoting `react-native-test` config', + ); +}); + +test('should read `rnpm` config from a dependency and transform it to a new format', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native-foo/package.json': `{ + "name": "react-native-foo", + "rnpm": { + "ios": { + "project": "./customLocation/customProject.xcodeproj" + }, + "haste": { + "platforms": ["dummy"], + "providesModuleNodeModules": ["react-native-dummy"] + } + } + }`, + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1", + "react-native-foo": "0.0.1" + } + }`, + }); + const {dependencies, haste} = loadConfig(DIR); + expect(removeString(dependencies['react-native-foo'], DIR)).toMatchSnapshot( + 'foo config', + ); + expect(haste).toMatchSnapshot('haste config'); +}); + +test('should load commands from "react-native-foo" and "react-native-bar" packages', () => { + writeFiles(DIR, { + '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': '{}', + 'node_modules/react-native-bar/react-native.config.js': `module.exports = { + commands: [ + { + name: 'bar-command', + func: () => console.log('bar') + } + ] + }`, + 'package.json': `{ + "dependencies": { + "react-native-foo": "0.0.1", + "react-native-bar": "0.0.1" + } + }`, + }); + const {commands} = loadConfig(DIR); + expect(commands).toMatchSnapshot(); +}); + +test('should load an out-of-tree "windows" platform that ships with a dependency', () => { + writeFiles(DIR, { + '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": { + "haste": { + "platforms": [ + "windows" + ], + "providesModuleNodeModules": [ + "react-native-windows" + ] + }, + "plugin": "./plugin.js", + "platform": "./platform.js" + } + }`, + 'package.json': `{ + "dependencies": { + "react-native-windows": "0.0.1" + } + }`, + }); + const {haste, platforms} = loadConfig(DIR); + expect(removeString({haste, platforms}, DIR)).toMatchSnapshot(); +}); + +test('should automatically put "react-native" into haste config', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1" + } + }`, + }); + const {haste} = loadConfig(DIR); + expect(haste).toMatchSnapshot(); +}); + +test('should not add default React Native config when one present', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native/react-native.config.js': `module.exports = { + commands: [{ + name: 'test', + func: () => {}, + }] + }`, + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1" + } + }`, + }); + const {commands} = loadConfig(DIR); + expect(commands).toMatchSnapshot(); +}); + +// @todo: figure out why this test is so flaky +test.skip('should skip packages that have invalid configuration', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'node_modules/react-native/react-native.config.js': `module.exports = { + dependency: { + invalidProperty: 5 + } + }`, + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1" + } + }`, + }); + const spy = jest.spyOn(logger, 'warn'); + const {dependencies} = loadConfig(DIR); + expect(dependencies).toMatchSnapshot('dependencies config'); + expect(spy.mock.calls[0][0]).toMatchSnapshot('logged warning'); +}); + +test('does not use restricted "react-native" key to resolve config from package.json', () => { + writeFiles(DIR, { + 'node_modules/react-native-netinfo/package.json': `{ + "react-native": "src/index.js" + }`, + 'package.json': `{ + "dependencies": { + "react-native-netinfo": "0.0.1" + } + }`, + }); + const spy = jest.spyOn(logger, 'warn'); + const {dependencies} = loadConfig(DIR); + expect(dependencies).toHaveProperty('react-native-netinfo'); + expect(spy).not.toHaveBeenCalled(); +}); + +test('supports dependencies from user configuration with custom root and properties', () => { + writeFiles(DIR, { + 'node_modules/react-native/package.json': '{}', + 'native-libs/local-lib/ios/LocalRNLibrary.xcodeproj/project.pbxproj': '', + 'react-native.config.js': `module.exports = { + dependencies: { + 'local-lib': { + root: "${DIR}/native-libs/local-lib", + platforms: { + ios: { + podspecPath: "custom-path" + } + } + }, + } + }`, + 'package.json': `{ + "dependencies": { + "react-native": "0.0.1" + } + }`, + }); + + const {dependencies} = loadConfig(DIR); + expect(removeString(dependencies['local-lib'], DIR)).toMatchInlineSnapshot(` + Object { + "assets": Array [], + "hooks": Object {}, + "name": "local-lib", + "params": Array [], + "platforms": Object { + "android": null, + "ios": Object { + "folder": "<>/native-libs/local-lib", + "libraryFolder": "Libraries", + "pbxprojPath": "<>/native-libs/local-lib/ios/LocalRNLibrary.xcodeproj/project.pbxproj", + "plist": Array [], + "podfile": null, + "podspecPath": "custom-path", + "projectName": "LocalRNLibrary.xcodeproj", + "projectPath": "<>/native-libs/local-lib/ios/LocalRNLibrary.xcodeproj", + "sharedLibraries": Array [], + "sourceDir": "<>/native-libs/local-lib/ios", + }, + }, + "root": "<>/native-libs/local-lib", + } + `); +}); diff --git a/packages/cli/src/tools/config/errors.js b/packages/cli/src/tools/config/errors.js new file mode 100644 index 0000000000..3b1fbbc55a --- /dev/null +++ b/packages/cli/src/tools/config/errors.js @@ -0,0 +1,55 @@ +/** + * @flow + */ +import {CLIError} from '@react-native-community/cli-tools'; + +type JoiErrorDetails = { + message: string, + path: string[], + type: K, + context: T, +}; + +type JoiErrorT = { + details: Array< + JoiErrorDetails< + 'object.allowUnknown' | 'object.base' | 'string.base', + { + key: string, + label: string, + value: Object, + }, + >, + >, +}; + +export class JoiError extends CLIError { + constructor(joiError: JoiErrorT) { + super( + joiError.details + .map(error => { + const name = error.path.join('.'); + switch (error.type) { + case 'object.allowUnknown': { + const value = JSON.stringify(error.context.value); + return ` + Unknown option ${name} with value "${value}" was found. + This is either a typing error or a user mistake. Fixing it will remove this message. + `; + } + case 'object.base': + case 'string.base': { + const expectedType = error.type.replace('.base', ''); + const actualType = typeof error.context.value; + return ` + Option ${name} must be a ${expectedType}, instead got ${actualType} + `; + } + default: + return error.message; + } + }) + .join(), + ); + } +} diff --git a/packages/cli/src/tools/getAssets.js b/packages/cli/src/tools/config/findAssets.js similarity index 54% rename from packages/cli/src/tools/getAssets.js rename to packages/cli/src/tools/config/findAssets.js index 26c751dcd4..9f35e5c0c3 100644 --- a/packages/cli/src/tools/getAssets.js +++ b/packages/cli/src/tools/config/findAssets.js @@ -4,10 +4,9 @@ import glob from 'glob'; import path from 'path'; -import getPackageConfiguration from './getPackageConfiguration'; const findAssetsInFolder = folder => - glob.sync(path.join(folder, '**'), { nodir: true }); + glob.sync(path.join(folder, '**'), {nodir: true}); /** * Given an array of assets folders, e.g. ['Fonts', 'Images'], @@ -15,20 +14,12 @@ const findAssetsInFolder = folder => * * It returns an array of absolute paths to files found. */ -export function findAssets(folder: string, assets?: string[]) { +export default function findAssets(folder: string, assets: string[]) { return (assets || []) .map(asset => path.join(folder, asset)) .reduce( (acc, assetPath) => (acc.concat(findAssetsInFolder(assetPath)): Array), - [] + [], ); } - -/** - * Returns a project configuration in a given folder - */ -export default function getAssets(root: string) { - const config = getPackageConfiguration(root); - return findAssets(root, config.assets); -} diff --git a/packages/cli/src/tools/config/findDependencies.js b/packages/cli/src/tools/config/findDependencies.js new file mode 100644 index 0000000000..c5f3929648 --- /dev/null +++ b/packages/cli/src/tools/config/findDependencies.js @@ -0,0 +1,28 @@ +/** + * @flow + */ + +import path from 'path'; +import fs from 'fs'; + +/** + * Returns an array of dependencies from project's package.json + */ +export default function findDependencies(root: string): Array { + let pjson; + + try { + pjson = JSON.parse( + fs.readFileSync(path.join(root, 'package.json'), 'UTF-8'), + ); + } catch (e) { + return []; + } + + const deps = [ + ...Object.keys(pjson.dependencies || {}), + ...Object.keys(pjson.devDependencies || {}), + ]; + + return deps; +} diff --git a/packages/cli/src/tools/config/index.js b/packages/cli/src/tools/config/index.js new file mode 100644 index 0000000000..08afb4e72a --- /dev/null +++ b/packages/cli/src/tools/config/index.js @@ -0,0 +1,215 @@ +/** + * @flow + */ +import path from 'path'; +import chalk from 'chalk'; +import {logger, inlineString} from '@react-native-community/cli-tools'; +import * as ios from '@react-native-community/cli-platform-ios'; +import * as android from '@react-native-community/cli-platform-android'; +import findDependencies from './findDependencies'; +import resolveReactNativePath from './resolveReactNativePath'; +import findAssets from './findAssets'; +import { + readConfigFromDisk, + readDependencyConfigFromDisk, +} from './readConfigFromDisk'; +import type { + ConfigT, + UserDependencyConfigT, + UserConfigT, + DependencyConfigT, +} from 'types'; +import assign from '../assign'; +import merge from '../merge'; +import resolveNodeModuleDir from './resolveNodeModuleDir'; + +function getDependencyConfig( + root: string, + dependencyName: string, + finalConfig: ConfigT, + config: UserDependencyConfigT, + userConfig: UserConfigT, + isPlatform: boolean, +): DependencyConfigT { + return merge( + { + root, + name: dependencyName, + platforms: Object.keys(finalConfig.platforms).reduce( + (dependency, platform) => { + const platformConfig = finalConfig.platforms[platform]; + dependency[platform] = + // Linking platforms is not supported + isPlatform || !platformConfig + ? null + : platformConfig.dependencyConfig( + root, + /* $FlowFixMe - can't figure out which platform's dependency + config to choose */ + config.dependency.platforms[platform], + ); + return dependency; + }, + {}, + ), + assets: findAssets(root, config.dependency.assets), + hooks: config.dependency.hooks, + params: config.dependency.params, + }, + userConfig.dependencies[dependencyName] || {}, + ); +} + +/** + * Loads CLI configuration + */ +function loadConfig(projectRoot: string = process.cwd()): ConfigT { + let lazyProject; + const userConfig = readConfigFromDisk(projectRoot); + + const initialConfig: ConfigT = { + root: projectRoot, + get reactNativePath() { + return userConfig.reactNativePath + ? path.resolve(projectRoot, userConfig.reactNativePath) + : resolveReactNativePath(projectRoot); + }, + dependencies: userConfig.dependencies, + commands: userConfig.commands, + get assets() { + return findAssets(projectRoot, userConfig.assets); + }, + platforms: userConfig.platforms, + haste: { + providesModuleNodeModules: [], + platforms: Object.keys(userConfig.platforms), + }, + get project() { + if (lazyProject) { + return lazyProject; + } + + lazyProject = {}; + for (const platform in finalConfig.platforms) { + lazyProject[platform] = finalConfig.platforms[platform].projectConfig( + projectRoot, + userConfig.project[platform] || {}, + ); + } + + return lazyProject; + }, + }; + + let depsWithWarnings = []; + + const finalConfig = Array.from( + new Set([ + ...Object.keys(userConfig.dependencies), + ...findDependencies(projectRoot), + ]), + ).reduce((acc: ConfigT, dependencyName) => { + const localDependencyRoot = + userConfig.dependencies[dependencyName] && + userConfig.dependencies[dependencyName].root; + let root; + let config; + try { + root = + localDependencyRoot || + resolveNodeModuleDir(projectRoot, dependencyName); + const output = readDependencyConfigFromDisk(root); + config = output.config; + + if (output.legacy && !localDependencyRoot) { + const pkg = require(path.join(root, 'package.json')); + const link = + pkg.homepage || `https://npmjs.com/package/${dependencyName}`; + depsWithWarnings.push([dependencyName, link]); + } + } catch (error) { + logger.warn( + inlineString(` + Package ${chalk.bold( + dependencyName, + )} has been ignored because it contains invalid configuration. + + Reason: ${chalk.dim(error.message)}`), + ); + return acc; + } + + /** + * @todo: remove this code once `react-native` is published with + * `platforms` and `commands` inside `react-native.config.js`. + */ + if (dependencyName === 'react-native') { + if (Object.keys(config.platforms).length === 0) { + config.platforms = {ios, android}; + } + if (config.commands.length === 0) { + config.commands = [...ios.commands, ...android.commands]; + } + } + + const isPlatform = Object.keys(config.platforms).length > 0; + + /** + * Legacy `rnpm` config required `haste` to be defined. With new config, + * we do it automatically. + * + * @todo: Remove this once `rnpm` config is deprecated and all major RN libs are converted. + */ + const haste = config.haste || { + providesModuleNodeModules: isPlatform ? [dependencyName] : [], + platforms: Object.keys(config.platforms), + }; + + return (assign({}, acc, { + dependencies: assign({}, acc.dependencies, { + // $FlowExpectedError: Dynamic getters are not supported + get [dependencyName]() { + return getDependencyConfig( + root, + dependencyName, + finalConfig, + config, + userConfig, + isPlatform, + ); + }, + }), + commands: [...acc.commands, ...config.commands], + platforms: { + ...acc.platforms, + ...config.platforms, + }, + haste: { + providesModuleNodeModules: [ + ...acc.haste.providesModuleNodeModules, + ...haste.providesModuleNodeModules, + ], + platforms: [...acc.haste.platforms, ...haste.platforms], + }, + }): ConfigT); + }, initialConfig); + + if (depsWithWarnings.length) { + logger.warn( + `The following packages use deprecated "rnpm" config that will stop working from next release:\n${depsWithWarnings + .map( + ([name, link]) => + ` - ${chalk.bold(name)}: ${chalk.dim(chalk.underline(link))}`, + ) + .join( + '\n', + )}\nPlease notify their maintainers about it. You can find more details at ${chalk.dim.underline( + 'https://github.com/react-native-community/cli/blob/master/docs/configuration.md#migration-guide', + )}.`, + ); + } + + return finalConfig; +} + +export default loadConfig; diff --git a/packages/cli/src/tools/config/readConfigFromDisk.js b/packages/cli/src/tools/config/readConfigFromDisk.js new file mode 100644 index 0000000000..197ed237b9 --- /dev/null +++ b/packages/cli/src/tools/config/readConfigFromDisk.js @@ -0,0 +1,184 @@ +/** + * @flow + * + * Loads and validates a project configuration + */ +import Joi from '@hapi/joi'; +import cosmiconfig from 'cosmiconfig'; +import path from 'path'; +import chalk from 'chalk'; +import { + type UserDependencyConfigT, + type UserConfigT, + type CommandT, +} from 'types'; +import {JoiError} from './errors'; +import * as schema from './schema'; +import {logger} from '@react-native-community/cli-tools'; +import resolveReactNativePath from './resolveReactNativePath'; + +const MIGRATION_GUIDE = `Migration guide: ${chalk.dim.underline( + 'https://github.com/react-native-community/cli/blob/master/docs/configuration.md', +)}`; + +/** + * Places to look for the new configuration + */ +const searchPlaces = ['react-native.config.js']; + +function readLegacyConfigFromDisk(rootFolder: string): UserConfigT | void { + let config; + + try { + config = require(path.join(rootFolder, 'package.json')).rnpm; + } catch (error) { + // when `init` is running, there's no package.json yet + return undefined; + } + + if (!config) { + return undefined; + } + + const transformedConfig = { + project: { + ios: config.ios, + android: config.android, + }, + assets: config.assets, + commands: [], + dependencies: {}, + platforms: {}, + get reactNativePath() { + return config.reactNativePath + ? path.resolve(rootFolder, config.reactNativePath) + : resolveReactNativePath(rootFolder); + }, + }; + + logger.warn( + `Your project is using deprecated "${chalk.bold( + 'rnpm', + )}" config that will stop working from next release. Please use a "${chalk.bold( + 'react-native.config.js', + )}" file to configure the React Native CLI. ${MIGRATION_GUIDE}`, + ); + + return transformedConfig; +} + +/** + * Reads a project configuration as defined by the user in the current + * workspace. + */ +export function readConfigFromDisk(rootFolder: string): UserConfigT { + const explorer = cosmiconfig('react-native', {searchPlaces}); + + const {config} = explorer.searchSync(rootFolder) || { + config: readLegacyConfigFromDisk(rootFolder), + }; + + const result = Joi.validate(config, schema.projectConfig); + + if (result.error) { + throw new JoiError(result.error); + } + + return result.value; +} + +/** + * Reads a dependency configuration as defined by the developer + * inside `node_modules`. + */ +export function readDependencyConfigFromDisk( + rootFolder: string, +): {config: UserDependencyConfigT, legacy?: boolean} { + const explorer = cosmiconfig('react-native', { + stopDir: rootFolder, + searchPlaces, + }); + + const {config, legacy} = explorer.searchSync(rootFolder) || { + config: readLegacyDependencyConfigFromDisk(rootFolder), + legacy: true, + }; + + const result = Joi.validate(config, schema.dependencyConfig); + + if (result.error) { + throw new JoiError(result.error); + } + + return {config: result.value, legacy: legacy && config !== undefined}; +} + +/** + * 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 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); + }, []); +}; + +/** + * Reads a legacy configuration from a `package.json` "rnpm" key. + */ +function readLegacyDependencyConfigFromDisk( + rootFolder: string, +): ?UserDependencyConfigT { + let config = {}; + + try { + config = require(path.join(rootFolder, 'package.json')).rnpm; + } catch (error) { + // package.json is usually missing in local libraries that are not in + // project "dependencies", so we just return a bare config + return { + dependency: { + platforms: {}, + assets: [], + hooks: {}, + params: [], + }, + commands: [], + platforms: {}, + }; + } + + if (!config) { + return undefined; + } + + const transformedConfig = { + dependency: { + platforms: { + ios: config.ios, + android: config.android, + }, + assets: config.assets, + hooks: config.commands, + params: config.params, + }, + haste: config.haste, + commands: loadProjectCommands(rootFolder, config.plugin), + platforms: config.platform + ? require(path.join(rootFolder, config.platform)) + : {}, + }; + + return transformedConfig; +} diff --git a/packages/cli/src/tools/config/resolveNodeModuleDir.js b/packages/cli/src/tools/config/resolveNodeModuleDir.js new file mode 100644 index 0000000000..09a0e49173 --- /dev/null +++ b/packages/cli/src/tools/config/resolveNodeModuleDir.js @@ -0,0 +1,19 @@ +/** + * @flow + */ +import path from 'path'; + +/** + * Finds a path inside `node_modules` + */ +export default function resolveNodeModuleDir( + root: string, + packageName: string, +): string { + return path.dirname( + // $FlowIssue: Wrong `require.resolve` type definition + require.resolve(path.join(packageName, 'package.json'), { + paths: [root], + }), + ); +} diff --git a/packages/cli/src/tools/config/resolveReactNativePath.js b/packages/cli/src/tools/config/resolveReactNativePath.js new file mode 100644 index 0000000000..dbce4e5c84 --- /dev/null +++ b/packages/cli/src/tools/config/resolveReactNativePath.js @@ -0,0 +1,29 @@ +/** + * @flow + */ +import {CLIError} from '@react-native-community/cli-tools'; + +import resolveNodeModuleDir from './resolveNodeModuleDir'; + +/** + * Finds path to React Native inside `node_modules` or throws + * an error otherwise. + */ +export default function resolveReactNativePath(root: string) { + try { + return resolveNodeModuleDir(root, 'react-native'); + } catch (_ignored) { + throw new CLIError(` + Unable to find React Native files. Make sure "react-native" module is installed + in your project dependencies. + + If you are using React Native from a non-standard location, consider setting: + { + "react-native": { + "reactNativePath": "./path/to/react-native" + } + } + in your \`package.json\`. + `); + } +} diff --git a/packages/cli/src/tools/config/schema.js b/packages/cli/src/tools/config/schema.js new file mode 100644 index 0000000000..8bb0174c78 --- /dev/null +++ b/packages/cli/src/tools/config/schema.js @@ -0,0 +1,188 @@ +/** + * @flow + */ +import t from '@hapi/joi'; + +const map = (key, value) => + t + .object() + .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({ + name: t.string().required(), + description: t.string(), + parse: t.func(), + default: t + .alternatives() + .try([t.bool(), t.number(), t.string().allow(''), t.func()]), + }) + .rename('command', 'name', {ignoreUndefined: true}), + ), + examples: t.array().items( + t.object({ + desc: t.string().required(), + cmd: t.string().required(), + }), + ), +}); + +/** + * Schema for UserDependencyConfigT + */ +export const dependencyConfig = t + .object({ + dependency: t + .object({ + platforms: map(t.string(), t.any()) + .keys({ + ios: t + .object({ + project: t.string(), + podspecPath: t.string(), + sharedLibraries: t.array().items(t.string()), + libraryFolder: t.string(), + }) + .default({}), + android: t + .object({ + sourceDir: t.string(), + manifestPath: t.string(), + packageImportPath: t.string(), + packageInstance: t.string(), + }) + .default({}), + }) + .default(), + assets: t + .array() + .items(t.string()) + .default([]), + hooks: map(t.string(), t.string()).default({}), + params: t + .array() + .items( + t.object({ + name: t.string(), + type: t.string(), + message: t.string(), + }), + ) + .default([]), + }) + .default(), + platforms: map( + t.string(), + t.object({ + dependencyConfig: t.func(), + projectConfig: t.func(), + linkConfig: t.func(), + }), + ).default({}), + commands: t + .array() + .items(command) + .default([]), + }) + .unknown(true) + .default(); + +/** + * Schema for ProjectConfigT + */ +export const projectConfig = t + .object({ + dependencies: map( + t.string(), + t + .object({ + root: t.string(), + platforms: map(t.string(), t.any()).keys({ + ios: t + .object({ + sourceDir: t.string(), + folder: t.string(), + pbxprojPath: t.string(), + podfile: t.string(), + podspecPath: t.string(), + projectPath: t.string(), + projectName: t.string(), + libraryFolder: t.string(), + sharedLibraries: t.array().items(t.string()), + }) + .allow(null), + android: t + .object({ + sourceDir: t.string(), + folder: t.string(), + packageImportPath: t.string(), + packageInstance: t.string(), + }) + .allow(null), + }), + assets: t.array().items(t.string()), + hooks: map(t.string(), t.string()), + params: t.array().items( + t.object({ + name: t.string(), + type: t.string(), + message: t.string(), + }), + ), + }) + .allow(null), + ).default({}), + reactNativePath: t.string(), + project: map(t.string(), t.any()) + .keys({ + ios: t + .object({ + project: t.string(), + sharedLibraries: t.array().items(t.string()), + libraryFolder: t.string(), + }) + .default({}), + android: t + .object({ + sourceDir: t.string(), + manifestPath: t.string(), + packageName: t.string(), + packageFolder: t.string(), + mainFilePath: t.string(), + stringsPath: t.string(), + settingsGradlePath: t.string(), + assetsPath: t.string(), + buildGradlePath: t.string(), + }) + .default({}), + }) + .default(), + assets: t + .array() + .items(t.string()) + .default([]), + commands: t + .array() + .items(command) + .default([]), + platforms: map( + t.string(), + t.object({ + dependencyConfig: t.func(), + projectConfig: t.func(), + linkConfig: t.func(), + }), + ).default({}), + }) + .unknown(true) + .default(); diff --git a/packages/cli/src/tools/copyAndReplace.js b/packages/cli/src/tools/copyAndReplace.js index 1d6d964388..1feb0e6f27 100644 --- a/packages/cli/src/tools/copyAndReplace.js +++ b/packages/cli/src/tools/copyAndReplace.js @@ -11,7 +11,7 @@ import fs from 'fs'; import path from 'path'; // Binary files, don't process these (avoid decoding as utf8) -const binaryExtensions = ['.png', '.jar']; +const binaryExtensions = ['.png', '.jar', '.keystore']; /** * Copy a file to given destination, replacing parts of its contents. @@ -29,7 +29,7 @@ function copyAndReplace( srcPath, destPath, replacements, - contentChangedCallback + contentChangedCallback, ) { if (fs.lstatSync(srcPath).isDirectory()) { if (!fs.existsSync(destPath)) { diff --git a/packages/cli/src/tools/copyFiles.js b/packages/cli/src/tools/copyFiles.js new file mode 100644 index 0000000000..e2e5fad664 --- /dev/null +++ b/packages/cli/src/tools/copyFiles.js @@ -0,0 +1,90 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import fs from 'fs'; +import path from 'path'; +import walk from './walk'; + +type Options = { + exclude?: Array, +}; + +/** + * Copy files (binary included) recursively. + */ +async function copyFiles( + srcPath: string, + destPath: string, + options?: Options = {}, +) { + return Promise.all( + walk(srcPath).map(async absoluteSrcFilePath => { + const exclude = options.exclude; + if (exclude && exclude.some(p => p.test(absoluteSrcFilePath))) { + return; + } + const relativeFilePath = path.relative(srcPath, absoluteSrcFilePath); + await copyFile( + absoluteSrcFilePath, + path.resolve(destPath, relativeFilePath), + ); + }), + ); +} + +/** + * Copy a file to given destination. + */ +function copyFile(srcPath: string, destPath: string) { + if (fs.lstatSync(srcPath).isDirectory()) { + if (!fs.existsSync(destPath)) { + fs.mkdirSync(destPath); + } + // Not recursive + return; + } + + return new Promise((resolve, reject) => { + copyBinaryFile(srcPath, destPath, err => { + if (err) { + reject(err); + } + resolve(destPath); + }); + }); +} + +/** + * Same as 'cp' on Unix. Don't do any replacements. + */ +function copyBinaryFile(srcPath, destPath, cb) { + let cbCalled = false; + const {mode} = fs.statSync(srcPath); + const readStream = fs.createReadStream(srcPath); + const writeStream = fs.createWriteStream(destPath); + readStream.on('error', err => { + done(err); + }); + writeStream.on('error', err => { + done(err); + }); + readStream.on('close', () => { + done(); + fs.chmodSync(destPath, mode); + }); + readStream.pipe(writeStream); + function done(err) { + if (!cbCalled) { + cb(err); + cbCalled = true; + } + } +} + +export default copyFiles; diff --git a/packages/cli/src/tools/errors.js b/packages/cli/src/tools/errors.js deleted file mode 100644 index 278d35cc22..0000000000 --- a/packages/cli/src/tools/errors.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @flow - */ -import chalk from 'chalk'; - -export class ProcessError extends Error { - constructor(msg: string, processError: string) { - super(`${chalk.red(msg)}\n\n${chalk.gray(processError)}`); - Error.captureStackTrace(this, ProcessError); - } -} diff --git a/packages/cli/src/commands/upgrade/helpers.js b/packages/cli/src/tools/fetch.js similarity index 96% rename from packages/cli/src/commands/upgrade/helpers.js rename to packages/cli/src/tools/fetch.js index e403535886..5c9ad2fc26 100644 --- a/packages/cli/src/commands/upgrade/helpers.js +++ b/packages/cli/src/tools/fetch.js @@ -6,7 +6,7 @@ export const fetch = (url: string) => const request = https.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject( - new Error(`Failed to load page, status code: ${response.statusCode}`) + new Error(`Failed to load page, status code: ${response.statusCode}`), ); } const body = []; diff --git a/packages/cli/src/tools/findPlugins.js b/packages/cli/src/tools/findPlugins.js deleted file mode 100644 index caa78179a5..0000000000 --- a/packages/cli/src/tools/findPlugins.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -import path from 'path'; -import { union, uniq, flatten } from 'lodash'; - -const RNPM_PLUGIN_PATTERNS = [/^rnpm-plugin-/, /^@(.*)\/rnpm-plugin-/]; - -const REACT_NATIVE_PLUGIN_PATTERNS = [ - /^react-native-/, - /^@(.*)\/react-native-/, - /^@react-native(.*)\/(?!rnpm-plugin-)/, -]; - -/** - * Filter dependencies by name pattern - * @param {String} dependency Name of the dependency - * @return {Boolean} If dependency is a rnpm plugin - */ -const isRNPMPlugin = dependency => - RNPM_PLUGIN_PATTERNS.some(pattern => pattern.test(dependency)); -const isReactNativePlugin = dependency => - REACT_NATIVE_PLUGIN_PATTERNS.some(pattern => pattern.test(dependency)); - -const readPackage = folder => { - try { - return require(path.join(folder, 'package.json')); - } catch (e) { - return null; - } -}; - -const findPluginsInReactNativePackage = pjson => { - if (!pjson.rnpm || !pjson.rnpm.plugin) { - return []; - } - - return path.join(pjson.name, pjson.rnpm.plugin); -}; - -const findPlatformsInPackage = pjson => { - if (!pjson.rnpm || !pjson.rnpm.platform) { - return []; - } - - return path.join(pjson.name, pjson.rnpm.platform); -}; - -const getEmptyPluginConfig = () => ({ - commands: [], - platforms: [], - haste: { - platforms: [], - providesModuleNodeModules: [], - }, -}); - -const findHasteConfigInPackageAndConcat = (pjson, haste) => { - if (!pjson.rnpm || !pjson.rnpm.haste) { - return; - } - const pkgHaste = pjson.rnpm.haste; - - if (pkgHaste.platforms) { - // eslint-disable-next-line no-param-reassign - haste.platforms = haste.platforms.concat(pkgHaste.platforms); - } - - if (pkgHaste.providesModuleNodeModules) { - // eslint-disable-next-line no-param-reassign - haste.providesModuleNodeModules = haste.providesModuleNodeModules.concat( - pkgHaste.providesModuleNodeModules - ); - } -}; - -const findPluginsInFolder = folder => { - const pjson = readPackage(folder); - - if (!pjson) { - return getEmptyPluginConfig(); - } - - const deps = union( - Object.keys(pjson.dependencies || {}), - Object.keys(pjson.devDependencies || {}) - ); - - return deps.reduce((acc, pkg) => { - let { commands, platforms } = acc; - if (isRNPMPlugin(pkg)) { - commands = commands.concat(pkg); - } - if (isReactNativePlugin(pkg)) { - const pkgJson = readPackage(path.join(folder, 'node_modules', pkg)); - if (pkgJson) { - commands = commands.concat(findPluginsInReactNativePackage(pkgJson)); - platforms = platforms.concat(findPlatformsInPackage(pkgJson)); - findHasteConfigInPackageAndConcat(pkgJson, acc.haste); - } - } - return { commands, platforms, haste: acc.haste }; - }, getEmptyPluginConfig()); -}; - -/** - * Find plugins in package.json of the given folder - * @param {String} folder Path to the folder to get the package.json from - */ -export default function findPlugins(folder: string) { - const plugin = findPluginsInFolder(folder); - return { - commands: uniq(flatten(plugin.commands)), - platforms: uniq(flatten(plugin.platforms)), - haste: { - platforms: uniq(flatten(plugin.haste.platforms)), - providesModuleNodeModules: uniq( - flatten(plugin.haste.providesModuleNodeModules) - ), - }, - }; -} diff --git a/packages/cli/src/tools/findReactNativeScripts.js b/packages/cli/src/tools/findReactNativeScripts.js deleted file mode 100644 index 9918081b71..0000000000 --- a/packages/cli/src/tools/findReactNativeScripts.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict - */ - -import path from 'path'; -import fs from 'fs'; - -function findReactNativeScripts(): ?string { - const executablePath = path.resolve( - 'node_modules', - '.bin', - 'react-native-scripts' - ); - if (fs.existsSync(executablePath)) { - return executablePath; - } - return null; -} - -export default findReactNativeScripts; diff --git a/packages/cli/src/tools/findSymlinkedModules.js b/packages/cli/src/tools/findSymlinkedModules.js index 068ded2db2..90a0f5933a 100644 --- a/packages/cli/src/tools/findSymlinkedModules.js +++ b/packages/cli/src/tools/findSymlinkedModules.js @@ -32,7 +32,7 @@ import fs from 'fs'; */ export default function findSymlinkedModules( projectRoot: string, - ignoredRoots?: Array = [] + ignoredRoots?: Array = [], ) { const nodeModuleRoot = path.join(projectRoot, 'node_modules'); const resolvedSymlinks = findModuleSymlinks(nodeModuleRoot, [ @@ -44,7 +44,7 @@ export default function findSymlinkedModules( function findModuleSymlinks( modulesPath: string, - ignoredPaths: Array = [] + ignoredPaths: Array = [], ): Array { if (!fs.existsSync(modulesPath)) { return []; @@ -58,7 +58,7 @@ function findModuleSymlinks( if (folderName.startsWith('@')) { const scopedModuleFolders = fs.readdirSync(folderPath); maybeSymlinkPaths.push( - ...scopedModuleFolders.map(name => path.join(folderPath, name)) + ...scopedModuleFolders.map(name => path.join(folderPath, name)), ); } else { maybeSymlinkPaths.push(folderPath); @@ -76,9 +76,9 @@ function findModuleSymlinks( findModuleSymlinks(path.join(symlinkPath, 'node_modules'), [ ...ignoredPaths, ...symlinks, - ]) + ]), ), - [] + [], ); return [...new Set([...symlinks, ...nestedSymlinks])]; @@ -89,7 +89,7 @@ function resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths) { if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) { const resolved = path.resolve( path.dirname(maybeSymlinkPath), - fs.readlinkSync(maybeSymlinkPath) + fs.readlinkSync(maybeSymlinkPath), ); if (ignoredPaths.indexOf(resolved) === -1 && fs.existsSync(resolved)) { links.push(resolved); diff --git a/packages/cli/src/tools/generator/copyProjectTemplateAndReplace.js b/packages/cli/src/tools/generator/copyProjectTemplateAndReplace.js index 5a0362a6e9..1f65781270 100644 --- a/packages/cli/src/tools/generator/copyProjectTemplateAndReplace.js +++ b/packages/cli/src/tools/generator/copyProjectTemplateAndReplace.js @@ -12,7 +12,7 @@ import path from 'path'; import copyAndReplace from '../copyAndReplace'; import promptInitializer from './promptSync'; import walk from '../walk'; -import logger from '../logger'; +import {logger} from '@react-native-community/cli-tools'; const prompt = promptInitializer(); @@ -34,7 +34,7 @@ function copyProjectTemplateAndReplace( srcPath, destPath, newProjectName, - options = {} + options = {}, ) { if (!srcPath) { throw new Error('Need a path to copy from'); @@ -67,7 +67,7 @@ function copyProjectTemplateAndReplace( } const relativeFilePath = translateFilePath( - path.relative(srcPath, absoluteSrcFilePath) + path.relative(srcPath, absoluteSrcFilePath), ) .replace(/HelloWorld/g, newProjectName) .replace(/helloworld/g, newProjectName.toLowerCase()); @@ -94,7 +94,7 @@ function copyProjectTemplateAndReplace( upgradeFileContentChangedCallback( absoluteSrcFilePath, relativeFilePath, - contentChanged + contentChanged, ); } copyAndReplace( @@ -105,7 +105,7 @@ function copyProjectTemplateAndReplace( HelloWorld: newProjectName, helloworld: newProjectName.toLowerCase(), }, - contentChangedCallback + contentChangedCallback, ); }); } @@ -127,6 +127,7 @@ function translateFilePath(filePath) { .replace('_gitignore', '.gitignore') .replace('_gitattributes', '.gitattributes') .replace('_babelrc', '.babelrc') + .replace('_eslintrc.js', '.eslintrc.js') .replace('_flowconfig', '.flowconfig') .replace('_buckconfig', '.buckconfig') .replace('_watchmanconfig', '.watchmanconfig'); @@ -135,7 +136,7 @@ function translateFilePath(filePath) { function upgradeFileContentChangedCallback( absoluteSrcFilePath, relativeDestPath, - contentChanged + contentChanged, ) { if (contentChanged === 'new') { logger.info(`${chalk.bold('new')} ${relativeDestPath}`); @@ -145,11 +146,11 @@ function upgradeFileContentChangedCallback( logger.info( `${chalk.bold(relativeDestPath)} ` + `has changed in the new version.\nDo you want to keep your ${relativeDestPath} or replace it with the ` + - `latest version?\nIf you ever made any changes ` + - `to this file, you'll probably want to keep it.\n` + + 'latest version?\nIf you ever made any changes ' + + "to this file, you'll probably want to keep it.\n" + `You can see the new version here: ${absoluteSrcFilePath}\n` + `Do you want to replace ${relativeDestPath}? ` + - `Answer y to replace, n to keep your version: ` + 'Answer y to replace, n to keep your version: ', ); const answer = prompt(); if (answer === 'y') { @@ -163,7 +164,7 @@ function upgradeFileContentChangedCallback( return 'keep'; } throw new Error( - `Unknown file changed state: ${relativeDestPath}, ${contentChanged}` + `Unknown file changed state: ${relativeDestPath}, ${contentChanged}`, ); } diff --git a/packages/cli/src/tools/generator/promptSync.js b/packages/cli/src/tools/generator/promptSync.js index ce17409af3..8c73a5a2cc 100644 --- a/packages/cli/src/tools/generator/promptSync.js +++ b/packages/cli/src/tools/generator/promptSync.js @@ -10,8 +10,6 @@ // Simplified version of: // https://github.com/0x00A/prompt-sync/blob/master/index.js -/* eslint-disable */ - import fs from 'fs'; const term = 13; // carriage return @@ -112,7 +110,7 @@ function create() { if (masked) { process.stdout.write( - `\u001b[2K\u001b[0G${ask}${Array(str.length + 1).join(echo)}` + `\u001b[2K\u001b[0G${ask}${Array(str.length + 1).join(echo)}`, ); } else { process.stdout.write('\u001b[s'); @@ -122,7 +120,7 @@ function create() { process.stdout.write(`\u001b[2K\u001b[0G${ask}${str}`); } else { process.stdout.write( - `\u001b[2K\u001b[0G${str}\u001b[${str.length - insert}D` + `\u001b[2K\u001b[0G${str}\u001b[${str.length - insert}D`, ); } process.stdout.write('\u001b[u'); diff --git a/packages/cli/src/tools/generator/templates.js b/packages/cli/src/tools/generator/templates.js index 66150c6b43..1520c0645d 100644 --- a/packages/cli/src/tools/generator/templates.js +++ b/packages/cli/src/tools/generator/templates.js @@ -8,12 +8,12 @@ * @flow */ -import { execSync } from 'child_process'; +import {execSync} from 'child_process'; import fs from 'fs'; import path from 'path'; import copyProjectTemplateAndReplace from './copyProjectTemplateAndReplace'; -import logger from '../logger'; -import PackageManager from '../PackageManager'; +import {logger} from '@react-native-community/cli-tools'; +import * as PackageManager from '../packageManager'; /** * @param destPath Create the new project at this path. @@ -22,11 +22,11 @@ import PackageManager from '../PackageManager'; * @param yarnVersion Version of yarn available on the system, or null if * yarn is not available. For example '0.18.1'. */ -function createProjectFromTemplate( +async function createProjectFromTemplate( destPath: string, newProjectName: string, template: string, - destinationRoot: string + destinationRoot: string, ) { const templatePath = path.dirname(require.resolve('react-native/template')); copyProjectTemplateAndReplace(templatePath, destPath, newProjectName); @@ -44,7 +44,12 @@ function createProjectFromTemplate( // This way we don't have to duplicate the native files in every template. // If we duplicated them we'd make RN larger and risk that people would // forget to maintain all the copies so they would go out of sync. - createFromRemoteTemplate(template, destPath, newProjectName, destinationRoot); + await createFromRemoteTemplate( + template, + destPath, + newProjectName, + destinationRoot, + ); } /** @@ -52,11 +57,11 @@ function createProjectFromTemplate( * - 'demo' -> Fetch the package react-native-template-demo from npm * - git://..., http://..., file://... or any other URL supported by npm */ -function createFromRemoteTemplate( +async function createFromRemoteTemplate( template: string, destPath: string, newProjectName: string, - destinationRoot: string + destinationRoot: string, ) { let installPackage; let templateName; @@ -72,9 +77,8 @@ function createFromRemoteTemplate( // Check if the template exists logger.info(`Fetching template ${installPackage}...`); - const packageManager = new PackageManager({ projectDir: destinationRoot }); try { - packageManager.install([installPackage]); + await PackageManager.install([installPackage]); const templatePath = path.resolve('node_modules', templateName); copyProjectTemplateAndReplace(templatePath, destPath, newProjectName, { // Every template contains a dummy package.json file included @@ -87,24 +91,24 @@ function createFromRemoteTemplate( 'devDependencies.json', ], }); - installTemplateDependencies(templatePath, destinationRoot); - installTemplateDevDependencies(templatePath, destinationRoot); + await installTemplateDependencies(templatePath, destinationRoot); + await installTemplateDevDependencies(templatePath, destinationRoot); } finally { // Clean up the temp files try { - packageManager.uninstall([templateName]); + await PackageManager.uninstall([templateName]); } catch (err) { // Not critical but we still want people to know and report // if this the clean up fails. logger.warn( `Failed to clean up template temp files in node_modules/${templateName}. ` + - 'This is not a critical error, you can work on your app.' + 'This is not a critical error, you can work on your app.', ); } } } -function installTemplateDependencies(templatePath, destinationRoot) { +async function installTemplateDependencies(templatePath, destinationRoot) { // dependencies.json is a special file that lists additional dependencies // that are required by this template const dependenciesJsonPath = path.resolve(templatePath, 'dependencies.json'); @@ -119,25 +123,23 @@ function installTemplateDependencies(templatePath, destinationRoot) { dependencies = require(dependenciesJsonPath); } catch (err) { throw new Error( - `Could not parse the template's dependencies.json: ${err.message}` + `Could not parse the template's dependencies.json: ${err.message}`, ); } const dependenciesToInstall = Object.keys(dependencies).map( - depName => `${depName}@${dependencies[depName]}` - ); - new PackageManager({ projectDir: destinationRoot }).install( - dependenciesToInstall + depName => `${depName}@${dependencies[depName]}`, ); + await PackageManager.install(dependenciesToInstall); logger.info("Linking native dependencies into the project's build files..."); - execSync('react-native link', { stdio: 'inherit' }); + execSync('react-native link', {stdio: 'inherit'}); } -function installTemplateDevDependencies(templatePath, destinationRoot) { +async function installTemplateDevDependencies(templatePath, destinationRoot) { // devDependencies.json is a special file that lists additional develop dependencies // that are required by this template const devDependenciesJsonPath = path.resolve( templatePath, - 'devDependencies.json' + 'devDependencies.json', ); logger.info('Adding develop dependencies for the project...'); if (!fs.existsSync(devDependenciesJsonPath)) { @@ -150,16 +152,14 @@ function installTemplateDevDependencies(templatePath, destinationRoot) { dependencies = require(devDependenciesJsonPath); } catch (err) { throw new Error( - `Could not parse the template's devDependencies.json: ${err.message}` + `Could not parse the template's devDependencies.json: ${err.message}`, ); } const dependenciesToInstall = Object.keys(dependencies).map( - depName => `${depName}@${dependencies[depName]}` - ); - new PackageManager({ projectDir: destinationRoot }).installDev( - dependenciesToInstall + depName => `${depName}@${dependencies[depName]}`, ); + await PackageManager.installDev(dependenciesToInstall); } -export { createProjectFromTemplate }; +export {createProjectFromTemplate}; diff --git a/packages/cli/src/tools/getHooks.js b/packages/cli/src/tools/getHooks.js deleted file mode 100644 index ec8da8a4ab..0000000000 --- a/packages/cli/src/tools/getHooks.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @flow - */ - -import { spawn } from 'child_process'; -import getPackageConfiguration from './getPackageConfiguration'; - -export function makeCommand(command: string) { - // eslint-disable-next-line flowtype/no-weak-types - return (cb: Function) => { - if (!cb) { - throw new Error( - `You missed a callback function for the ${command} command` - ); - } - - const args = command.split(' '); - const cmd = args.shift(); - - const commandProcess = spawn(cmd, args, { - stdio: 'inherit', - stdin: 'inherit', - }); - - commandProcess.on('close', code => { - if (code) { - throw new Error(`Error occurred during executing "${command}" command`); - } - - cb(); - }); - }; -} - -export default function getHooks(root: string) { - const commands = getPackageConfiguration(root).commands || {}; - - const acc = {}; - - Object.keys(commands).forEach(command => { - acc[command] = makeCommand(commands[command]); - }); - - return acc; -} diff --git a/packages/cli/src/tools/getLegacyConfig.js b/packages/cli/src/tools/getLegacyConfig.js deleted file mode 100644 index c359d8fc5c..0000000000 --- a/packages/cli/src/tools/getLegacyConfig.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @flow - */ -import path from 'path'; -import util from 'util'; - -import getPlatforms from './getPlatforms'; -import getPackageConfiguration from './getPackageConfiguration'; -import getHooks from './getHooks'; -import getAssets from './getAssets'; -import getParams from './getParams'; - -const generateDeprecationMessage = api => - `${api} is deprecated and will be removed soon. Please check release notes on how to upgrade`; - -/** - * Gets legacy configuration to support existing plugins while they migrate - * to the new API - * - * This file will be removed from the next version. - */ -export default (root: string) => ({ - getPlatformConfig: util.deprecate( - () => getPlatforms(root), - generateDeprecationMessage('getPlatformConfig()') - ), - getProjectConfig: util.deprecate(() => { - const platforms = getPlatforms(root); - - const rnpm = getPackageConfiguration(root); - - const config = { - ...rnpm, - assets: getAssets(root), - }; - - Object.keys(platforms).forEach(key => { - config[key] = platforms[key].projectConfig(root, rnpm[key] || {}); - }); - - return config; - }, generateDeprecationMessage('getProjectConfig()')), - getDependencyConfig: util.deprecate((packageName: string) => { - const platforms = getPlatforms(root); - const folder = path.join(process.cwd(), 'node_modules', packageName); - - const rnpm = getPackageConfiguration(folder); - - const config = { - ...rnpm, - assets: getAssets(folder), - commands: getHooks(folder), - params: getParams(folder), - }; - - Object.keys(platforms).forEach(key => { - config[key] = platforms[key].dependencyConfig(folder, rnpm[key] || {}); - }); - - return config; - }, generateDeprecationMessage('getDependencyConfig()')), -}); diff --git a/packages/cli/src/tools/getPackageConfiguration.js b/packages/cli/src/tools/getPackageConfiguration.js deleted file mode 100644 index e430b565cc..0000000000 --- a/packages/cli/src/tools/getPackageConfiguration.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @flow - */ -import path from 'path'; -import type { PackageConfigurationT } from './types.flow'; - -/** - * Returns configuration of the CLI from `package.json`. - */ -export default function getPackageConfiguration( - folder: string -): PackageConfigurationT { - return require(path.join(folder, './package.json')).rnpm || {}; -} diff --git a/packages/cli/src/tools/getParams.js b/packages/cli/src/tools/getParams.js deleted file mode 100644 index d8a528b60e..0000000000 --- a/packages/cli/src/tools/getParams.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @flow - */ - -import getPackageConfiguration from './getPackageConfiguration'; - -export default function getParams(root: string) { - const config = getPackageConfiguration(root); - return config.params || []; -} diff --git a/packages/cli/src/tools/getPlatforms.js b/packages/cli/src/tools/getPlatforms.js deleted file mode 100644 index 84fd955541..0000000000 --- a/packages/cli/src/tools/getPlatforms.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @flow - */ - -import path from 'path'; -import type { PlatformsT } from './types.flow'; - -import findPlugins from './findPlugins'; - -/** - * Support for `ios` and `android` platforms is built-in - * - * @todo(grabbou): Move this out of the core to increase "interoperability" - * with other platforms - */ -const builtInPlatforms = { - ios: require('./ios'), - android: require('./android'), -}; - -/** - * Returns an object with available platforms - */ -export default function getPlatforms(root: string): PlatformsT { - const plugins = findPlugins(root); - - /** - * Each `platfom` is a file that should define an object with platforms available - * and the config required. - * - * @todo(grabbou): We should validate if the config loaded is correct, warn and skip - * using it if it's invalid. - */ - const projectPlatforms = plugins.platforms.reduce( - (acc, pathToPlatform) => - Object.assign( - acc, - require(path.join(root, 'node_modules', pathToPlatform)) - ), - {} - ); - - return { - ...builtInPlatforms, - ...projectPlatforms, - }; -} - -const names = { - ios: 'iOS', - android: 'Android', -}; - -export function getPlatformName(name: string) { - return names[name] || name; -} diff --git a/packages/cli/src/tools/installPods.js b/packages/cli/src/tools/installPods.js new file mode 100644 index 0000000000..04d6e9e5ae --- /dev/null +++ b/packages/cli/src/tools/installPods.js @@ -0,0 +1,125 @@ +// @flow +import fs from 'fs'; +import execa from 'execa'; +import chalk from 'chalk'; +import Ora from 'ora'; +import inquirer from 'inquirer'; +import {logger} from '@react-native-community/cli-tools'; +import {NoopLoader} from './loader'; + +async function installPods({ + projectName, + loader, +}: { + projectName: string, + loader?: typeof Ora, +}) { + loader = loader || new NoopLoader(); + try { + if (!fs.existsSync('ios')) { + return; + } + + process.chdir('ios'); + + const hasPods = fs.existsSync('Podfile'); + + if (!hasPods) { + return; + } + + try { + // Check if "pod" is available and usable. It happens that there are + // multiple versions of "pod" command and even though it's there, it exits + // with a failure + await execa('pod', ['--version']); + } catch (e) { + loader.info(); + + const {shouldInstallCocoaPods} = await inquirer.prompt([ + { + type: 'confirm', + name: 'shouldInstallCocoaPods', + message: `CocoaPods ${chalk.dim.underline( + '(https://cocoapods.org/)', + )} ${chalk.reset.bold( + "is not installed. It's necessary for iOS project to run correctly. Do you want to install it?", + )}`, + }, + ]); + + if (shouldInstallCocoaPods) { + loader.start('Installing CocoaPods'); + + try { + // First attempt to install `cocoapods` + await execa('gem', ['install', 'cocoapods', '--no-document']); + loader.succeed(); + } catch (_error) { + try { + // If that doesn't work then try with sudo + await execa('sudo', [ + 'gem', + 'install', + 'cocoapods', + '--no-document', + ]); + } catch (error) { + loader.fail(); + logger.log(error.stderr); + + throw new Error( + `Error occured while trying to install CocoaPods, which is required by this template.\nPlease try again manually: "sudo gem install cocoapods".\nCocoaPods documentation: ${chalk.dim.underline( + 'https://cocoapods.org/', + )}`, + ); + } + } + + try { + loader.start( + `Updating CocoaPods repositories ${chalk.dim( + '(this make take a few minutes)', + )}`, + ); + await execa('pod', ['repo', 'update']); + } catch (error) { + // "pod" command outputs errors to stdout (at least some of them) + logger.log(error.stderr || error.stdout); + loader.fail(); + + throw new Error( + `Failed to update CocoaPods repositories for iOS project.\nPlease try again manually: "pod repo update".\nCocoaPods documentation: ${chalk.dim.underline( + 'https://cocoapods.org/', + )}`, + ); + } + } + } + + try { + loader.succeed(); + loader.start( + `Installing CocoaPods dependencies ${chalk.dim( + '(this make take a few minutes)', + )}`, + ); + await execa('pod', ['install']); + } catch (error) { + // "pod" command outputs errors to stdout (at least some of them) + logger.log(error.stderr || error.stdout); + + throw new Error( + `Failed to install CocoaPods dependencies for iOS project, which is required by this template.\nPlease try again manually: "cd ./${projectName}/ios && pod install".\nCocoaPods documentation: ${chalk.dim.underline( + 'https://cocoapods.org/', + )}`, + ); + } + } catch (error) { + throw error; + } finally { + process.chdir('..'); + } +} + +export default installPods; diff --git a/packages/cli/src/tools/ios/findPodspecName.js b/packages/cli/src/tools/ios/findPodspecName.js deleted file mode 100644 index 67126cea13..0000000000 --- a/packages/cli/src/tools/ios/findPodspecName.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import glob from 'glob'; -import path from 'path'; - -export default function findPodspecName(folder) { - const podspecs = glob.sync('*.podspec', { cwd: folder }); - let podspecFile = null; - if (podspecs.length === 0) { - return null; - } - if (podspecs.length === 1) { - podspecFile = podspecs[0]; // eslint-disable-line prefer-destructuring - } else { - const folderParts = folder.split(path.sep); - const currentFolder = folderParts[folderParts.length - 1]; - const toSelect = podspecs.indexOf(`${currentFolder}.podspec`); - if (toSelect === -1) { - podspecFile = podspecs[0]; // eslint-disable-line prefer-destructuring - } else { - podspecFile = podspecs[toSelect]; - } - } - - return podspecFile.replace('.podspec', ''); -} diff --git a/packages/cli/src/tools/loadMetroConfig.js b/packages/cli/src/tools/loadMetroConfig.js index 2d79bb173e..a59f287511 100644 --- a/packages/cli/src/tools/loadMetroConfig.js +++ b/packages/cli/src/tools/loadMetroConfig.js @@ -3,16 +3,16 @@ * @flow */ import path from 'path'; -import { createBlacklist } from 'metro'; -import { loadConfig } from 'metro-config'; -import type { ContextT } from './types.flow'; -import findPlugins from './findPlugins'; +import {createBlacklist} from 'metro'; +import {loadConfig} from 'metro-config'; +import {existsSync} from 'fs'; +import {type ConfigT} from 'types'; import findSymlinkedModules from './findSymlinkedModules'; const resolveSymlinksForRoots = roots => roots.reduce( (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)), - [...roots] + [...roots], ); const getWatchFolders = () => { @@ -31,39 +31,37 @@ 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) => { - const plugins = findPlugins(ctx.root); - +export const getDefaultConfig = (ctx: ConfigT) => { + const hasteImplPath = path.join(ctx.reactNativePath, 'jest/hasteImpl.js'); return { resolver: { resolverMainFields: ['react-native', 'browser', 'main'], blacklistRE: getBlacklistRE(), - platforms: ['ios', 'android', 'native', ...plugins.haste.platforms], - providesModuleNodeModules: [ - 'react-native', - ...plugins.haste.providesModuleNodeModules, - ], - hasteImplModulePath: path.join(ctx.reactNativePath, 'jest/hasteImpl'), + platforms: [...ctx.haste.platforms, 'native'], + providesModuleNodeModules: ctx.haste.providesModuleNodeModules, + hasteImplModulePath: existsSync(hasteImplPath) + ? hasteImplPath + : undefined, }, serializer: { getModulesRunBeforeMainModule: () => [ require.resolve( - path.join(ctx.reactNativePath, 'Libraries/tools/InitializeCore') + path.join(ctx.reactNativePath, 'Libraries/Core/InitializeCore'), ), ], getPolyfills: () => require(path.join(ctx.reactNativePath, 'rn-get-polyfills'))(), }, server: { - port: process.env.RCT_METRO_PORT || 8081, + port: Number(process.env.RCT_METRO_PORT) || 8081, }, transformer: { babelTransformerPath: require.resolve( - 'metro-react-native-babel-transformer' + 'metro-react-native-babel-transformer', ), assetRegistryPath: path.join( ctx.reactNativePath, - 'Libraries/Image/AssetRegistry' + 'Libraries/Image/AssetRegistry', ), }, watchFolders: getWatchFolders(), @@ -76,7 +74,7 @@ export type ConfigOptionsT = {| resetCache?: boolean, watchFolders?: string[], sourceExts?: string[], - reporter?: any, // eslint-disable-line flowtype/no-weak-types + reporter?: any, config?: string, |}; @@ -85,20 +83,20 @@ export type ConfigOptionsT = {| * * This allows the CLI to always overwrite the file settings. */ -export default async function load( - ctx: ContextT, - // $FlowFixMe - troubles with empty object being inexact - options?: ConfigOptionsT = {} -) { +export default function load(ctx: ConfigT, options?: ConfigOptionsT) { const defaultConfig = getDefaultConfig(ctx); - - const config = await loadConfig( - { - cwd: ctx.root, - ...options, - }, - defaultConfig - ); - - return config; + if (options && options.reporter) { + /** + * $FlowIssue: Metro doesn't accept `reporter` to be passed along other options + * and will ignore the value, if provided. + * + * We explicitly read `reporter` value and set it on a default configuration. Note + * that all other options described in the `ConfigOptionsT` are handled by Metro + * automatically. + * + * This is a temporary workaround. + */ + defaultConfig.reporter = options.reporter; + } + return loadConfig({cwd: ctx.root, ...options}, defaultConfig); } diff --git a/packages/cli/src/tools/loader.js b/packages/cli/src/tools/loader.js new file mode 100644 index 0000000000..b0c480975f --- /dev/null +++ b/packages/cli/src/tools/loader.js @@ -0,0 +1,16 @@ +// @flow +import Ora from 'ora'; +import logger from './logger'; + +class OraNoop { + succeed() {} + fail() {} + start(message?: string) {} + info(message?: string) {} +} + +export function getLoader(): typeof Ora { + return logger.isVerbose() ? OraNoop : Ora; +} + +export const NoopLoader = OraNoop; diff --git a/packages/cli/src/tools/logger.js b/packages/cli/src/tools/logger.js index 35aeff6815..839cbbe637 100644 --- a/packages/cli/src/tools/logger.js +++ b/packages/cli/src/tools/logger.js @@ -1,42 +1 @@ -/** - * @flow - */ -import chalk from 'chalk'; - -const SEPARATOR = ', '; - -const formatMessages = (messages: Array) => - chalk.reset(messages.join(SEPARATOR)); - -const success = (...messages: Array) => { - console.log(`${chalk.green.bold('success')} ${formatMessages(messages)}`); -}; - -const info = (...messages: Array) => { - console.log(`${chalk.cyan.bold('info')} ${formatMessages(messages)}`); -}; - -const warn = (...messages: Array) => { - console.warn(`${chalk.yellow.bold('warn')} ${formatMessages(messages)}`); -}; - -const error = (...messages: Array) => { - console.error(`${chalk.red.bold('error')} ${formatMessages(messages)}`); -}; - -const debug = (...messages: Array) => { - console.log(`${chalk.gray.bold('debug')} ${formatMessages(messages)}`); -}; - -const log = (...messages: Array) => { - console.log(`${formatMessages(messages)}`); -}; - -export default { - success, - info, - warn, - error, - debug, - log, -}; +export {logger as default} from '@react-native-community/cli-tools'; diff --git a/packages/cli/src/tools/merge.js b/packages/cli/src/tools/merge.js new file mode 100644 index 0000000000..4439b50cc0 --- /dev/null +++ b/packages/cli/src/tools/merge.js @@ -0,0 +1,15 @@ +/** + * @flow + */ + +import deepmerge from 'deepmerge'; + +/** + * `deepmerge` concatenates arrays by default instead of overwriting them. + * We define custom merging function for arrays to change that behaviour + */ +export default function merge(...objs: Array<{[key: string]: any}>) { + return deepmerge(...objs, { + arrayMerge: (destinationArray, sourceArray, options) => sourceArray, + }); +} diff --git a/packages/cli/src/tools/packageManager.js b/packages/cli/src/tools/packageManager.js new file mode 100644 index 0000000000..b85e8c293a --- /dev/null +++ b/packages/cli/src/tools/packageManager.js @@ -0,0 +1,78 @@ +// @flow +import execa from 'execa'; +import logger from './logger'; +import {getYarnVersionIfAvailable, isProjectUsingYarn} from './yarn'; + +type Options = {| + preferYarn?: boolean, + silent?: boolean, + cwd?: string, +|}; + +let projectDir; + +const packageManagers = { + yarn: { + install: ['add'], + installDev: ['add', '-D'], + uninstall: ['remove'], + installAll: ['install'], + }, + npm: { + install: ['install', '--save', '--save-exact'], + installDev: ['install', '--save-dev', '--save-exact'], + uninstall: ['uninstall', '--save'], + installAll: ['install'], + }, +}; + +function configurePackageManager( + packageNames: Array, + options?: Options, + action: 'install' | 'installDev' | 'installAll' | 'uninstall', +) { + const pm = shouldUseYarn(options) ? 'yarn' : 'npm'; + const [executable, ...flags] = packageManagers[pm][action]; + const args = [executable, ...flags, ...packageNames]; + return executeCommand(pm, args, options); +} + +function executeCommand( + command: string, + args: Array, + options?: Options, +) { + return execa(command, args, { + stdio: + options && options.silent && !logger.isVerbose() ? 'pipe' : 'inherit', + cwd: options && options.cwd, + }); +} + +function shouldUseYarn(options?: Options) { + if (options && options.preferYarn !== undefined) { + return options.preferYarn && getYarnVersionIfAvailable(); + } + + return isProjectUsingYarn(projectDir) && getYarnVersionIfAvailable(); +} + +export function setProjectDir(dir: string) { + projectDir = dir; +} + +export function install(packageNames: Array, options?: Options) { + return configurePackageManager(packageNames, options, 'install'); +} + +export function installDev(packageNames: Array, options?: Options) { + return configurePackageManager(packageNames, options, 'installDev'); +} + +export function uninstall(packageNames: Array, options?: Options) { + return configurePackageManager(packageNames, options, 'uninstall'); +} + +export function installAll(options?: Options) { + return configurePackageManager([], options, 'installAll'); +} diff --git a/packages/cli/src/tools/releaseChecker/getLatestRelease.js b/packages/cli/src/tools/releaseChecker/getLatestRelease.js new file mode 100644 index 0000000000..7f41a2304e --- /dev/null +++ b/packages/cli/src/tools/releaseChecker/getLatestRelease.js @@ -0,0 +1,140 @@ +/** + * @flow + */ +import https from 'https'; +import semver from 'semver'; +import logger from '../logger'; +import cacheManager from './releaseCacheManager'; + +export type Release = { + version: string, + changelogUrl: string, +}; + +/** + * Checks via GitHub API if there is a newer stable React Native release and, + * if it exists, returns the release data. + * + * If the latest release is not newer or if it's a prerelease, the function + * will return undefined. + */ +export default async function getLatestRelease( + name: string, + currentVersion: string, +) { + logger.debug('Checking for a newer version of React Native'); + try { + logger.debug(`Current version: ${currentVersion}`); + + const cachedLatest = cacheManager.get(name, 'latestVersion'); + + if (cachedLatest) { + logger.debug(`Cached release version: ${cachedLatest}`); + } + + const aWeek = 7 * 24 * 60 * 60 * 1000; + const lastChecked = cacheManager.get(name, 'lastChecked'); + const now = new Date(); + if (lastChecked && now - new Date(lastChecked) < aWeek) { + logger.debug('Cached release is still recent, skipping remote check'); + return; + } + + logger.debug('Checking for newer releases on GitHub'); + const eTag = cacheManager.get(name, 'eTag'); + const latestVersion = await getLatestRnDiffPurgeVersion(name, eTag); + logger.debug(`Latest release: ${latestVersion}`); + + if ( + semver.compare(latestVersion, currentVersion) === 1 && + !semver.prerelease(latestVersion) + ) { + return { + version: latestVersion, + changelogUrl: buildChangelogUrl(latestVersion), + }; + } + } catch (e) { + logger.debug( + 'Something went wrong with remote version checking, moving on', + ); + logger.debug(e); + } +} + +function buildChangelogUrl(version: string) { + return `https://github.com/facebook/react-native/releases/tag/v${version}`; +} + +/** + * Returns the most recent React Native version available to upgrade to. + */ +async function getLatestRnDiffPurgeVersion(name: string, eTag: ?string) { + const options = { + hostname: 'api.github.com', + path: '/repos/react-native-community/rn-diff-purge/tags', + // https://developer.github.com/v3/#user-agent-required + headers: ({'User-Agent': 'React-Native-CLI'}: Headers), + }; + + if (eTag) { + options.headers['If-None-Match'] = eTag; + } + + const response = await httpsGet(options); + + // Remote is newer. + if (response.statusCode === 200) { + const latestVersion = JSON.parse(response.body)[0].name.substring(8); + + // Update cache only if newer release is stable. + if (!semver.prerelease(latestVersion)) { + logger.debug(`Saving ${response.eTag} to cache`); + cacheManager.set(name, 'eTag', response.eTag); + cacheManager.set(name, 'latestVersion', latestVersion); + } + + return latestVersion; + } + + // Cache is still valid. + if (response.statusCode === 304) { + const latestVersion = cacheManager.get(name, 'latestVersion'); + if (latestVersion) { + return latestVersion; + } + } + + // Should be returned only if something went wrong. + return '0.0.0'; +} + +type Headers = { + 'User-Agent': mixed, + [header: string]: mixed, +}; + +function httpsGet(options) { + return new Promise((resolve, reject) => { + https + .get(options, result => { + let body = ''; + + result.setEncoding('utf8'); + result.on('data', data => { + body += data; + }); + + result.on('end', () => { + resolve({ + body, + eTag: result.headers.etag, + statusCode: result.statusCode, + }); + }); + + result.on('error', error => reject(error)); + }) + .on('error', error => reject(error)); + }); +} diff --git a/packages/cli/src/tools/releaseChecker/index.js b/packages/cli/src/tools/releaseChecker/index.js new file mode 100644 index 0000000000..1d0dd15ce8 --- /dev/null +++ b/packages/cli/src/tools/releaseChecker/index.js @@ -0,0 +1,29 @@ +// @flow +import path from 'path'; +import {logger} from '@react-native-community/cli-tools'; +import resolveNodeModuleDir from '../config/resolveNodeModuleDir'; +import getLatestRelease from './getLatestRelease'; +import printNewRelease from './printNewRelease'; + +export default async function releaseChecker(root: string) { + try { + const {version: currentVersion} = require(path.join( + resolveNodeModuleDir(root, 'react-native'), + 'package.json', + )); + const {name} = require(path.join(root, 'package.json')); + const latestRelease = await getLatestRelease(name, currentVersion); + + if (latestRelease) { + printNewRelease(name, latestRelease, currentVersion); + } + } catch (e) { + // We let the flow continue as this component is not vital for the rest of + // the CLI. + logger.debug( + 'Cannot detect current version of React Native, ' + + 'skipping check for a newer release', + ); + logger.debug(e); + } +} diff --git a/packages/cli/src/tools/releaseChecker/printNewRelease.js b/packages/cli/src/tools/releaseChecker/printNewRelease.js new file mode 100644 index 0000000000..cfababab70 --- /dev/null +++ b/packages/cli/src/tools/releaseChecker/printNewRelease.js @@ -0,0 +1,26 @@ +/** + * @flow + */ +import chalk from 'chalk'; +import logger from '../logger'; +import type {Release} from './getLatestRelease'; +import cacheManager from './releaseCacheManager'; + +/** + * Notifies the user that a newer version of React Native is available. + */ +export default function printNewRelease( + name: string, + latestRelease: Release, + currentVersion: string, +) { + logger.info( + `React Native v${ + latestRelease.version + } is now available (your project is running on v${currentVersion}).`, + ); + logger.info(`Changelog: ${chalk.dim.underline(latestRelease.changelogUrl)}.`); + logger.info(`To upgrade, run "${chalk.bold('react-native upgrade')}".`); + + cacheManager.set(name, 'lastChecked', new Date().toISOString()); +} diff --git a/packages/cli/src/tools/releaseChecker/releaseCacheManager.js b/packages/cli/src/tools/releaseChecker/releaseCacheManager.js new file mode 100644 index 0000000000..193af6c332 --- /dev/null +++ b/packages/cli/src/tools/releaseChecker/releaseCacheManager.js @@ -0,0 +1,69 @@ +/** + * @flow + */ +import path from 'path'; +import fs from 'fs'; +import os from 'os'; +import mkdirp from 'mkdirp'; +import logger from '../logger'; + +type ReleaseCacheKey = 'eTag' | 'lastChecked' | 'latestVersion'; +type Cache = {[key: ReleaseCacheKey]: string}; + +function loadCache(name: string): ?Cache { + try { + const cacheRaw = fs.readFileSync( + path.resolve(getCacheRootPath(), name), + 'utf8', + ); + const cache = JSON.parse(cacheRaw); + return cache; + } catch (e) { + if (e.code === 'ENOENT') { + // Create cache file since it doesn't exist. + saveCache(name, {}); + } + logger.debug('No release cache found'); + } +} + +function saveCache(name: string, cache: Cache) { + fs.writeFileSync( + path.resolve(getCacheRootPath(), name), + JSON.stringify(cache, null, 2), + ); +} + +/** + * Returns the path string of `$HOME/.react-native-cli`. + * + * In case it doesn't exist, it will be created. + */ +function getCacheRootPath() { + const cachePath = path.resolve(os.homedir(), '.react-native-cli', 'cache'); + if (!fs.existsSync(cachePath)) { + mkdirp(cachePath); + } + + return cachePath; +} + +function get(name: string, key: ReleaseCacheKey): ?string { + const cache = loadCache(name); + if (cache) { + return cache[key]; + } +} + +function set(name: string, key: ReleaseCacheKey, value: string) { + const cache = loadCache(name); + if (cache) { + cache[key] = value; + saveCache(name, cache); + } +} + +export default { + get, + set, +}; diff --git a/packages/cli/src/tools/types.flow.js b/packages/cli/src/tools/types.flow.js deleted file mode 100644 index 4082413336..0000000000 --- a/packages/cli/src/tools/types.flow.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable flowtype/no-weak-types */ - -export type ContextT = { - root: string, - reactNativePath: string, -}; - -export type LocalCommandT = { - 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, - }>, -}; - -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; - -/** - * Config of a single platform - */ -export type PlatformConfigT = { - projectConfig: (string, ParamsT) => ?ProjectConfigT, - dependencyConfig: (string, ParamsT) => ?DependencyConfigT, - /** - * @todo(grabbou): This should not be part of the "core". It should be - * specific to `link` and `unlink`. Remove it from here soon. - */ - linkConfig: () => { - /** - * @todo(grabbou): Revert the arguments order to align with the rest - */ - isInstalled: (ProjectConfigT, string, DependencyConfigT) => boolean, - register: (string, DependencyConfigT, Object, ProjectConfigT) => void, - unregister: ( - string, - DependencyConfigT, - ProjectConfigT, - Array - ) => void, - copyAssets: (string[], ProjectConfigT) => void, - unlinkAssets: (string[], ProjectConfigT) => void, - }, -}; - -/** - * The following types will be useful when we type `link` itself. For now, - * they can be treated as aliases. - */ -export type AndroidConfigParamsT = {}; - -export type IOSConfigParamsT = {}; - -export type ProjectConfigIOST = {}; - -export type DependencyConfigIOST = ProjectConfigIOST; - -export type ProjectConfigAndroidT = {}; - -export type DependencyConfigAndroidT = {}; - -/** - * Config of a project. - * - * When one of the projects is `null`, that means given platform - * is not available in the current project. - */ -export type ProjectConfigT = { - android: ?ProjectConfigAndroidT, - ios: ?ProjectConfigIOST, -}; - -/** - * Config of a dependency. Just like above, when one of the values is `null`, - * given platform is not available. - */ -export type DependencyConfigT = { - android: ?DependencyConfigAndroidT, - ios: ?DependencyConfigIOST, -}; - -export type DependenciesConfig = { - config: DependencyConfigT, - name: string, - path: string, - assets: string[], - commands: { [name: string]: string }, - params: InquirerPromptT[], -}; - -/** - * Available platforms. Additional plugins should assert the type on their own. - */ -export type PlatformsT = { - ios: PlatformConfigT< - ProjectConfigIOST, - DependencyConfigIOST, - IOSConfigParamsT - >, - android: PlatformConfigT< - ProjectConfigAndroidT, - DependencyConfigAndroidT, - AndroidConfigParamsT - >, - [name: string]: PlatformConfigT, -}; - -export type InquirerPromptT = any; - -/** - * Configuration of the CLI as set by a package in the package.json - */ -export type PackageConfigurationT = { - assets?: string[], - commands?: { [name: string]: string }, - params?: InquirerPromptT[], - android: AndroidConfigParamsT, - ios: IOSConfigParamsT, -}; diff --git a/packages/cli/src/tools/walk.js b/packages/cli/src/tools/walk.js index 5fdc888481..fb0a81eba5 100644 --- a/packages/cli/src/tools/walk.js +++ b/packages/cli/src/tools/walk.js @@ -4,13 +4,13 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import fs from 'fs'; import path from 'path'; -function walk(current) { +function walk(current: string) { if (!fs.lstatSync(current).isDirectory()) { return [current]; } diff --git a/packages/cli/src/tools/yarn.js b/packages/cli/src/tools/yarn.js index bb7372bf70..13817d42f6 100644 --- a/packages/cli/src/tools/yarn.js +++ b/packages/cli/src/tools/yarn.js @@ -7,17 +7,17 @@ * @format */ -import { execSync } from 'child_process'; +import {execSync} from 'child_process'; import fs from 'fs'; import path from 'path'; import semver from 'semver'; -import logger from './logger'; +import {logger} from '@react-native-community/cli-tools'; /** * Use Yarn if available, it's much faster than the npm client. * Return the version of yarn installed on the system, null if yarn is not available. */ -function getYarnVersionIfAvailable() { +export function getYarnVersionIfAvailable() { let yarnVersion; try { // execSync returns a Buffer -> convert to string @@ -48,11 +48,6 @@ function getYarnVersionIfAvailable() { * Let's be safe and not mix yarn and npm in a single project. * @param projectDir e.g. /Users/martin/AwesomeApp */ -function isGlobalCliUsingYarn(projectDir) { +export function isProjectUsingYarn(projectDir) { return fs.existsSync(path.join(projectDir, 'yarn.lock')); } - -export default { - getYarnVersionIfAvailable, - isGlobalCliUsingYarn, -}; diff --git a/packages/cli/testSetup.js b/packages/cli/testSetup.js deleted file mode 100644 index 7a043b8b89..0000000000 --- a/packages/cli/testSetup.js +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -jest.mock('./src/tools/logger'); diff --git a/packages/global-cli/index.js b/packages/global-cli/index.js index 1c8da2dad4..d24657bbdc 100755 --- a/packages/global-cli/index.js +++ b/packages/global-cli/index.js @@ -68,7 +68,7 @@ const getRNPkgJsonPath = function() { process.cwd(), 'node_modules', 'react-native', - 'package.json' + 'package.json', ); }; @@ -114,7 +114,10 @@ const commands = options._; if (cli) { cli.run(); } else { - if (options._.length === 0 && (options.h || options.help) || commands.length === 0) { + if ( + (options._.length === 0 && (options.h || options.help)) || + commands.length === 0 + ) { console.log( [ '', @@ -131,7 +134,7 @@ if (cli) { ' -v, --version use a specific version of React Native', ' --template use an app template. Use --template to see available templates.', '', - ].join('\n') + ].join('\n'), ); process.exit(0); } @@ -149,7 +152,7 @@ if (cli) { console.error( 'Command `%s` unrecognized. ' + 'Make sure that you have run `npm install` and that you are inside a react-native project.', - commands[0] + commands[0], ); process.exit(1); break; @@ -161,7 +164,7 @@ function validateProjectName(name) { console.error( '"%s" is not a valid name for a project. Please use a valid identifier ' + 'name (alphanumeric).', - name + name, ); process.exit(1); } @@ -170,7 +173,7 @@ function validateProjectName(name) { console.error( '"%s" is not a valid name for a project. Please do not use the ' + 'reserved word "React".', - name + name, ); process.exit(1); } @@ -220,7 +223,7 @@ function createProject(name, options) { console.log( 'This will walk you through creating a new React Native project in', - root + root, ); if (!fs.existsSync(root)) { @@ -239,7 +242,7 @@ function createProject(name, options) { }; fs.writeFileSync( path.join(root, 'package.json'), - JSON.stringify(packageJson) + JSON.stringify(packageJson), ); process.chdir(root); @@ -278,18 +281,18 @@ function run(root, projectName, options) { console.log(`Installing ${getInstallPackage(rnPackage)}...`); if (!forceNpmClient) { console.log( - 'Consider installing yarn to make this faster: https://yarnpkg.com' + 'Consider installing yarn to make this faster: https://yarnpkg.com', ); } installCommand = `npm install --save --save-exact ${getInstallPackage( - rnPackage + rnPackage, )}`; if (options.verbose) { installCommand += ' --verbose'; } } try { - execSync(installCommand, { stdio: 'inherit' }); + execSync(installCommand, {stdio: 'inherit'}); } catch (err) { console.error(err); console.error(`Command \`${installCommand}\` failed.`); @@ -307,11 +310,11 @@ function checkNodeVersion() { } if (!semver.satisfies(process.version, packageJson.engines.node)) { console.error( - 'You are currently running Node %s but React Native requires %s. ' + - 'Please use a supported version of Node.\n' + - 'See https://facebook.github.io/react-native/docs/getting-started.html', + 'You are currently running Node %s but React Native requires %s. ' + + 'Please use a supported version of Node.\n' + + 'See https://facebook.github.io/react-native/docs/getting-started.html', process.version, - packageJson.engines.node + packageJson.engines.node, ); } } @@ -322,7 +325,7 @@ function printVersionsAndExit(reactNativePackageJsonPath) { console.log(`react-native: ${require(reactNativePackageJsonPath).version}`); } catch (e) { console.log( - 'react-native: n/a - not inside a React Native project directory' + 'react-native: n/a - not inside a React Native project directory', ); } process.exit(); diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle new file mode 100644 index 0000000000..e311548654 --- /dev/null +++ b/packages/platform-android/native_modules.gradle @@ -0,0 +1,256 @@ +import groovy.json.JsonSlurper +import org.gradle.initialization.DefaultSettings + +def generatedFileName = "PackageList.java" +def generatedFileContentsTemplate = """ +package com.facebook.react; + +import android.app.Application; +import android.content.Context; +import android.content.res.Resources; + +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; +import java.util.Arrays; +import java.util.ArrayList; + +{{ packageImports }} + +public class PackageList { + private Application application; + private ReactNativeHost reactNativeHost; + public PackageList(ReactNativeHost reactNativeHost) { + this.reactNativeHost = reactNativeHost; + } + + public PackageList(Application application) { + this.reactNativeHost = null; + this.application = application; + } + + private ReactNativeHost getReactNativeHost() { + return this.reactNativeHost; + } + + private Resources getResources() { + return this.getApplication().getResources(); + } + + private Application getApplication() { + if (this.reactNativeHost == null) return this.application; + return this.reactNativeHost.getApplication(); + } + + private Context getApplicationContext() { + return this.getApplication().getApplicationContext(); + } + + public ArrayList getPackages() { + return new ArrayList<>(Arrays.asList( + new MainReactPackage(){{ packageClassInstances }} + )); + } +} +""" + +class ReactNativeModules { + private Logger logger + private Project project + private String packageName + private DefaultSettings defaultSettings + private String root + private ArrayList> reactNativeModules + + private static String LOG_PREFIX = ":ReactNative:" + + ReactNativeModules(Logger logger) { + this.logger = logger + } + + void applySettingsGradle(DefaultSettings defaultSettings, String root) { + this.defaultSettings = defaultSettings + this.root = root + this.reactNativeModules = this.getReactNativeConfig() + + addReactNativeModuleProjects() + } + + void applyBuildGradle(Project project, String root) { + this.project = project + this.root = root + this.reactNativeModules = this.getReactNativeConfig() + + addReactNativeModuleDependencies() + } + + /** + * Include the react native modules android projects and specify their project directory + */ + void addReactNativeModuleProjects() { + reactNativeModules.forEach { reactNativeModule -> + String nameCleansed = reactNativeModule["nameCleansed"] + String androidSourceDir = reactNativeModule["androidSourceDir"] + defaultSettings.include(":${nameCleansed}") + defaultSettings.project(":${nameCleansed}").projectDir = new File("${androidSourceDir}") + } + } + + /** + * Adds the react native modules as dependencies to the users `app` project + */ + void addReactNativeModuleDependencies() { + reactNativeModules.forEach { reactNativeModule -> + def nameCleansed = reactNativeModule["nameCleansed"] + project.dependencies { + // TODO(salakar): are other dependency scope methods such as `api` required? + implementation project(path: ":${nameCleansed}") + } + } + } + + /** + * This returns the users project root (e.g. where the node_modules dir is located). + * + * This defaults to up one directory from the root android directory unless the user has defined + * a `ext.reactNativeProjectRoot` extension property + * + * @return + */ + File getReactNativeProjectRoot() { + File androidRoot + + if (this.project) { + androidRoot = this.project.rootProject.projectDir + } else { + androidRoot = this.defaultSettings.rootProject.projectDir + } + + File rnRoot = new File(androidRoot, this.root) + this.logger.debug("${LOG_PREFIX}Using React Native project root path '${rnRoot.toString()}'") + return rnRoot + } + + /** + * Code-gen a java file with all the detected ReactNativePackage instances automatically added + * + * @param outputDir + * @param generatedFileName + * @param generatedFileContentsTemplate + */ + void generatePackagesFile(File outputDir, String generatedFileName, String generatedFileContentsTemplate) { + ArrayList>[] packages = this.reactNativeModules + String packageName = this.packageName + + String packageImports = "" + String packageClassInstances = "" + + if (packages.size() > 0) { + packageImports = "import ${packageName}.BuildConfig;\nimport ${packageName}.R;\n\n" + packageImports = packageImports + packages.collect { + "// ${it.name}\n${it.packageImportPath}" + }.join('\n') + packageClassInstances = ",\n " + packages.collect { it.packageInstance }.join(",\n ") + } + + String generatedFileContents = generatedFileContentsTemplate + .replace("{{ packageImports }}", packageImports) + .replace("{{ packageClassInstances }}", packageClassInstances) + + outputDir.mkdirs() + final FileTreeBuilder treeBuilder = new FileTreeBuilder(outputDir) + treeBuilder.file(generatedFileName).newWriter().withWriter { w -> + w << generatedFileContents + } + } + + /** + * Runs a process to call the React Native CLI Config command and parses the output + * + * @return ArrayList < HashMap < String , String > > + */ + ArrayList> getReactNativeConfig() { + if (this.reactNativeModules != null) return this.reactNativeModules + ArrayList> reactNativeModules = new ArrayList>() + + def cmdProcess + def root = getReactNativeProjectRoot() + def command = "node ./node_modules/react-native/cli.js config" + def reactNativeConfigOutput = "" + + try { + cmdProcess = Runtime.getRuntime().exec(command, null, root) + def bufferedReader = new BufferedReader(new InputStreamReader(cmdProcess.getInputStream())) + def buff = "" + def readBuffer = new StringBuffer() + while ((buff = bufferedReader.readLine()) != null){ + readBuffer.append(buff) + } + reactNativeConfigOutput = readBuffer.toString() + } catch (Exception exception) { + this.logger.warn("${LOG_PREFIX}${exception.message}") + this.logger.warn("${LOG_PREFIX}Automatic import of native modules failed.") + return reactNativeModules + } + + def json = new JsonSlurper().parseText(reactNativeConfigOutput) + this.packageName = json["project"]["android"]["packageName"] + def dependencies = json["dependencies"] + + dependencies.each { name, value -> + def platformsConfig = value["platforms"]; + def androidConfig = platformsConfig["android"] + + if (androidConfig != null && androidConfig["sourceDir"] != null) { + this.logger.info("${LOG_PREFIX}Automatically adding native module '${name}'") + + HashMap reactNativeModuleConfig = new HashMap() + reactNativeModuleConfig.put("name", name) + reactNativeModuleConfig.put("nameCleansed", name.replaceAll('/', '_')) + reactNativeModuleConfig.put("androidSourceDir", androidConfig["sourceDir"]) + reactNativeModuleConfig.put("packageInstance", androidConfig["packageInstance"]) + reactNativeModuleConfig.put("packageImportPath", androidConfig["packageImportPath"]) + this.logger.trace("${LOG_PREFIX}'${name}': ${reactNativeModuleConfig.toMapString()}") + + reactNativeModules.add(reactNativeModuleConfig) + } else { + this.logger.info("${LOG_PREFIX}Skipping native module '${name}'") + } + } + + return reactNativeModules + } +} + +/** ----------------------- + * Exported Extensions + * ------------------------ */ + +def autoModules = new ReactNativeModules(logger) + +ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = ".." -> + autoModules.applySettingsGradle(defaultSettings, root) +} + +ext.applyNativeModulesAppBuildGradle = { Project project, String root = ".." -> + autoModules.applyBuildGradle(project, root) + + def generatedSrcDir = new File(buildDir, "generated/rncli/src/main/java/com/facebook/react") + + task generatePackageList { + doLast { + autoModules.generatePackagesFile(generatedSrcDir, generatedFileName, generatedFileContentsTemplate) + } + } + + preBuild.dependsOn generatePackageList + + android { + sourceSets { + main { + java { + srcDirs += generatedSrcDir + } + } + } + } +} diff --git a/packages/platform-android/package.json b/packages/platform-android/package.json new file mode 100644 index 0000000000..6e3fad8b81 --- /dev/null +++ b/packages/platform-android/package.json @@ -0,0 +1,17 @@ +{ + "name": "@react-native-community/cli-platform-android", + "version": "2.4.1", + "license": "MIT", + "main": "build/index.js", + "dependencies": { + "@react-native-community/cli-tools": "^2.4.1", + "chalk": "^2.4.2", + "logkitty": "^0.5.0", + "slash": "^2.0.0", + "xmldoc": "^0.4.0" + }, + "files": [ + "build", + "native_modules.gradle" + ] +} diff --git a/packages/platform-android/src/commands/index.js b/packages/platform-android/src/commands/index.js new file mode 100644 index 0000000000..01ef421d53 --- /dev/null +++ b/packages/platform-android/src/commands/index.js @@ -0,0 +1,7 @@ +/** + * @flow + */ +import logAndroid from './logAndroid'; +import runAndroid from './runAndroid'; + +export default [logAndroid, runAndroid]; diff --git a/packages/platform-android/src/commands/logAndroid/index.js b/packages/platform-android/src/commands/logAndroid/index.js new file mode 100644 index 0000000000..6ae7c99142 --- /dev/null +++ b/packages/platform-android/src/commands/logAndroid/index.js @@ -0,0 +1,39 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { + logkitty, + makeTagsFilter, + formatEntry, + formatError, + AndroidPriority, +} from 'logkitty'; +import {logger} from '@react-native-community/cli-tools'; + +async function logAndroid() { + logger.info('Starting logkitty'); + + const emitter = logkitty({ + platform: 'android', + minPriority: AndroidPriority.VERBOSE, + filter: makeTagsFilter('ReactNative', 'ReactNativeJS'), + }); + + emitter.on('entry', entry => { + logger.log(formatEntry(entry)); + }); + + emitter.on('error', error => { + logger.log(formatError(error)); + }); +} + +export default { + name: 'log-android', + description: 'starts logkitty', + func: logAndroid, +}; diff --git a/packages/cli/src/commands/runAndroid/__tests__/runOnAllDevices.test.js b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js similarity index 55% rename from packages/cli/src/commands/runAndroid/__tests__/runOnAllDevices.test.js rename to packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js index b09559d68c..86cd9948b4 100644 --- a/packages/cli/src/commands/runAndroid/__tests__/runOnAllDevices.test.js +++ b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js @@ -14,15 +14,17 @@ jest.mock('child_process', () => ({ })); jest.mock('../getAdbPath'); -const { execFileSync } = require('child_process'); +const {execFileSync} = require('child_process'); describe('--appFolder', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('uses installDebug as default if no arguments', () => { - runOnAllDevices({}); + it('uses task "install[Variant]" as default task', () => { + runOnAllDevices({ + variant: 'debug', + }); expect(execFileSync.mock.calls[0][1]).toContain('installDebug'); }); @@ -30,59 +32,51 @@ describe('--appFolder', () => { it('uses appFolder and default variant', () => { runOnAllDevices({ appFolder: 'someApp', + variant: 'debug', }); expect(execFileSync.mock.calls[0][1]).toContain('someApp:installDebug'); }); - it('uses appFolder and variant', () => { - runOnAllDevices({ - appFolder: 'app', - variant: 'debug', - }); - - expect(execFileSync.mock.calls[0][1]).toContain('app:installDebug'); - - runOnAllDevices({ - appFolder: 'anotherApp', - variant: 'debug', - }); - - expect(execFileSync.mock.calls[1][1]).toContain('anotherApp:installDebug'); - + it('uses appFolder and custom variant', () => { runOnAllDevices({ appFolder: 'anotherApp', variant: 'staging', }); - expect(execFileSync.mock.calls[2][1]).toContain( - 'anotherApp:installStaging' + expect(execFileSync.mock.calls[0][1]).toContain( + 'anotherApp:installStaging', ); }); - it('uses appFolder and flavor', () => { + it('uses only task argument', () => { runOnAllDevices({ - appFolder: 'app', - flavor: 'someFlavor', + tasks: ['someTask'], + variant: 'debug', }); - expect(execFileSync.mock.calls[0][1]).toContain('app:installSomeFlavor'); + expect(execFileSync.mock.calls[0][1]).toContain('someTask'); }); - it('uses only installDebug argument', () => { + it('uses appFolder and custom task argument', () => { runOnAllDevices({ - installDebug: 'someCommand', + appFolder: 'anotherApp', + tasks: ['someTask'], + variant: 'debug', }); - expect(execFileSync.mock.calls[0][1]).toContain('someCommand'); + expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someTask'); }); - it('uses appFolder and custom installDebug argument', () => { + it('uses multiple tasks', () => { runOnAllDevices({ - appFolder: 'anotherApp', - installDebug: 'someCommand', + appFolder: 'app', + tasks: ['clean', 'someTask'], }); - expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someCommand'); + expect(execFileSync.mock.calls[0][1]).toContain( + 'app:clean', + 'app:someTask', + ); }); }); diff --git a/packages/cli/src/commands/runAndroid/adb.js b/packages/platform-android/src/commands/runAndroid/adb.js similarity index 89% rename from packages/cli/src/commands/runAndroid/adb.js rename to packages/platform-android/src/commands/runAndroid/adb.js index b93d8f98ff..c67f467c6c 100644 --- a/packages/cli/src/commands/runAndroid/adb.js +++ b/packages/platform-android/src/commands/runAndroid/adb.js @@ -8,7 +8,7 @@ * @flow */ -import { execSync, execFileSync } from 'child_process'; +import {execSync, execFileSync} from 'child_process'; /** * Parses the output of the 'adb devices' command @@ -52,14 +52,14 @@ function getAvailableCPUs(adbPath: string, device: string): Array { let cpus = execFileSync( adbPath, - baseArgs.concat(['ro.product.cpu.abilist']) + baseArgs.concat(['ro.product.cpu.abilist']), ).toString(); // pre-Lollipop if (!cpus || cpus.trim().length === 0) { cpus = execFileSync( adbPath, - baseArgs.concat(['ro.product.cpu.abi']) + baseArgs.concat(['ro.product.cpu.abi']), ).toString(); } @@ -70,7 +70,6 @@ function getAvailableCPUs(adbPath: string, device: string): Array { } export default { - parseDevicesResult, getDevices, getAvailableCPUs, }; diff --git a/packages/cli/src/commands/runAndroid/getAdbPath.js b/packages/platform-android/src/commands/runAndroid/getAdbPath.js similarity index 100% rename from packages/cli/src/commands/runAndroid/getAdbPath.js rename to packages/platform-android/src/commands/runAndroid/getAdbPath.js diff --git a/packages/cli/src/commands/runAndroid/runAndroid.js b/packages/platform-android/src/commands/runAndroid/index.js similarity index 67% rename from packages/cli/src/commands/runAndroid/runAndroid.js rename to packages/platform-android/src/commands/runAndroid/index.js index a075afe061..887fda6a13 100644 --- a/packages/cli/src/commands/runAndroid/runAndroid.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -7,40 +7,57 @@ * @flow */ -/* eslint-disable consistent-return */ - import path from 'path'; -import { spawnSync, spawn, execFileSync } from 'child_process'; +import {spawnSync, spawn, execFileSync} from 'child_process'; 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 'types'; import adb from './adb'; import runOnAllDevices from './runOnAllDevices'; import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import getAdbPath from './getAdbPath'; -import logger from '../../tools/logger'; +import { + isPackagerRunning, + logger, + getDefaultUserTerminal, + CLIError, +} from '@react-native-community/cli-tools'; +import warnAboutManuallyLinkedLibs from '../../link/warnAboutManuallyLinkedLibs'; // Verifies this is an Android project function checkAndroid(root) { return fs.existsSync(path.join(root, 'android/gradlew')); } +export type FlagsT = {| + tasks?: Array, + root: string, + variant: string, + appFolder: string, + appId: string, + appIdSuffix: string, + mainActivity: string, + deviceId?: string, + packager: boolean, + port: number, + terminal: string, +|}; + /** * Starts the app on a connected Android emulator or device. */ -// eslint-disable-next-line flowtype/no-weak-types -function runAndroid(argv: Array, ctx: ContextT, args: Object) { +function runAndroid(argv: Array, config: ConfigT, args: FlagsT) { if (!checkAndroid(args.root)) { logger.error( - 'Android project not found. Are you sure this is a React Native project?' + 'Android project not found. Are you sure this is a React Native project?', ); return; } + warnAboutManuallyLinkedLibs(config); + if (!args.packager) { return buildAndRun(args); } @@ -53,7 +70,7 @@ function runAndroid(argv: Array, ctx: ContextT, args: Object) { } else { // result == 'not_running' logger.info('Starting JS server...'); - startServerInNewWindow(args.port, args.terminal, ctx.reactNativePath); + startServerInNewWindow(args.port, args.terminal, config.reactNativePath); } return buildAndRun(args); }); @@ -76,7 +93,7 @@ function buildAndRun(args) { const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew'; // "app" is usually the default value for Android apps with only 1 app - const { appFolder } = args; + const {appFolder} = args; const packageName = fs .readFileSync(`${appFolder}/src/main/AndroidManifest.xml`, 'utf8') // $FlowFixMe @@ -85,28 +102,25 @@ function buildAndRun(args) { const packageNameWithSuffix = getPackageNameWithSuffix( args.appId, args.appIdSuffix, - packageName + packageName, ); const adbPath = getAdbPath(); if (args.deviceId) { - if (isString(args.deviceId)) { - return runOnSpecificDevice( - args, - cmd, - packageNameWithSuffix, - packageName, - adbPath - ); - } - logger.error('Argument missing for parameter --deviceId'); + return runOnSpecificDevice( + args, + cmd, + packageNameWithSuffix, + packageName, + adbPath, + ); } else { return runOnAllDevices( args, cmd, packageNameWithSuffix, packageName, - adbPath + adbPath, ); } } @@ -116,25 +130,24 @@ function runOnSpecificDevice( gradlew, packageNameWithSuffix, packageName, - adbPath + adbPath, ) { const devices = adb.getDevices(adbPath); - if (devices && devices.length > 0) { - if (devices.indexOf(args.deviceId) !== -1) { + const {deviceId} = args; + if (devices.length > 0 && deviceId) { + if (devices.indexOf(deviceId) !== -1) { buildApk(gradlew); installAndLaunchOnDevice( args, - args.deviceId, + deviceId, packageNameWithSuffix, packageName, - adbPath + adbPath, ); } else { logger.error( - `Could not find device with the id: "${ - args.deviceId - }". Choose one of the following:`, - ...devices + `Could not find device with the id: "${deviceId}". Please choose one of the following:`, + ...devices, ); } } else { @@ -144,21 +157,20 @@ function runOnSpecificDevice( function buildApk(gradlew) { try { - logger.info('Building the app...'); - // using '-x lint' in order to ignore linting errors while building the apk - execFileSync(gradlew, ['build', '-x', 'lint'], { - stdio: [process.stdin, process.stdout, process.stderr], - }); - } catch (e) { - logger.error('Could not build the app, read the error above for details.'); + const gradleArgs = ['build', '-x', 'lint']; + logger.info('Building the app...'); + logger.debug(`Running command "${gradlew} ${gradleArgs.join(' ')}"`); + execFileSync(gradlew, gradleArgs, {stdio: 'inherit'}); + } catch (error) { + throw new CLIError('Failed to build the app.', error); } } function tryInstallAppOnDevice(args, adbPath, device) { try { // "app" is usually the default value for Android apps with only 1 app - const { appFolder } = args; + const {appFolder} = args; const variant = args.variant.toLowerCase(); const buildDirectory = `${appFolder}/build/outputs/apk/${variant}`; const apkFile = getInstallApkName( @@ -166,23 +178,18 @@ function tryInstallAppOnDevice(args, adbPath, device) { adbPath, variant, device, - buildDirectory + buildDirectory, ); const pathToApk = `${buildDirectory}/${apkFile}`; - const adbArgs = ['-s', device, 'install', pathToApk]; - logger.info( - `Installing the app on the device (cd android && adb -s ${device} install ${pathToApk}` - ); - execFileSync(adbPath, adbArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); - } catch (e) { - logger.error( - `${ - e.message - }\nCould not install the app on the device, read the error above for details.` + const adbArgs = ['-s', device, 'install', '-r', '-d', pathToApk]; + logger.info(`Installing the app on the device "${device}"...`); + logger.debug( + `Running command "cd android && adb -s ${device} install -r -d ${pathToApk}"`, ); + execFileSync(adbPath, adbArgs, {stdio: 'inherit'}); + } catch (error) { + throw new CLIError('Failed to install the app on the device.', error); } } @@ -191,7 +198,7 @@ function getInstallApkName( adbPath, variant, device, - buildDirectory + buildDirectory, ) { const availableCPUs = adb.getAvailableCPUs(adbPath, device); @@ -217,7 +224,7 @@ function installAndLaunchOnDevice( selectedDevice, packageNameWithSuffix, packageName, - adbPath + adbPath, ) { tryRunAdbReverse(args.port, selectedDevice); tryInstallAppOnDevice(args, adbPath, selectedDevice); @@ -226,15 +233,11 @@ function installAndLaunchOnDevice( packageNameWithSuffix, packageName, adbPath, - args.mainActivity + args.mainActivity, ); } -function startServerInNewWindow( - port, - terminal = process.env.REACT_TERMINAL, - reactNativePath -) { +function startServerInNewWindow(port, terminal, reactNativePath) { /** * Set up OS-specific filenames and commands */ @@ -247,12 +250,30 @@ function startServerInNewWindow( ? `set RCT_METRO_PORT=${port}` : `export RCT_METRO_PORT=${port}`; + /** + * Quick & temporary fix for packager crashing on Windows due to using removed --projectRoot flag + * in script. So we just replace the contents of the script with the fixed version. This should be + * removed when PR #25517 on RN Repo gets approved and a new RN version is released. + */ + const launchPackagerScriptContent = `:: Copyright (c) Facebook, Inc. and its affiliates. + :: + :: This source code is licensed under the MIT license found in the + :: LICENSE file in the root directory of this source tree. + + @echo off + title Metro Bundler + call .packager.bat + cd ../../../ + node "%~dp0..\\cli.js" start + pause + exit`; + /** * Set up the `.packager.(env|bat)` file to ensure the packager starts on the right port. */ const launchPackagerScript = path.join( reactNativePath, - `scripts/${scriptFile}` + `scripts/${scriptFile}`, ); /** @@ -261,8 +282,7 @@ function startServerInNewWindow( */ const scriptsDir = path.dirname(launchPackagerScript); const packagerEnvFile = path.join(scriptsDir, packagerEnvFilename); - // eslint-disable-next-line flowtype/no-weak-types - const procConfig: Object = { cwd: scriptsDir }; + const procConfig: Object = {cwd: scriptsDir}; /** * Ensure we overwrite file by passing the `w` flag @@ -277,7 +297,7 @@ function startServerInNewWindow( return spawnSync( 'open', ['-a', terminal, launchPackagerScript], - procConfig + procConfig, ); } return spawnSync('open', [launchPackagerScript], procConfig); @@ -294,10 +314,15 @@ function startServerInNewWindow( if (/^win/.test(process.platform)) { procConfig.detached = true; procConfig.stdio = 'ignore'; + //Temporary fix for #484. See comment on line 254 + fs.writeFileSync(launchPackagerScript, launchPackagerScriptContent, { + encoding: 'utf8', + flag: 'w', + }); return spawn('cmd.exe', ['/C', launchPackagerScript], procConfig); } logger.error( - `Cannot start the packager. Unknown platform ${process.platform}` + `Cannot start the packager. Unknown platform ${process.platform}`, ); } @@ -308,63 +333,62 @@ export default { func: runAndroid, options: [ { - command: '--install-debug', - }, - { - command: '--root [string]', + name: '--root [string]', description: 'Override the root directory for the android build (which contains the android directory)', default: '', }, { - command: '--flavor [string]', - description: '--flavor has been deprecated. Use --variant instead', - }, - { - command: '--variant [string]', + name: '--variant [string]', + description: "Specify your app's build variant", default: 'debug', }, { - command: '--appFolder [string]', + name: '--appFolder [string]', description: 'Specify a different application folder name for the android source. If not, we assume is "app"', default: 'app', }, { - command: '--appId [string]', + name: '--appId [string]', description: 'Specify an applicationId to launch after build.', default: '', }, { - command: '--appIdSuffix [string]', + name: '--appIdSuffix [string]', description: 'Specify an applicationIdSuffix to launch after build.', default: '', }, { - command: '--main-activity [string]', + name: '--main-activity [string]', description: 'Name of the activity to start', default: 'MainActivity', }, { - command: '--deviceId [string]', + name: '--deviceId [string]', description: 'builds your app and starts it on a specific device/simulator with the ' + 'given device id (listed by running "adb devices" on the command line).', }, { - command: '--no-packager', + name: '--no-packager', description: 'Do not launch packager while building', }, { - command: '--port [number]', + name: '--port [number]', default: process.env.RCT_METRO_PORT || 8081, parse: (val: string) => Number(val), }, { - command: '--terminal [string]', + name: '--terminal [string]', description: 'Launches the Metro Bundler in a new window using the specified terminal path.', - default: '', + default: getDefaultUserTerminal, + }, + { + name: '--tasks [list]', + description: 'Run custom Gradle tasks. By default it\'s "installDebug"', + parse: (val: string) => val.split(','), }, ], }; diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js new file mode 100644 index 0000000000..164296f640 --- /dev/null +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import chalk from 'chalk'; +import {execFileSync} from 'child_process'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import adb from './adb'; +import tryRunAdbReverse from './tryRunAdbReverse'; +import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; +import type {FlagsT} from '.'; + +function getTaskNames( + appFolder: string, + commands: Array, +): Array { + return appFolder + ? commands.map(command => `${appFolder}:${command}`) + : commands; +} + +function toPascalCase(value: string) { + return value[0].toUpperCase() + value.slice(1); +} + +function runOnAllDevices( + args: FlagsT, + cmd: string, + packageNameWithSuffix: string, + packageName: string, + adbPath: string, +) { + try { + const tasks = args.tasks || ['install' + toPascalCase(args.variant)]; + const gradleArgs = getTaskNames(args.appFolder, tasks); + + if (args.port != null) { + gradleArgs.push('-PreactNativeDevServerPort=' + args.port); + } + + logger.info('Installing the app...'); + logger.debug( + `Running command "cd android && ${cmd} ${gradleArgs.join(' ')}"`, + ); + + execFileSync(cmd, gradleArgs, {stdio: ['inherit', 'inherit', 'pipe']}); + } catch (error) { + throw createInstallError(error); + } + const devices = adb.getDevices(adbPath); + + (devices.length > 0 ? devices : [undefined]).forEach(device => { + tryRunAdbReverse(args.port, device); + tryLaunchAppOnDevice( + device, + packageNameWithSuffix, + packageName, + adbPath, + args.mainActivity, + ); + }); +} + +function createInstallError(error) { + const stderr = (error.stderr || '').toString(); + const docs = + 'https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment'; + let message = `Make sure you have the Android development environment set up: ${chalk.underline.dim( + docs, + )}`; + + // Pass the error message from the command to stdout because we pipe it to + // parent process so it's not visible + logger.log(stderr); + + // Handle some common failures and make the errors more helpful + if (stderr.includes('No connected devices')) { + message = + 'Make sure you have an Android emulator running or a device connected'; + } else if ( + stderr.includes('licences have not been accepted') || + stderr.includes('accept the SDK license') + ) { + message = `Please accept all necessary SDK licenses using SDK Manager: "${chalk.bold( + '$ANDROID_HOME/tools/bin/sdkmanager --licenses', + )}"`; + } + + return new CLIError(`Failed to install the app. ${message}.`, error); +} + +export default runOnAllDevices; diff --git a/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js b/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js new file mode 100644 index 0000000000..4fd39fbec2 --- /dev/null +++ b/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import {spawnSync} from 'child_process'; +import {logger, CLIError} from '@react-native-community/cli-tools'; + +function tryLaunchAppOnDevice( + device?: string, + packageNameWithSuffix: string, + packageName: string, + adbPath: string, + mainActivity: string, +) { + try { + const adbArgs = [ + 'shell', + 'am', + 'start', + '-n', + `${packageNameWithSuffix}/${packageName}.${mainActivity}`, + ]; + if (device) { + adbArgs.unshift('-s', device); + logger.info(`Starting the app on "${device}"...`); + } else { + logger.info('Starting the app...'); + } + logger.debug(`Running command "${adbPath} ${adbArgs.join(' ')}"`); + spawnSync(adbPath, adbArgs, {stdio: 'inherit'}); + } catch (error) { + throw new CLIError('Failed to start the app.', error); + } +} + +export default tryLaunchAppOnDevice; diff --git a/packages/cli/src/commands/runAndroid/tryRunAdbReverse.js b/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js similarity index 56% rename from packages/cli/src/commands/runAndroid/tryRunAdbReverse.js rename to packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js index 952e7e885d..ffb021540e 100644 --- a/packages/cli/src/commands/runAndroid/tryRunAdbReverse.js +++ b/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js @@ -7,12 +7,12 @@ * @flow */ -import { execFileSync } from 'child_process'; -import logger from '../../tools/logger'; +import {execFileSync} from 'child_process'; +import {logger} from '@react-native-community/cli-tools'; import getAdbPath from './getAdbPath'; // Runs ADB reverse tcp:8081 tcp:8081 to allow loading the jsbundle from the packager -function tryRunAdbReverse(packagerPort: number | string, device: string) { +function tryRunAdbReverse(packagerPort: number | string, device?: string) { try { const adbPath = getAdbPath(); const adbArgs = ['reverse', `tcp:${packagerPort}`, `tcp:${packagerPort}`]; @@ -22,13 +22,16 @@ function tryRunAdbReverse(packagerPort: number | string, device: string) { adbArgs.unshift('-s', device); } - logger.info(`Running ${adbPath} ${adbArgs.join(' ')}`); + logger.info('Connecting to the development server...'); + logger.debug(`Running command "${adbPath} ${adbArgs.join(' ')}"`); - execFileSync(adbPath, adbArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); + execFileSync(adbPath, adbArgs, {stdio: 'inherit'}); } catch (e) { - logger.info(`Could not run adb reverse: ${e.message}`); + logger.warn( + `Failed to connect to development server using "adb reverse": ${ + e.message + }`, + ); } } diff --git a/packages/cli/src/tools/__fixtures__/android.js b/packages/platform-android/src/config/__fixtures__/android.js similarity index 91% rename from packages/cli/src/tools/__fixtures__/android.js rename to packages/platform-android/src/config/__fixtures__/android.js index d6097b0bfa..d5f603069f 100644 --- a/packages/cli/src/tools/__fixtures__/android.js +++ b/packages/platform-android/src/config/__fixtures__/android.js @@ -11,10 +11,10 @@ const fs = jest.requireActual('fs'); const path = jest.requireActual('path'); const manifest = fs.readFileSync( - path.join(__dirname, './files/AndroidManifest.xml') + path.join(__dirname, './files/AndroidManifest.xml'), ); const mainJavaClass = fs.readFileSync( - path.join(__dirname, './files/Main.java') + path.join(__dirname, './files/Main.java'), ); function generateValidFileStructure(classFileName) { @@ -27,7 +27,7 @@ function generateValidFileStructure(classFileName) { example: { 'Main.java': mainJavaClass, [classFileName]: fs.readFileSync( - path.join(__dirname, `./files/${classFileName}`) + path.join(__dirname, `./files/${classFileName}`), ), }, }, @@ -50,7 +50,7 @@ exports.userConfigManifest = { example: { 'Main.java': mainJavaClass, 'ReactPackage.java': fs.readFileSync( - path.join(__dirname, './files/ReactPackage.java') + path.join(__dirname, './files/ReactPackage.java'), ), }, }, @@ -58,7 +58,7 @@ exports.userConfigManifest = { }, debug: { 'AndroidManifest.xml': fs.readFileSync( - path.join(__dirname, './files/AndroidManifest-debug.xml') + path.join(__dirname, './files/AndroidManifest-debug.xml'), ), }, }, diff --git a/packages/cli/src/tools/__fixtures__/files/AndroidManifest-debug.xml b/packages/platform-android/src/config/__fixtures__/files/AndroidManifest-debug.xml similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/AndroidManifest-debug.xml rename to packages/platform-android/src/config/__fixtures__/files/AndroidManifest-debug.xml diff --git a/packages/cli/src/tools/__fixtures__/files/AndroidManifest.xml b/packages/platform-android/src/config/__fixtures__/files/AndroidManifest.xml similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/AndroidManifest.xml rename to packages/platform-android/src/config/__fixtures__/files/AndroidManifest.xml diff --git a/packages/cli/src/tools/__fixtures__/files/Main.java b/packages/platform-android/src/config/__fixtures__/files/Main.java similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/Main.java rename to packages/platform-android/src/config/__fixtures__/files/Main.java diff --git a/packages/cli/src/tools/__fixtures__/files/ReactPackage.java b/packages/platform-android/src/config/__fixtures__/files/ReactPackage.java similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/ReactPackage.java rename to packages/platform-android/src/config/__fixtures__/files/ReactPackage.java diff --git a/packages/cli/src/tools/__fixtures__/files/ReactPackage.kt b/packages/platform-android/src/config/__fixtures__/files/ReactPackage.kt similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/ReactPackage.kt rename to packages/platform-android/src/config/__fixtures__/files/ReactPackage.kt diff --git a/packages/cli/src/tools/__fixtures__/files/package.json b/packages/platform-android/src/config/__fixtures__/files/package.json similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/package.json rename to packages/platform-android/src/config/__fixtures__/files/package.json diff --git a/packages/cli/src/tools/__fixtures__/files/project.pbxproj b/packages/platform-android/src/config/__fixtures__/files/project.pbxproj similarity index 100% rename from packages/cli/src/tools/__fixtures__/files/project.pbxproj rename to packages/platform-android/src/config/__fixtures__/files/project.pbxproj diff --git a/packages/platform-android/src/config/__fixtures__/projects.js b/packages/platform-android/src/config/__fixtures__/projects.js new file mode 100644 index 0000000000..646a77c9bd --- /dev/null +++ b/packages/platform-android/src/config/__fixtures__/projects.js @@ -0,0 +1,16 @@ +import android from './android'; + +export const flat = { + android: android.valid, +}; + +export const nested = { + android: { + app: android.valid, + }, +}; + +export const withExamples = { + Examples: flat, + android: android.valid, +}; diff --git a/packages/cli/src/tools/__tests__/android/findAndroidAppFolder-test.js b/packages/platform-android/src/config/__tests__/findAndroidAppFolder-test.js similarity index 88% rename from packages/cli/src/tools/__tests__/android/findAndroidAppFolder-test.js rename to packages/platform-android/src/config/__tests__/findAndroidAppFolder-test.js index 866350e139..1c6ebb3e47 100644 --- a/packages/cli/src/tools/__tests__/android/findAndroidAppFolder-test.js +++ b/packages/platform-android/src/config/__tests__/findAndroidAppFolder-test.js @@ -8,8 +8,8 @@ * @emails oncall+javascript_foundation */ -import findAndroidAppFolder from '../../android/findAndroidAppFolder'; -import mocks from '../../__fixtures__/android'; +import findAndroidAppFolder from '../findAndroidAppFolder'; +import mocks from '../__fixtures__/android'; jest.mock('path'); jest.mock('fs'); diff --git a/packages/cli/src/tools/__tests__/android/findManifest-test.js b/packages/platform-android/src/config/__tests__/findManifest-test.js similarity index 87% rename from packages/cli/src/tools/__tests__/android/findManifest-test.js rename to packages/platform-android/src/config/__tests__/findManifest-test.js index 74259e833a..88c3803d8e 100644 --- a/packages/cli/src/tools/__tests__/android/findManifest-test.js +++ b/packages/platform-android/src/config/__tests__/findManifest-test.js @@ -8,8 +8,8 @@ * @emails oncall+javascript_foundation */ -import findManifest from '../../android/findManifest'; -import mocks from '../../__fixtures__/android'; +import findManifest from '../findManifest'; +import mocks from '../__fixtures__/android'; jest.mock('path'); jest.mock('fs'); diff --git a/packages/cli/src/tools/__tests__/android/findPackageClassName-test.js b/packages/platform-android/src/config/__tests__/findPackageClassName-test.js similarity index 86% rename from packages/cli/src/tools/__tests__/android/findPackageClassName-test.js rename to packages/platform-android/src/config/__tests__/findPackageClassName-test.js index a2ddc80ac7..f12b6c555a 100644 --- a/packages/cli/src/tools/__tests__/android/findPackageClassName-test.js +++ b/packages/platform-android/src/config/__tests__/findPackageClassName-test.js @@ -8,8 +8,8 @@ * @emails oncall+javascript_foundation */ -import mocks from '../../__fixtures__/android'; -import findPackageClassName from '../../android/findPackageClassName'; +import mocks from '../__fixtures__/android'; +import findPackageClassName from '../findPackageClassName'; jest.mock('path'); jest.mock('fs'); @@ -30,7 +30,7 @@ const fs = require('fs'); android: mocks.validKotlin, }, }, - platform + platform, ); }); @@ -40,13 +40,13 @@ const fs = require('fs'); it('returns the name of the java class implementing ReactPackage', () => { expect(findPackageClassName(`${root}flatJava`)).toBe( - 'SomeExampleJavaPackage' + 'SomeExampleJavaPackage', ); }); it('returns the name of the kotlin class implementing ReactPackage', () => { expect(findPackageClassName(`${root}flatKotlin`)).toBe( - 'SomeExampleKotlinPackage' + 'SomeExampleKotlinPackage', ); }); diff --git a/packages/cli/src/tools/__tests__/android/getDependencyConfig-test.js b/packages/platform-android/src/config/__tests__/getDependencyConfig-test.js similarity index 92% rename from packages/cli/src/tools/__tests__/android/getDependencyConfig-test.js rename to packages/platform-android/src/config/__tests__/getDependencyConfig-test.js index a11c731698..e0eb79d3d7 100644 --- a/packages/cli/src/tools/__tests__/android/getDependencyConfig-test.js +++ b/packages/platform-android/src/config/__tests__/getDependencyConfig-test.js @@ -8,14 +8,14 @@ * @emails oncall+javascript_foundation */ -import mocks from '../../__fixtures__/android'; +import mocks from '../__fixtures__/android'; jest.mock('path'); jest.mock('fs'); const fs = require('fs'); -const getDependencyConfig = require('../../android').dependencyConfig; +const getDependencyConfig = require('../').dependencyConfig; const userConfig = {}; diff --git a/packages/cli/src/tools/__tests__/android/getProjectConfig-test.js b/packages/platform-android/src/config/__tests__/getProjectConfig-test.js similarity index 95% rename from packages/cli/src/tools/__tests__/android/getProjectConfig-test.js rename to packages/platform-android/src/config/__tests__/getProjectConfig-test.js index 6061498eb5..5dae615c6a 100644 --- a/packages/cli/src/tools/__tests__/android/getProjectConfig-test.js +++ b/packages/platform-android/src/config/__tests__/getProjectConfig-test.js @@ -8,14 +8,14 @@ * @emails oncall+javascript_foundation */ -import mocks from '../../__fixtures__/android'; +import mocks from '../__fixtures__/android'; jest.mock('path'); jest.mock('fs'); const fs = require('fs'); -const getProjectConfig = require('../../android').projectConfig; +const getProjectConfig = require('../').projectConfig; describe('android::getProjectConfig', () => { beforeAll(() => { diff --git a/packages/cli/src/tools/__tests__/android/readManifest-test.js b/packages/platform-android/src/config/__tests__/readManifest-test.js similarity index 85% rename from packages/cli/src/tools/__tests__/android/readManifest-test.js rename to packages/platform-android/src/config/__tests__/readManifest-test.js index 58c00d9e09..5aaa7dea35 100644 --- a/packages/cli/src/tools/__tests__/android/readManifest-test.js +++ b/packages/platform-android/src/config/__tests__/readManifest-test.js @@ -8,9 +8,9 @@ * @emails oncall+javascript_foundation */ -import findManifest from '../../android/findManifest'; -import readManifest from '../../android/readManifest'; -import mocks from '../../__fixtures__/android'; +import findManifest from '../findManifest'; +import readManifest from '../readManifest'; +import mocks from '../__fixtures__/android'; jest.mock('path'); jest.mock('fs'); diff --git a/packages/cli/src/tools/android/findAndroidAppFolder.js b/packages/platform-android/src/config/findAndroidAppFolder.js similarity index 100% rename from packages/cli/src/tools/android/findAndroidAppFolder.js rename to packages/platform-android/src/config/findAndroidAppFolder.js diff --git a/packages/cli/src/tools/android/findManifest.js b/packages/platform-android/src/config/findManifest.js similarity index 100% rename from packages/cli/src/tools/android/findManifest.js rename to packages/platform-android/src/config/findManifest.js diff --git a/packages/cli/src/tools/android/findPackageClassName.js b/packages/platform-android/src/config/findPackageClassName.js similarity index 92% rename from packages/cli/src/tools/android/findPackageClassName.js rename to packages/platform-android/src/config/findPackageClassName.js index 76ca9cf6ca..eaac9631d5 100644 --- a/packages/cli/src/tools/android/findPackageClassName.js +++ b/packages/platform-android/src/config/findPackageClassName.js @@ -18,7 +18,7 @@ import path from 'path'; * @param {String} folder Folder to find java/kt files */ export default function getPackageClassName(folder) { - const files = glob.sync('**/+(*.java|*.kt)', { cwd: folder }); + const files = glob.sync('**/+(*.java|*.kt)', {cwd: folder}); const packages = files .map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8')) diff --git a/packages/cli/src/tools/android/index.js b/packages/platform-android/src/config/index.js similarity index 86% rename from packages/cli/src/tools/android/index.js rename to packages/platform-android/src/config/index.js index 631c8b80ab..78ab2f682e 100644 --- a/packages/cli/src/tools/android/index.js +++ b/packages/platform-android/src/config/index.js @@ -12,9 +12,6 @@ import findAndroidAppFolder from './findAndroidAppFolder'; import findManifest from './findManifest'; import findPackageClassName from './findPackageClassName'; import readManifest from './readManifest'; -import linkConfigAndroid from '../../commands/link/android'; - -export const linkConfig = linkConfigAndroid; const getPackageName = manifest => manifest.attr.package; @@ -53,28 +50,28 @@ export function projectConfig(folder, userConfig = {}) { const mainFilePath = path.join( sourceDir, userConfig.mainFilePath || - `src/main/java/${packageFolder}/MainApplication.java` + `src/main/java/${packageFolder}/MainApplication.java`, ); const stringsPath = path.join( sourceDir, - userConfig.stringsPath || 'src/main/res/values/strings.xml' + userConfig.stringsPath || 'src/main/res/values/strings.xml', ); const settingsGradlePath = path.join( folder, 'android', - userConfig.settingsGradlePath || 'settings.gradle' + userConfig.settingsGradlePath || 'settings.gradle', ); const assetsPath = path.join( sourceDir, - userConfig.assetsPath || 'src/main/assets' + userConfig.assetsPath || 'src/main/assets', ); const buildGradlePath = path.join( sourceDir, - userConfig.buildGradlePath || 'build.gradle' + userConfig.buildGradlePath || 'build.gradle', ); return { @@ -87,6 +84,7 @@ export function projectConfig(folder, userConfig = {}) { settingsGradlePath, assetsPath, mainFilePath, + packageName, }; } @@ -128,5 +126,5 @@ export function dependencyConfig(folder, userConfig = {}) { const packageInstance = userConfig.packageInstance || `new ${packageClassName}()`; - return { sourceDir, folder, manifest, packageImportPath, packageInstance }; + return {sourceDir, folder, packageImportPath, packageInstance}; } diff --git a/packages/cli/src/tools/android/readManifest.js b/packages/platform-android/src/config/readManifest.js similarity index 100% rename from packages/cli/src/tools/android/readManifest.js rename to packages/platform-android/src/config/readManifest.js diff --git a/packages/platform-android/src/index.js b/packages/platform-android/src/index.js new file mode 100644 index 0000000000..d7cabc044c --- /dev/null +++ b/packages/platform-android/src/index.js @@ -0,0 +1,9 @@ +/** + * @flow + * + * Android platform files + */ + +export {default as linkConfig} from './link'; +export {default as commands} from './commands'; +export {projectConfig, dependencyConfig} from './config'; diff --git a/packages/cli/src/commands/link/__fixtures__/android/patchedBuild.gradle b/packages/platform-android/src/link/__fixtures__/patchedBuild.gradle similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/android/patchedBuild.gradle rename to packages/platform-android/src/link/__fixtures__/patchedBuild.gradle diff --git a/packages/cli/src/commands/link/__tests__/android/isInstalled-test.js b/packages/platform-android/src/link/__tests__/isInstalled-test.js similarity index 84% rename from packages/cli/src/commands/link/__tests__/android/isInstalled-test.js rename to packages/platform-android/src/link/__tests__/isInstalled-test.js index fac2114d7e..f5ada2908d 100644 --- a/packages/cli/src/commands/link/__tests__/android/isInstalled-test.js +++ b/packages/platform-android/src/link/__tests__/isInstalled-test.js @@ -8,15 +8,12 @@ * @emails oncall+javascript_foundation */ -import isInstalled from '../../android/isInstalled'; +import isInstalled from '../isInstalled'; const path = require('path'); const projectConfig = { - buildGradlePath: path.join( - __dirname, - '../../__fixtures__/android/patchedBuild.gradle' - ), + buildGradlePath: path.join(__dirname, '../__fixtures__/patchedBuild.gradle'), }; describe('android::isInstalled', () => { @@ -37,6 +34,6 @@ describe('android::isInstalled', () => { 'properly detects if %p project is already in build.gradle', (project, isPresent) => { expect(isInstalled(projectConfig, project)).toBe(isPresent); - } + }, ); }); diff --git a/packages/platform-android/src/link/copyAssets.js b/packages/platform-android/src/link/copyAssets.js new file mode 100644 index 0000000000..dcc61e2d23 --- /dev/null +++ b/packages/platform-android/src/link/copyAssets.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import fs from 'fs-extra'; +import path from 'path'; +import {logger, groupFilesByType} from '@react-native-community/cli-tools'; + +/** + * Copies each file from an array of assets provided to targetPath directory + * + * For now, the only types of files that are handled are: + * - Fonts (otf, ttf) - copied to targetPath/fonts under original name + */ +export default function copyAssetsAndroid( + files: Array, + project: {assetsPath: string}, +) { + const assets = groupFilesByType(files); + + logger.debug(`Assets path: ${project.assetsPath}`); + (assets.font || []).forEach(asset => { + const fontsDir = path.join(project.assetsPath, 'fonts'); + logger.debug(`Copying asset ${asset}`); + // @todo: replace with fs.mkdirSync(path, {recursive}) + fs.copyFileSync + // and get rid of fs-extra once we move to Node 10 + fs.copySync(asset, path.join(fontsDir, path.basename(asset))); + }); +} diff --git a/packages/cli/src/commands/link/android/index.js b/packages/platform-android/src/link/index.js similarity index 85% rename from packages/cli/src/commands/link/android/index.js rename to packages/platform-android/src/link/index.js index 3114a8f901..26583d7ffb 100644 --- a/packages/cli/src/commands/link/android/index.js +++ b/packages/platform-android/src/link/index.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import isInstalled from './isInstalled'; @@ -14,7 +14,7 @@ import copyAssets from './copyAssets'; import unlinkAssets from './unlinkAssets'; export function getAndroidLinkConfig() { - return { isInstalled, register, unregister, copyAssets, unlinkAssets }; + return {isInstalled, register, unregister, copyAssets, unlinkAssets}; } export default getAndroidLinkConfig; diff --git a/packages/cli/src/commands/link/android/isInstalled.js b/packages/platform-android/src/link/isInstalled.js similarity index 100% rename from packages/cli/src/commands/link/android/isInstalled.js rename to packages/platform-android/src/link/isInstalled.js diff --git a/packages/cli/src/commands/link/__tests__/android/applyPatch-test.js b/packages/platform-android/src/link/patches/__tests__/applyPatch-test.js similarity index 62% rename from packages/cli/src/commands/link/__tests__/android/applyPatch-test.js rename to packages/platform-android/src/link/patches/__tests__/applyPatch-test.js index c298513ae8..55a5ec5a67 100644 --- a/packages/cli/src/commands/link/__tests__/android/applyPatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/applyPatch-test.js @@ -5,14 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -/* eslint-disable no-template-curly-in-string */ - -import applyParams from '../../android/patches/applyParams'; +import applyParams from '../applyParams'; describe('applyParams', () => { it('apply params to the string', () => { - expect(applyParams('${foo}', { foo: 'foo' }, 'react-native')).toEqual( - 'getResources().getString(R.string.reactNative_foo)' + expect(applyParams('${foo}', {foo: 'foo'}, 'react-native')).toEqual( + 'getResources().getString(R.string.reactNative_foo)', ); }); diff --git a/packages/cli/src/commands/link/__tests__/android/makeBuildPatch-test.js b/packages/platform-android/src/link/patches/__tests__/makeBuildPatch-test.js similarity index 51% rename from packages/cli/src/commands/link/__tests__/android/makeBuildPatch-test.js rename to packages/platform-android/src/link/patches/__tests__/makeBuildPatch-test.js index fc00ead440..4663e8e3b6 100644 --- a/packages/cli/src/commands/link/__tests__/android/makeBuildPatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/makeBuildPatch-test.js @@ -8,43 +8,65 @@ * @emails oncall+javascript_foundation */ -import makeBuildPatch from '../../android/patches/makeBuildPatch'; -import normalizeProjectName from '../../android/patches/normalizeProjectName'; +import makeBuildPatch from '../makeBuildPatch'; +import normalizeProjectName from '../normalizeProjectName'; +import path from 'path'; const name = 'test'; const scopedName = '@scoped/test'; const normalizedScopedName = normalizeProjectName('@scoped/test'); +const buildGradlePath = path.join( + __dirname, + '../../__fixtures__/patchedBuild.gradle', +); describe('makeBuildPatch', () => { it('should build a patch function', () => { expect(Object.prototype.toString(makeBuildPatch(name))).toBe( - '[object Object]' + '[object Object]', ); }); it('should make a correct patch', () => { - const { patch } = makeBuildPatch(name); + const {patch} = makeBuildPatch(name); expect(patch).toBe(` implementation project(':${name}')\n`); }); it('should make a correct install check pattern', () => { - const { installPattern } = makeBuildPatch(name); + const {installPattern} = makeBuildPatch(name); expect(installPattern.toString()).toEqual(expect.stringContaining(name)); }); + + test.each([ + ['test-impl', " implementation project(':test-impl')\n"], + ['test-compile', " compile project(':test-compile')\n"], + ['test-api', " api project(':test-api')\n"], + [ + 'test-not-there-yet', + " implementation project(':test-not-there-yet')\n", + ], + ])( + 'properly detects the patch string of project %p in build.gradle', + (project, projectPatchString) => { + expect(makeBuildPatch(project, buildGradlePath).patch).toBe( + projectPatchString, + ); + }, + ); }); describe('makeBuildPatchWithScopedPackage', () => { it('should make a correct patch', () => { - const { patch } = makeBuildPatch(scopedName); + const {patch} = makeBuildPatch(scopedName); expect(patch).toBe( - ` implementation project(':${normalizedScopedName}')\n` + ` implementation project(':${normalizedScopedName}')\n`, ); }); it('should make a correct install check pattern', () => { - const { installPattern } = makeBuildPatch(scopedName); + const {installPattern} = makeBuildPatch(scopedName); expect(installPattern.toString()).toEqual( - expect.stringContaining(normalizedScopedName) + expect.stringContaining(normalizedScopedName), ); }); }); diff --git a/packages/cli/src/commands/link/__tests__/android/makeImportPatch-test.js b/packages/platform-android/src/link/patches/__tests__/makeImportPatch-test.js similarity index 79% rename from packages/cli/src/commands/link/__tests__/android/makeImportPatch-test.js rename to packages/platform-android/src/link/patches/__tests__/makeImportPatch-test.js index 165230c415..fdbac34130 100644 --- a/packages/cli/src/commands/link/__tests__/android/makeImportPatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/makeImportPatch-test.js @@ -8,19 +8,19 @@ * @emails oncall+javascript_foundation */ -import makeImportPatch from '../../android/patches/makeImportPatch'; +import makeImportPatch from '../makeImportPatch'; const packageImportPath = 'import some.example.project'; describe('makeImportPatch', () => { it('should build a patch', () => { expect(Object.prototype.toString(makeImportPatch(packageImportPath))).toBe( - '[object Object]' + '[object Object]', ); }); it('MainActivity contains a correct import patch', () => { - const { patch } = makeImportPatch(packageImportPath); + const {patch} = makeImportPatch(packageImportPath); expect(patch).toBe(`\n${packageImportPath}`); }); diff --git a/packages/cli/src/commands/link/__tests__/android/makePackagePatch-test.js b/packages/platform-android/src/link/patches/__tests__/makePackagePatch-test.js similarity index 75% rename from packages/cli/src/commands/link/__tests__/android/makePackagePatch-test.js rename to packages/platform-android/src/link/patches/__tests__/makePackagePatch-test.js index 409f3894c9..681b19a2ba 100644 --- a/packages/cli/src/commands/link/__tests__/android/makePackagePatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/makePackagePatch-test.js @@ -5,10 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -/* eslint-disable no-template-curly-in-string */ - -import makePackagePatch from '../../android/patches/makePackagePatch'; -import applyParams from '../../android/patches/applyParams'; +import makePackagePatch from '../makePackagePatch'; +import applyParams from '../applyParams'; const packageInstance = "new SomeLibrary(${foo}, ${bar}, 'something')"; const name = 'some-library'; @@ -24,7 +22,7 @@ describe('makePackagePatch@0.20', () => { }); it('MainActivity contains a correct 0.20 import patch', () => { - const { patch } = makePackagePatch(packageInstance, params, name); + const {patch} = makePackagePatch(packageInstance, params, name); const processedInstance = applyParams(packageInstance, params, name); expect(patch).toBe(`,\n ${processedInstance}`); diff --git a/packages/cli/src/commands/link/__tests__/android/makeSettingsPatch-test.js b/packages/platform-android/src/link/patches/__tests__/makeSettingsPatch-test.js similarity index 79% rename from packages/cli/src/commands/link/__tests__/android/makeSettingsPatch-test.js rename to packages/platform-android/src/link/patches/__tests__/makeSettingsPatch-test.js index 429076827a..aa7cdd0146 100644 --- a/packages/cli/src/commands/link/__tests__/android/makeSettingsPatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/makeSettingsPatch-test.js @@ -7,7 +7,7 @@ * @flow */ -import makeSettingsPatch from '../../android/patches/makeSettingsPatch'; +import makeSettingsPatch from '../makeSettingsPatch'; const projectConfig = { sourceDir: '/home/project/android/app', @@ -22,7 +22,7 @@ describe('makeSettingsPatch with package "test"', () => { it('should build a patch function', () => { expect( - makeSettingsPatch(name, dependencyConfig, projectConfig) + makeSettingsPatch(name, dependencyConfig, projectConfig), ).toMatchObject({ pattern: '\n', patch: expect.any(String), @@ -30,7 +30,7 @@ describe('makeSettingsPatch with package "test"', () => { }); it('includes project with correct path', () => { - const { patch } = makeSettingsPatch(name, dependencyConfig, projectConfig); + const {patch} = makeSettingsPatch(name, dependencyConfig, projectConfig); expect(patch).toMatchInlineSnapshot(` "include ':test' @@ -41,7 +41,8 @@ project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/ // Simulate Windows environment on POSIX filesystem // TODO: scope this test to Windows-only once we setup CI on Windows - it('includes project with correct path on Windows', () => { + // as changing path to be windows-specific breaks global path mock + it.skip('includes project with correct path on Windows', () => { jest.resetModules(); jest.doMock('path', () => { const path = jest.requireActual('path'); @@ -50,8 +51,7 @@ project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/ return path; }); // eslint-disable-next-line no-shadow - const makeSettingsPatch = require('../../android/patches/makeSettingsPatch') - .default; + const makeSettingsPatch = require('../makeSettingsPatch').default; const projectConfigWindows = { sourceDir: 'C:\\home\\project\\android\\app', settingsGradlePath: 'C:\\home\\project\\android\\settings.gradle', @@ -59,10 +59,10 @@ project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/ const dependencyConfigWindows = { sourceDir: `C:\\home\\project\\node_modules\\${name}\\android`, }; - const { patch } = makeSettingsPatch( + const {patch} = makeSettingsPatch( name, dependencyConfigWindows, - projectConfigWindows + projectConfigWindows, ); jest.dontMock('path'); @@ -83,7 +83,7 @@ describe('makeSettingsPatch with scoped package "@scoped/test"', () => { it('should build a patch function', () => { expect( - makeSettingsPatch(name, dependencyConfig, projectConfig) + makeSettingsPatch(name, dependencyConfig, projectConfig), ).toMatchObject({ pattern: '\n', patch: expect.any(String), @@ -91,7 +91,7 @@ describe('makeSettingsPatch with scoped package "@scoped/test"', () => { }); it('includes project with correct path', () => { - const { patch } = makeSettingsPatch(name, dependencyConfig, projectConfig); + const {patch} = makeSettingsPatch(name, dependencyConfig, projectConfig); expect(patch).toMatchInlineSnapshot(` "include ':@scoped_test' diff --git a/packages/cli/src/commands/link/__tests__/android/makeStringsPatch-test.js b/packages/platform-android/src/link/patches/__tests__/makeStringsPatch-test.js similarity index 89% rename from packages/cli/src/commands/link/__tests__/android/makeStringsPatch-test.js rename to packages/platform-android/src/link/patches/__tests__/makeStringsPatch-test.js index 9b0c6ec16e..0186de375a 100644 --- a/packages/cli/src/commands/link/__tests__/android/makeStringsPatch-test.js +++ b/packages/platform-android/src/link/patches/__tests__/makeStringsPatch-test.js @@ -8,7 +8,7 @@ * @emails oncall+javascript_foundation */ -import makeStringsPatch from '../../android/patches/makeStringsPatch'; +import makeStringsPatch from '../makeStringsPatch'; describe('makeStringsPatch', () => { it('should export a patch with element', () => { @@ -17,7 +17,7 @@ describe('makeStringsPatch', () => { }; expect(makeStringsPatch(params, 'module').patch).toContain( - 'valueA' + 'valueA', ); }); diff --git a/packages/cli/src/commands/link/__tests__/android/normalizeProjectName-test.js b/packages/platform-android/src/link/patches/__tests__/normalizeProjectName-test.js similarity index 87% rename from packages/cli/src/commands/link/__tests__/android/normalizeProjectName-test.js rename to packages/platform-android/src/link/patches/__tests__/normalizeProjectName-test.js index 27792874a4..69443035e9 100644 --- a/packages/cli/src/commands/link/__tests__/android/normalizeProjectName-test.js +++ b/packages/platform-android/src/link/patches/__tests__/normalizeProjectName-test.js @@ -8,7 +8,7 @@ * @emails oncall+javascript_foundation */ -import normalizeProjectName from '../../android/patches/normalizeProjectName'; +import normalizeProjectName from '../normalizeProjectName'; const name = 'test'; const scopedName = '@scoped/test'; diff --git a/packages/cli/src/commands/link/android/patches/applyParams.js b/packages/platform-android/src/link/patches/applyParams.js similarity index 90% rename from packages/cli/src/commands/link/android/patches/applyParams.js rename to packages/platform-android/src/link/patches/applyParams.js index 40862280ec..b3981c05dc 100644 --- a/packages/cli/src/commands/link/android/patches/applyParams.js +++ b/packages/platform-android/src/link/patches/applyParams.js @@ -7,7 +7,7 @@ * @format */ -import { camelCase as toCamelCase } from 'lodash'; +import {camelCase as toCamelCase} from 'lodash'; export default function applyParams(str, params, prefix) { return str.replace(/\$\{(\w+)\}/g, (pattern, param) => { diff --git a/packages/cli/src/commands/link/android/patches/applyPatch.js b/packages/platform-android/src/link/patches/applyPatch.js similarity index 78% rename from packages/cli/src/commands/link/android/patches/applyPatch.js rename to packages/platform-android/src/link/patches/applyPatch.js index 2fe518cc8c..94f3e6630f 100644 --- a/packages/cli/src/commands/link/android/patches/applyPatch.js +++ b/packages/platform-android/src/link/patches/applyPatch.js @@ -8,12 +8,17 @@ */ import fs from 'fs'; +import {logger} from '@react-native-community/cli-tools'; export default function applyPatch(file, patch) { + if (file) { + logger.debug(`Patching ${file}`); + } + fs.writeFileSync( file, fs .readFileSync(file, 'utf8') - .replace(patch.pattern, match => `${match}${patch.patch}`) + .replace(patch.pattern, match => `${match}${patch.patch}`), ); } diff --git a/packages/platform-android/src/link/patches/makeBuildPatch.js b/packages/platform-android/src/link/patches/makeBuildPatch.js new file mode 100644 index 0000000000..8ca0b74535 --- /dev/null +++ b/packages/platform-android/src/link/patches/makeBuildPatch.js @@ -0,0 +1,51 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import fs from 'fs'; +import normalizeProjectName from './normalizeProjectName'; + +const depConfigs = ['compile', 'api', 'implementation']; + +export default function makeBuildPatch(name, buildGradlePath) { + const normalizedProjectName = normalizeProjectName(name); + const installPattern = new RegExp( + buildDepRegExp(normalizedProjectName, ...depConfigs), + ); + + return { + installPattern, + pattern: /[^ \t]dependencies {(\r\n|\n)/, + patch: makePatchString(normalizedProjectName, buildGradlePath), + }; +} + +function makePatchString(normalizedProjectName, buildGradlePath) { + const defaultPatchString = ` implementation project(':${normalizedProjectName}')\n`; + if (!buildGradlePath) { + return defaultPatchString; + } + + const buildGradle = fs.readFileSync(buildGradlePath); + + for (const config of depConfigs) { + const depPattern = new RegExp( + buildDepRegExp(normalizedProjectName, config), + ); + if (depPattern.test(buildGradle)) { + return ` ${config} project(':${normalizedProjectName}')\n`; + } + } + + return defaultPatchString; +} + +function buildDepRegExp(normalizedProjectName, ...configs) { + const orConfigs = configs.join('|'); + return `(${orConfigs})\\w*\\s*\\(*project\\s*\\(['"]:${normalizedProjectName}['"]\\)`; +} diff --git a/packages/cli/src/commands/link/android/patches/makeImportPatch.js b/packages/platform-android/src/link/patches/makeImportPatch.js similarity index 100% rename from packages/cli/src/commands/link/android/patches/makeImportPatch.js rename to packages/platform-android/src/link/patches/makeImportPatch.js diff --git a/packages/cli/src/commands/link/android/patches/makePackagePatch.js b/packages/platform-android/src/link/patches/makePackagePatch.js similarity index 100% rename from packages/cli/src/commands/link/android/patches/makePackagePatch.js rename to packages/platform-android/src/link/patches/makePackagePatch.js diff --git a/packages/cli/src/commands/link/android/patches/makeSettingsPatch.js b/packages/platform-android/src/link/patches/makeSettingsPatch.js similarity index 95% rename from packages/cli/src/commands/link/android/patches/makeSettingsPatch.js rename to packages/platform-android/src/link/patches/makeSettingsPatch.js index 3944d29683..c73603f3f7 100644 --- a/packages/cli/src/commands/link/android/patches/makeSettingsPatch.js +++ b/packages/platform-android/src/link/patches/makeSettingsPatch.js @@ -16,8 +16,8 @@ export default function makeSettingsPatch(name, androidConfig, projectConfig) { const projectDir = slash( path.relative( path.dirname(projectConfig.settingsGradlePath), - androidConfig.sourceDir - ) + androidConfig.sourceDir, + ), ); const normalizedProjectName = normalizeProjectName(name); diff --git a/packages/cli/src/commands/link/android/patches/makeStringsPatch.js b/packages/platform-android/src/link/patches/makeStringsPatch.js similarity index 92% rename from packages/cli/src/commands/link/android/patches/makeStringsPatch.js rename to packages/platform-android/src/link/patches/makeStringsPatch.js index 592d5d8181..e99a190deb 100644 --- a/packages/cli/src/commands/link/android/patches/makeStringsPatch.js +++ b/packages/platform-android/src/link/patches/makeStringsPatch.js @@ -7,7 +7,7 @@ * @format */ -import { camelCase as toCamelCase } from 'lodash'; +import {camelCase as toCamelCase} from 'lodash'; export default function makeStringsPatch(params, prefix) { const values = Object.keys(params).map(param => { diff --git a/packages/cli/src/commands/link/android/patches/normalizeProjectName.js b/packages/platform-android/src/link/patches/normalizeProjectName.js similarity index 100% rename from packages/cli/src/commands/link/android/patches/normalizeProjectName.js rename to packages/platform-android/src/link/patches/normalizeProjectName.js diff --git a/packages/cli/src/commands/link/android/patches/revokePatch.js b/packages/platform-android/src/link/patches/revokePatch.js similarity index 64% rename from packages/cli/src/commands/link/android/patches/revokePatch.js rename to packages/platform-android/src/link/patches/revokePatch.js index d7ae0db9ed..ccf9eaaaf5 100644 --- a/packages/cli/src/commands/link/android/patches/revokePatch.js +++ b/packages/platform-android/src/link/patches/revokePatch.js @@ -8,10 +8,15 @@ */ import fs from 'fs'; +import {logger} from '@react-native-community/cli-tools'; export default function revokePatch(file, patch) { + if (file) { + logger.debug(`Patching ${file}`); + } + fs.writeFileSync( file, - fs.readFileSync(file, 'utf8').replace(patch.patch, '') + fs.readFileSync(file, 'utf8').replace(patch.patch, ''), ); } diff --git a/packages/cli/src/commands/link/android/registerNativeModule.js b/packages/platform-android/src/link/registerNativeModule.js similarity index 88% rename from packages/cli/src/commands/link/android/registerNativeModule.js rename to packages/platform-android/src/link/registerNativeModule.js index 6d03e3da3f..9388d82ded 100644 --- a/packages/cli/src/commands/link/android/registerNativeModule.js +++ b/packages/platform-android/src/link/registerNativeModule.js @@ -18,13 +18,13 @@ export default function registerNativeAndroidModule( name, androidConfig, params, - projectConfig + projectConfig, ) { const buildPatch = makeBuildPatch(name); applyPatch( projectConfig.settingsGradlePath, - makeSettingsPatch(name, androidConfig, projectConfig) + makeSettingsPatch(name, androidConfig, projectConfig), ); applyPatch(projectConfig.buildGradlePath, buildPatch); @@ -32,11 +32,11 @@ export default function registerNativeAndroidModule( applyPatch( projectConfig.mainFilePath, - makePackagePatch(androidConfig.packageInstance, params, name) + makePackagePatch(androidConfig.packageInstance, params, name), ); applyPatch( projectConfig.mainFilePath, - makeImportPatch(androidConfig.packageImportPath) + makeImportPatch(androidConfig.packageImportPath), ); } diff --git a/packages/cli/src/commands/link/android/unlinkAssets.js b/packages/platform-android/src/link/unlinkAssets.js similarity index 66% rename from packages/cli/src/commands/link/android/unlinkAssets.js rename to packages/platform-android/src/link/unlinkAssets.js index 6b42071e2b..33e256c942 100644 --- a/packages/cli/src/commands/link/android/unlinkAssets.js +++ b/packages/platform-android/src/link/unlinkAssets.js @@ -5,11 +5,12 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ -import fs from 'fs-extra'; +import fs from 'fs'; import path from 'path'; -import groupFilesByType from '../groupFilesByType'; +import {logger, groupFilesByType} from '@react-native-community/cli-tools'; /** * Copies each file from an array of assets provided to targetPath directory @@ -17,16 +18,21 @@ import groupFilesByType from '../groupFilesByType'; * For now, the only types of files that are handled are: * - Fonts (otf, ttf) - copied to targetPath/fonts under original name */ -export default function unlinkAssetsAndroid(files, project) { +export default function unlinkAssetsAndroid( + files: Array, + project: {assetsPath: string}, +) { const assets = groupFilesByType(files); + logger.debug(`Assets path: ${project.assetsPath}`); (assets.font || []).forEach(file => { const filePath = path.join( project.assetsPath, 'fonts', - path.basename(file) + path.basename(file), ); if (fs.existsSync(filePath)) { + logger.debug(`Removing asset ${filePath}`); fs.unlinkSync(filePath); } }); diff --git a/packages/cli/src/commands/link/android/unregisterNativeModule.js b/packages/platform-android/src/link/unregisterNativeModule.js similarity index 82% rename from packages/cli/src/commands/link/android/unregisterNativeModule.js rename to packages/platform-android/src/link/unregisterNativeModule.js index 7620414cbc..74098a936f 100644 --- a/packages/cli/src/commands/link/android/unregisterNativeModule.js +++ b/packages/platform-android/src/link/unregisterNativeModule.js @@ -8,7 +8,7 @@ */ import fs from 'fs'; -import { camelCase as toCamelCase } from 'lodash'; +import {camelCase as toCamelCase} from 'lodash'; import revokePatch from './patches/revokePatch'; import makeSettingsPatch from './patches/makeSettingsPatch'; @@ -20,9 +20,9 @@ import makePackagePatch from './patches/makePackagePatch'; export default function unregisterNativeAndroidModule( name, androidConfig, - projectConfig + projectConfig, ) { - const buildPatch = makeBuildPatch(name); + const buildPatch = makeBuildPatch(name, projectConfig.buildGradlePath); const strings = fs.readFileSync(projectConfig.stringsPath, 'utf8'); const params = {}; @@ -30,12 +30,12 @@ export default function unregisterNativeAndroidModule( /moduleConfig="true" name="(\w+)">(.*) { params[param.slice(toCamelCase(name).length + 1)] = value; - } + }, ); revokePatch( projectConfig.settingsGradlePath, - makeSettingsPatch(name, androidConfig, projectConfig) + makeSettingsPatch(name, androidConfig, projectConfig), ); revokePatch(projectConfig.buildGradlePath, buildPatch); @@ -43,11 +43,11 @@ export default function unregisterNativeAndroidModule( revokePatch( projectConfig.mainFilePath, - makePackagePatch(androidConfig.packageInstance, params, name) + makePackagePatch(androidConfig.packageInstance, params, name), ); revokePatch( projectConfig.mainFilePath, - makeImportPatch(androidConfig.packageImportPath) + makeImportPatch(androidConfig.packageImportPath), ); } diff --git a/packages/platform-android/src/link/warnAboutManuallyLinkedLibs.js b/packages/platform-android/src/link/warnAboutManuallyLinkedLibs.js new file mode 100644 index 0000000000..1e28485bee --- /dev/null +++ b/packages/platform-android/src/link/warnAboutManuallyLinkedLibs.js @@ -0,0 +1,53 @@ +// @flow + +import chalk from 'chalk'; +import {logger} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; +import getLinkConfig from './index'; + +// TODO: move to cli-tools once platform-ios and platform-android are migrated +// to TS and unify with iOS implementation +export default function warnAboutManuallyLinkedLibs( + config: ConfigT, + platform: string = 'android', + linkConfig: $Call = getLinkConfig(), +) { + let deps = []; + + for (let key in config.dependencies) { + const dependency = config.dependencies[key]; + try { + const projectConfig = config.project[platform]; + const dependencyConfig = dependency.platforms[platform]; + if (projectConfig && dependencyConfig) { + const x = linkConfig.isInstalled( + projectConfig, + dependency.name, + dependencyConfig, + ); + deps = deps.concat(x ? dependency.name : []); + } + } catch (error) { + logger.debug('Checking manually linked modules failed.', error); + } + } + + const installedModules = [...new Set(deps)]; + + if (installedModules.length) { + logger.error( + `React Native CLI uses autolinking for native dependencies, but the following modules are linked manually: \n${installedModules + .map( + x => + ` - ${chalk.bold(x)} ${chalk.dim( + `(to unlink run: "react-native unlink ${x}")`, + )}`, + ) + .join( + '\n', + )}\nThis is likely happening when upgrading React Native from below 0.60 to 0.60 or above. Going forward, you can unlink this dependency via "react-native unlink " and it will be included in your app automatically. If a library isn't compatible with autolinking, disregard this message and notify the library maintainers.\nRead more about autolinking: ${chalk.dim.underline( + 'https://github.com/react-native-community/cli/blob/master/docs/autolinking.md', + )}`, + ); + } +} diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb new file mode 100644 index 0000000000..205386754e --- /dev/null +++ b/packages/platform-ios/native_modules.rb @@ -0,0 +1,257 @@ +# This is a function which is used inside your Podfile. +# It uses `react-native config` to grab a list of dependencies, and pulls out.all of the ones +# which declare themselves to be iOS dependencies (via having a Podspec) and automatically +# imports those into your current target. +# +def use_native_modules!(root = "..", packages = nil) + if (!packages) + command = "./node_modules/.bin/react-native" + args = ["config"] + output = "" + # Make sure `react-native config` is ran from your project root + Dir.chdir(root) do + output = Pod::Executable.execute_command(command, args, true) + end + + json = [] + output.each_line do |line| + json << line + end + config = JSON.parse(json.join("\n")) + packages = config["dependencies"] + end + + found_pods = [] + + packages.each do |package_name, package| + next unless package_config = package["platforms"]["ios"] + + podspec_path = package_config["podspecPath"] + + # Add a warning to the queue and continue to the next dependency if the podspec_path is nil/empty + if podspec_path.nil? || podspec_path.empty? + Pod::UI.warn("use_native_modules! skipped the react-native dependency '#{package["name"]}'. No podspec file was found.", + [ + "Check to see if there is an updated version that contains the necessary podspec file", + "Contact the library maintainers or send them a PR to add a podspec. The react-native-webview podspec is a good example of a package.json driven podspec. See https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec", + "If necessary, you can disable autolinking for the dependency and link it manually. See https://github.com/react-native-community/cli/blob/master/docs/autolinking.md#how-can-i-disable-autolinking-for-unsupported-library" + ]) + end + next if podspec_path.nil? || podspec_path.empty? + + spec = Pod::Specification.from_file(podspec_path) + + # We want to do a look up inside the current CocoaPods target + # to see if it's already included, this: + # 1. Gives you the chance to define it beforehand + # 2. Ensures CocoaPods won't explode if it's included twice + # + this_target = current_target_definition + existing_deps = current_target_definition.dependencies + + # Skip dependencies that the user already activated themselves. + next if existing_deps.find do |existing_dep| + existing_dep.name.split('/').first == spec.name + end + + # Use relative path + absolute_podspec_path = File.dirname(podspec_path) + relative_podspec_path = File.join(root, absolute_podspec_path.partition('node_modules').last(2).join()) + + pod spec.name, :path => relative_podspec_path + + if package_config["scriptPhases"] + # Can be either an object, or an array of objects + Array(package_config["scriptPhases"]).each do |phase| + # see https://www.rubydoc.info/gems/cocoapods-core/Pod/Podfile/DSL#script_phase-instance_method + # for the full object keys + + # Support passing in a path relative to the root of the package + if phase["path"] + phase["script"] = File.read(File.expand_path(phase["path"], package["root"])) + phase.delete("path") + end + + # Support converting the execution position into a symbol + if phase["execution_position"] + phase["execution_position"] = phase["execution_position"].to_sym + end + + script_phase phase + end + end + + found_pods.push spec + end + + if found_pods.size > 0 + pods = found_pods.map { |p| p.name }.sort.to_sentence + Pod::UI.puts "Detected React Native module #{"pod".pluralize(found_pods.size)} for #{pods}" + end +end + +# You can run the tests for this file by running: +# $ ruby packages/platform-ios/native_modules.rb +if $0 == __FILE__ + require "minitest/spec" + require "minitest/autorun" + + # Define this here, because we’re not actually loading this code. + module Pod + class Specification + end + + module UI + end + end + + # CocoaPods loads ActiveSupport, but we’re not doing that here just for the test. + class Array + def to_sentence + size == 1 ? self[0] : "#{self[0..-2].join(", ")}, and #{self[-1]}" + end + end + class String + def pluralize(count) + count == 1 ? self : "#{self}s" + end + end + + describe "use_native_modules!" do + before do + @script_phase = { + "script" => "123", + "name" => "My Name", + "execution_position" => "before_compile", + "input" => "string" + } + + @ios_package = ios_package = { + "root" => "/root/app/node_modules/react", + "platforms" => { + "ios" => { + "podspecPath" => "/root/app/node_modules/react/React.podspec", + }, + "android" => nil, + }, + } + @android_package = { + "root" => "/root/app/node_modules/react-native-google-play-game-services", + "platforms" => { + "ios" => nil, + "android" => { + # This is where normally more config would be + }, + } + } + @config = { "ios-dep" => @ios_package, "android-dep" => @android_package } + + @activated_pods = activated_pods = [] + @current_target_definition_dependencies = current_target_definition_dependencies = [] + @printed_messages = printed_messages = [] + @added_scripts = added_scripts = [] + @target_definition = target_definition = Object.new + @podfile = podfile = Object.new + @spec = spec = Object.new + + spec.singleton_class.send(:define_method, :name) { "ios-dep" } + + podfile.singleton_class.send(:define_method, :use_native_modules) do |path, config| + use_native_modules!('..', config) + end + + Pod::Specification.singleton_class.send(:define_method, :from_file) do |podspec_path| + podspec_path.must_equal ios_package["platforms"]["ios"]["podspecPath"] + spec + end + + Pod::UI.singleton_class.send(:define_method, :puts) do |message| + printed_messages << message + end + + podfile.singleton_class.send(:define_method, :pod) do |name, options| + activated_pods << { name: name, options: options } + end + + podfile.singleton_class.send(:define_method, :script_phase) do |options| + added_scripts << options + end + + target_definition.singleton_class.send(:define_method, :dependencies) do + current_target_definition_dependencies + end + + podfile.singleton_class.send(:define_method, :current_target_definition) do + target_definition + end + end + + it "activates iOS pods" do + @podfile.use_native_modules('..', @config) + @activated_pods.must_equal [{ + name: "ios-dep", + options: { path: "../node_modules/react" } + }] + end + + it "does not activate pods that were already activated previously (by the user in their Podfile)" do + activated_pod = Object.new + activated_pod.singleton_class.send(:define_method, :name) { "ios-dep" } + @current_target_definition_dependencies << activated_pod + @podfile.use_native_modules('..', @config) + @activated_pods.must_equal [] + end + + it "does not activate pods whose root spec were already activated previously (by the user in their Podfile)" do + activated_pod = Object.new + activated_pod.singleton_class.send(:define_method, :name) { "ios-dep/foo/bar" } + @current_target_definition_dependencies << activated_pod + @podfile.use_native_modules('..', @config) + @activated_pods.must_equal [] + end + + it "prints out the native module pods that were found" do + @podfile.use_native_modules('..', {}) + @podfile.use_native_modules('..', { "pkg-1" => @ios_package }) + @podfile.use_native_modules('..', { "pkg-1" => @ios_package, "pkg-2" => @ios_package }) + @printed_messages.must_equal [ + "Detected React Native module pod for ios-dep", + "Detected React Native module pods for ios-dep, and ios-dep" + ] + end + + describe "concerning script_phases" do + it "uses the options directly" do + @config["ios-dep"]["platforms"]["ios"]["scriptPhases"] = [@script_phase] + @podfile.use_native_modules('..', @config) + @added_scripts.must_equal [{ + "script" => "123", + "name" => "My Name", + "execution_position" => :before_compile, + "input" => "string" + }] + end + + it "reads a script file relative to the package root" do + @script_phase.delete("script") + @script_phase["path"] = "./some_shell_script.sh" + @config["ios-dep"]["platforms"]["ios"]["scriptPhases"] = [@script_phase] + + file_read_mock = MiniTest::Mock.new + file_read_mock.expect(:call, "contents from file", [File.join(@ios_package["root"], "some_shell_script.sh")]) + + File.stub(:read, file_read_mock) do + @podfile.use_native_modules('..', @config) + end + + @added_scripts.must_equal [{ + "script" => "contents from file", + "name" => "My Name", + "execution_position" => :before_compile, + "input" => "string" + }] + file_read_mock.verify + end + end + end +end diff --git a/packages/platform-ios/package.json b/packages/platform-ios/package.json new file mode 100644 index 0000000000..5cfd4a292d --- /dev/null +++ b/packages/platform-ios/package.json @@ -0,0 +1,15 @@ +{ + "name": "@react-native-community/cli-platform-ios", + "version": "2.4.1", + "license": "MIT", + "main": "build/index.js", + "dependencies": { + "@react-native-community/cli-tools": "^2.4.1", + "chalk": "^2.4.2", + "xcode": "^2.0.0" + }, + "files": [ + "build", + "native_modules.rb" + ] +} diff --git a/packages/platform-ios/src/commands/index.js b/packages/platform-ios/src/commands/index.js new file mode 100644 index 0000000000..dc8a7abab5 --- /dev/null +++ b/packages/platform-ios/src/commands/index.js @@ -0,0 +1,7 @@ +/** + * @flow + */ +import logIOS from './logIOS'; +import runIOS from './runIOS'; + +export default [logIOS, runIOS]; diff --git a/packages/cli/src/commands/logIOS/logIOS.js b/packages/platform-ios/src/commands/logIOS/index.js similarity index 84% rename from packages/cli/src/commands/logIOS/logIOS.js rename to packages/platform-ios/src/commands/logIOS/index.js index fb10721c03..9e4e5524dc 100644 --- a/packages/cli/src/commands/logIOS/logIOS.js +++ b/packages/platform-ios/src/commands/logIOS/index.js @@ -7,10 +7,10 @@ * @format */ -import { execFileSync, spawnSync } from 'child_process'; +import {execFileSync, spawnSync} from 'child_process'; import os from 'os'; import path from 'path'; -import logger from '../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; function findAvailableDevice(devices) { for (const key of Object.keys(devices)) { @@ -30,13 +30,13 @@ async function logIOS() { const rawDevices = execFileSync( 'xcrun', ['simctl', 'list', 'devices', '--json'], - { encoding: 'utf8' } + {encoding: 'utf8'}, ); - const { devices } = JSON.parse(rawDevices); + const {devices} = JSON.parse(rawDevices); const device = findAvailableDevice(devices); - if (device === undefined) { + if (device === null) { logger.error('No active iOS device found'); return; } @@ -51,7 +51,7 @@ function tailDeviceLogs(udid) { 'Logs', 'CoreSimulator', udid, - 'asl' + 'asl', ); const log = spawnSync('syslog', ['-w', '-F', 'std', '-d', logDir], { diff --git a/packages/cli/src/commands/runIOS/__tests__/findMatchingSimulator-test.js b/packages/platform-ios/src/commands/runIOS/__tests__/findMatchingSimulator-test.js similarity index 74% rename from packages/cli/src/commands/runIOS/__tests__/findMatchingSimulator-test.js rename to packages/platform-ios/src/commands/runIOS/__tests__/findMatchingSimulator-test.js index e3657a1847..6a181328ff 100644 --- a/packages/cli/src/commands/runIOS/__tests__/findMatchingSimulator-test.js +++ b/packages/platform-ios/src/commands/runIOS/__tests__/findMatchingSimulator-test.js @@ -53,8 +53,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6' - ) + 'iPhone 6', + ), ).toEqual({ udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', name: 'iPhone 6', @@ -105,8 +105,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6' - ) + 'iPhone 6', + ), ).toEqual({ udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', name: 'iPhone 6', @@ -154,14 +154,14 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6' - ) + 'iPhone 6', + ), ).toEqual(null); }); it('should return null if an odd input', () => { expect(findMatchingSimulator('random string input', 'iPhone 6')).toEqual( - null + null, ); }); @@ -204,8 +204,8 @@ describe('findMatchingSimulator', () => { ], }, }, - null - ) + null, + ), ).toEqual({ udid: '1CCBBF8B-5773-4EA6-BD6F-C308C87A1ADB', name: 'iPhone 5', @@ -279,8 +279,8 @@ describe('findMatchingSimulator', () => { ], }, }, - null - ) + null, + ), ).toEqual({ udid: '1CCBBF8B-5773-4EA6-BD6F-C308C87A1ADB', name: 'iPhone 5', @@ -328,8 +328,8 @@ describe('findMatchingSimulator', () => { ], }, }, - null - ) + null, + ), ).toEqual({ udid: 'D0F29BE7-CC3C-4976-888D-C739B4F50508', name: 'iPhone 6s', @@ -377,8 +377,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6' - ) + 'iPhone 6', + ), ).toEqual({ udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', name: 'iPhone 6', @@ -452,8 +452,8 @@ describe('findMatchingSimulator', () => { ], }, }, - null - ) + null, + ), ).toEqual({ udid: '3A409DC5-5188-42A6-8598-3AA6F34607A5', name: 'iPhone 7', @@ -527,8 +527,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6s' - ) + 'iPhone 6s', + ), ).toEqual({ udid: 'D0F29BE7-CC3C-4976-888D-C739B4F50508', name: 'iPhone 6s', @@ -602,8 +602,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6s (10.0)' - ) + 'iPhone 6s (10.0)', + ), ).toEqual({ udid: 'CBBB8FB8-77AB-49A9-8297-4CCFE3189C22', name: 'iPhone 6s', @@ -671,8 +671,228 @@ describe('findMatchingSimulator', () => { ], }, }, - 'iPhone 6s (10.0)' - ) + 'iPhone 6s (10.0)', + ), + ).toEqual(null); + }); + + it('should return iPad(name with brackets) simulator if simulator name is in the list', () => { + expect( + findMatchingSimulator( + { + devices: { + 'iOS 12.0': [ + { + state: 'Shutdown', + availability: '(unavailable, runtime profile not found)', + name: 'iPhone 4s', + udid: 'B9B5E161-416B-43C4-A78F-729CB96CC8C6', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 5', + udid: '1CCBBF8B-5773-4EA6-BD6F-C308C87A1ADB', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '9564ABEE-9EC2-4B4A-B443-D3710929A45A', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6s', + udid: 'D0F29BE7-CC3C-4976-888D-C739B4F50508', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPad Pro (9.7-inch)', + udid: 'B2141C1E-86B7-4A10-82A7-4956799526DF', + }, + ], + 'iOS 12.2': [ + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: '2FF48AE5-CC3B-4C80-8D25-48966A6BE2C0', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '841E33FE-E8A1-4B65-9FF8-6EAA6442A3FC', + }, + { + state: 'Booted', + availability: '(available)', + name: 'iPhone 7', + udid: '3A409DC5-5188-42A6-8598-3AA6F34607A5', + }, + ], + }, + }, + 'iPad Pro (9.7-inch)', + ), + ).toEqual({ + udid: 'B2141C1E-86B7-4A10-82A7-4956799526DF', + name: 'iPad Pro (9.7-inch)', + booted: false, + version: 'iOS 12.0', + }); + }); + + it('should return iPad(name with brackets) simulator if simulator name and specified iOS version is in the list', () => { + expect( + findMatchingSimulator( + { + devices: { + 'iOS 12.0': [ + { + state: 'Shutdown', + availability: '(unavailable, runtime profile not found)', + name: 'iPhone 4s', + udid: 'B9B5E161-416B-43C4-A78F-729CB96CC8C6', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 5', + udid: '1CCBBF8B-5773-4EA6-BD6F-C308C87A1ADB', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '9564ABEE-9EC2-4B4A-B443-D3710929A45A', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6s', + udid: 'D0F29BE7-CC3C-4976-888D-C739B4F50508', + }, + ], + 'iOS 12.2': [ + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: '2FF48AE5-CC3B-4C80-8D25-48966A6BE2C0', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '841E33FE-E8A1-4B65-9FF8-6EAA6442A3FC', + }, + { + state: 'Booted', + availability: '(available)', + name: 'iPhone 7', + udid: '3A409DC5-5188-42A6-8598-3AA6F34607A5', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPad Pro (9.7-inch)', + udid: 'B2141C1E-86B7-4A10-82A7-4956799526DF', + }, + ], + }, + }, + 'iPad Pro (9.7-inch) (12.2)', + ), + ).toEqual({ + udid: 'B2141C1E-86B7-4A10-82A7-4956799526DF', + name: 'iPad Pro (9.7-inch)', + booted: false, + version: 'iOS 12.2', + }); + }); + + it('should return null if the version is specified and no iPad device with the exact version exists', () => { + expect( + findMatchingSimulator( + { + devices: { + 'iOS 12.0': [ + { + state: 'Shutdown', + availability: '(unavailable, runtime profile not found)', + name: 'iPhone 4s', + udid: 'B9B5E161-416B-43C4-A78F-729CB96CC8C6', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 5', + udid: '1CCBBF8B-5773-4EA6-BD6F-C308C87A1ADB', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: 'BA0D93BD-07E6-4182-9B0A-F60A2474139C', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '9564ABEE-9EC2-4B4A-B443-D3710929A45A', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6s', + udid: 'D0F29BE7-CC3C-4976-888D-C739B4F50508', + }, + ], + 'iOS 12.2': [ + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6', + udid: '2FF48AE5-CC3B-4C80-8D25-48966A6BE2C0', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPhone 6 (Plus)', + udid: '841E33FE-E8A1-4B65-9FF8-6EAA6442A3FC', + }, + { + state: 'Booted', + availability: '(available)', + name: 'iPhone 7', + udid: '3A409DC5-5188-42A6-8598-3AA6F34607A5', + }, + { + state: 'Shutdown', + availability: '(available)', + name: 'iPad Pro (9.7-inch)', + udid: 'B2141C1E-86B7-4A10-82A7-4956799526DF', + }, + ], + }, + }, + 'iPad Pro (9.7-inch) (12.0)', + ), ).toEqual(null); }); @@ -703,8 +923,8 @@ describe('findMatchingSimulator', () => { ], }, }, - 'Apple TV' - ) + 'Apple TV', + ), ).toEqual({ udid: '816C30EA-38EA-41AC-BFDA-96FB632D522E', name: 'Apple TV', diff --git a/packages/cli/src/commands/runIOS/__tests__/findXcodeProject-test.js b/packages/platform-ios/src/commands/runIOS/__tests__/findXcodeProject-test.js similarity index 97% rename from packages/cli/src/commands/runIOS/__tests__/findXcodeProject-test.js rename to packages/platform-ios/src/commands/runIOS/__tests__/findXcodeProject-test.js index 365d48747b..a3d79a0dfc 100644 --- a/packages/cli/src/commands/runIOS/__tests__/findXcodeProject-test.js +++ b/packages/platform-ios/src/commands/runIOS/__tests__/findXcodeProject-test.js @@ -23,7 +23,7 @@ describe('findXcodeProject', () => { 'PodFile', 'Podfile.lock', 'Pods', - ]) + ]), ).toEqual({ name: 'AwesomeApp.xcodeproj', isWorkspace: false, @@ -41,7 +41,7 @@ describe('findXcodeProject', () => { 'PodFile', 'Podfile.lock', 'Pods', - ]) + ]), ).toEqual({ name: 'AwesomeApp.xcworkspace', isWorkspace: true, @@ -57,7 +57,7 @@ describe('findXcodeProject', () => { 'PodFile', 'Podfile.lock', 'Pods', - ]) + ]), ).toEqual(null); }); }); diff --git a/packages/cli/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js b/packages/platform-ios/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js similarity index 97% rename from packages/cli/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js rename to packages/platform-ios/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js index e92b6a5276..b5ebb2372f 100644 --- a/packages/cli/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js +++ b/packages/platform-ios/src/commands/runIOS/__tests__/parseIOSDevicesList-test.js @@ -27,7 +27,7 @@ describe('parseIOSDevicesList', () => { 'Blank', 'System Usage', 'Zombies', - ].join('\n') + ].join('\n'), ); expect(devices).toEqual([ @@ -41,7 +41,7 @@ describe('parseIOSDevicesList', () => { it('ignores garbage', () => { expect(parseIOSDevicesList('Something went terribly wrong (-42)')).toEqual( - [] + [], ); }); }); diff --git a/packages/cli/src/commands/runIOS/findMatchingSimulator.js b/packages/platform-ios/src/commands/runIOS/findMatchingSimulator.js similarity index 87% rename from packages/cli/src/commands/runIOS/findMatchingSimulator.js rename to packages/platform-ios/src/commands/runIOS/findMatchingSimulator.js index 09f2d9a6b1..b26e08e618 100644 --- a/packages/cli/src/commands/runIOS/findMatchingSimulator.js +++ b/packages/platform-ios/src/commands/runIOS/findMatchingSimulator.js @@ -7,8 +7,6 @@ * @format */ -/* eslint-disable */ - /** * Takes in a parsed simulator list and a desired name, and returns an object with the matching simulator. The desired * name can optionally include the iOS version in between parenthesis after the device name. Ex: "iPhone 6 (9.2)" in @@ -29,8 +27,9 @@ function findMatchingSimulator(simulators, simulatorString) { const devices = simulators.devices; const parsedSimulatorName = simulatorString - ? simulatorString.match(/(.*)? (?:\((.*)?\))?/) + ? simulatorString.match(/(.*)? (?:\((\d+\.\d+)?\))$/) : []; + if (parsedSimulatorName && parsedSimulatorName[2] !== undefined) { var simulatorVersion = parsedSimulatorName[2]; var simulatorName = parsedSimulatorName[1]; @@ -43,13 +42,16 @@ function findMatchingSimulator(simulators, simulatorString) { const device = devices[versionDescriptor]; let version = versionDescriptor; - if ((/^com\.apple\.CoreSimulator\.SimRuntime\./g).test(version)) { + if (/^com\.apple\.CoreSimulator\.SimRuntime\./g.test(version)) { // Transform "com.apple.CoreSimulator.SimRuntime.iOS-12-2" into "iOS 12.2" - version = version.replace(/^com\.apple\.CoreSimulator\.SimRuntime\.([^-]+)-([^-]+)-([^-]+)$/g, '$1 $2.$3'); + version = version.replace( + /^com\.apple\.CoreSimulator\.SimRuntime\.([^-]+)-([^-]+)-([^-]+)$/g, + '$1 $2.$3', + ); } // Making sure the version of the simulator is an iOS or tvOS (Removes Apple Watch, etc) - if (!version.startsWith('iOS') && !version.startsWith('tvOS')) { + if (!version.includes('iOS') && !version.includes('tvOS')) { continue; } if (simulatorVersion && !version.endsWith(simulatorVersion)) { @@ -60,7 +62,8 @@ function findMatchingSimulator(simulators, simulatorString) { // Skipping non-available simulator if ( simulator.availability !== '(available)' && - simulator.isAvailable !== 'YES' + simulator.isAvailable !== 'YES' && + simulator.isAvailable !== true ) { continue; } diff --git a/packages/cli/src/commands/runIOS/findXcodeProject.js b/packages/platform-ios/src/commands/runIOS/findXcodeProject.js similarity index 100% rename from packages/cli/src/commands/runIOS/findXcodeProject.js rename to packages/platform-ios/src/commands/runIOS/findXcodeProject.js diff --git a/packages/cli/src/commands/runIOS/runIOS.js b/packages/platform-ios/src/commands/runIOS/index.js similarity index 58% rename from packages/cli/src/commands/runIOS/runIOS.js rename to packages/platform-ios/src/commands/runIOS/index.js index e2061a4521..5b7b3f5ae4 100644 --- a/packages/cli/src/commands/runIOS/runIOS.js +++ b/packages/platform-ios/src/commands/runIOS/index.js @@ -5,126 +5,107 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @format */ -// eslint-disable-next-line import child_process from 'child_process'; import fs from 'fs'; import path from 'path'; -import type { ContextT } from '../../tools/types.flow'; +import chalk from 'chalk'; +import type {ConfigT} from 'types'; import findXcodeProject from './findXcodeProject'; import parseIOSDevicesList from './parseIOSDevicesList'; import findMatchingSimulator from './findMatchingSimulator'; -import { ProcessError } from '../../tools/errors'; -import logger from '../../tools/logger'; +import warnAboutManuallyLinkedLibs from '../../link/warnAboutManuallyLinkedLibs'; +import { + logger, + CLIError, + getDefaultUserTerminal, +} from '@react-native-community/cli-tools'; type FlagsT = { simulator: string, configuration: string, scheme: ?string, projectPath: string, - device: ?string, + device: ?(string | true), udid: ?string, packager: boolean, verbose: boolean, port: number, + terminal: ?string, }; -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?' + throw new CLIError( + 'iOS project folder not found. Are you sure this is a React Native project?', ); } + warnAboutManuallyLinkedLibs(ctx); + process.chdir(args.projectPath); const xcodeProject = findXcodeProject(fs.readdirSync('.')); if (!xcodeProject) { - throw new Error( - `Could not find Xcode project files in "${args.projectPath}" folder` + throw new CLIError( + `Could not find Xcode project files in "${args.projectPath}" folder`, ); } const inferredSchemeName = path.basename( xcodeProject.name, - path.extname(xcodeProject.name) + path.extname(xcodeProject.name), ); const scheme = args.scheme || inferredSchemeName; logger.info( - `Found Xcode ${xcodeProject.isWorkspace ? 'workspace' : 'project'} ${ - xcodeProject.name - }` + `Found Xcode ${ + xcodeProject.isWorkspace ? 'workspace' : 'project' + } "${chalk.bold(xcodeProject.name)}"`, ); + const {device, udid} = args; + + if (!device && !udid) { + return runOnSimulator(xcodeProject, scheme, args); + } + const devices = parseIOSDevicesList( // $FlowExpectedError https://github.com/facebook/flow/issues/5675 child_process.execFileSync('xcrun', ['instruments', '-s'], { encoding: 'utf8', - }) + }), ); - if (args.device) { - const selectedDevice = matchingDevice(devices, args.device); - if (selectedDevice) { - return runOnDevice( - selectedDevice, - scheme, - xcodeProject, - args.configuration, - args.packager, - args.verbose, - args.port - ); - } - if (devices && devices.length > 0) { - // $FlowIssue: args.device is defined in this context - logger.error(`Could not find device with the name: "${args.device}". -Choose one of the following:${printFoundDevices(devices)}`); - } else { - logger.error('No iOS devices connected.'); - } - } else if (args.udid) { - // $FlowIssue: args.udid is defined in this context - return runOnDeviceByUdid(args, scheme, xcodeProject, devices); + if (devices.length === 0) { + return logger.error('No iOS devices connected.'); } - return runOnSimulator(xcodeProject, args, scheme); -} - -function runOnDeviceByUdid( - args: FlagsT & { udid: string }, - scheme, - xcodeProject, - devices -) { - const selectedDevice = matchingDeviceByUdid(devices, args.udid); + const selectedDevice = matchingDevice(devices, device, udid); if (selectedDevice) { - runOnDevice( - selectedDevice, - scheme, - xcodeProject, - args.configuration, - args.packager, - args.verbose, - args.port + return runOnDevice(selectedDevice, scheme, xcodeProject, args); + } + + if (device) { + return logger.error( + `Could not find a device named: "${chalk.bold( + String(device), + )}". ${printFoundDevices(devices)}`, ); - return; } - if (devices && devices.length > 0) { - // $FlowIssue: args.udid is defined in this context - logger.error(`Could not find device with the udid: "${args.udid}". -Choose one of the following:\n${printFoundDevices(devices)}`); - } else { - logger.error('No iOS devices connected.'); + if (udid) { + return logger.error( + `Could not find a device with udid: "${chalk.bold( + udid, + )}". ${printFoundDevices(devices)}`, + ); } } -async function runOnSimulator(xcodeProject, args, scheme) { +async function runOnSimulator(xcodeProject, scheme, args: FlagsT) { let simulators; try { simulators = JSON.parse( @@ -132,16 +113,16 @@ async function runOnSimulator(xcodeProject, args, scheme) { child_process.execFileSync( 'xcrun', ['simctl', 'list', '--json', 'devices'], - { encoding: 'utf8' } - ) + {encoding: 'utf8'}, + ), ); - } catch (e) { - throw new Error('Could not parse the simulator list output'); + } catch (error) { + throw new CLIError('Could not parse the simulator list output', error); } const selectedSimulator = findMatchingSimulator(simulators, args.simulator); if (!selectedSimulator) { - throw new Error(`Could not find ${args.simulator} simulator`); + throw new CLIError(`Could not find "${args.simulator}" simulator`); } /** @@ -156,7 +137,7 @@ async function runOnSimulator(xcodeProject, args, scheme) { * this flag has no effect. */ const activeDeveloperDir = child_process - .execFileSync('xcode-select', ['-p'], { encoding: 'utf8' }) + .execFileSync('xcode-select', ['-p'], {encoding: 'utf8'}) // $FlowExpectedError https://github.com/facebook/flow/issues/5675 .trim(); @@ -175,103 +156,100 @@ async function runOnSimulator(xcodeProject, args, scheme) { xcodeProject, selectedSimulator.udid, scheme, - args.configuration, - args.packager, - args.verbose, - args.port + args, ); const appPath = getBuildPath(args.configuration, appName, false, scheme); - logger.info(`Installing ${appPath}`); + logger.info(`Installing "${chalk.bold(appPath)}"`); child_process.spawnSync( 'xcrun', ['simctl', 'install', selectedSimulator.udid, appPath], - { - stdio: 'inherit', - } + {stdio: 'inherit'}, ); const bundleID = child_process .execFileSync( '/usr/libexec/PlistBuddy', ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], - { encoding: 'utf8' } + {encoding: 'utf8'}, ) // $FlowExpectedError https://github.com/facebook/flow/issues/5675 .trim(); - logger.info(`Launching ${bundleID}`); + logger.info(`Launching "${chalk.bold(bundleID)}"`); - child_process.spawnSync( - 'xcrun', - ['simctl', 'launch', selectedSimulator.udid, bundleID], - { - stdio: 'inherit', - } - ); + const result = child_process.spawnSync('xcrun', [ + 'simctl', + 'launch', + selectedSimulator.udid, + bundleID, + ]); + + if (result.status === 0) { + logger.success('Successfully launched the app on the simulator'); + } else { + logger.error('Failed to launch the app on simulator', result.stderr); + } } -async function runOnDevice( - selectedDevice, - scheme, - xcodeProject, - configuration, - launchPackager, - verbose, - port -) { +async function runOnDevice(selectedDevice, scheme, xcodeProject, args: FlagsT) { + const isIOSDeployInstalled = child_process.spawnSync( + 'ios-deploy', + ['--version'], + {encoding: 'utf8'}, + ); + + if (isIOSDeployInstalled.error) { + throw new CLIError( + `Failed to install the app on the device because we couldn't execute the "ios-deploy" command. Please install it by running "${chalk.bold( + 'npm install -g ios-deploy', + )}" and try again.`, + ); + } + const appName = await buildProject( xcodeProject, selectedDevice.udid, scheme, - configuration, - launchPackager, - verbose, - port + args, ); const iosDeployInstallArgs = [ '--bundle', - getBuildPath(configuration, appName, true, scheme), + getBuildPath(args.configuration, appName, true, scheme), '--id', selectedDevice.udid, '--justlaunch', ]; - logger.info(`installing and launching your app on ${selectedDevice.name}...`); + logger.info(`Installing and launching your app on ${selectedDevice.name}`); const iosDeployOutput = child_process.spawnSync( 'ios-deploy', iosDeployInstallArgs, - { encoding: 'utf8' } + {encoding: 'utf8'}, ); if (iosDeployOutput.error) { - logger.error( - `** INSTALLATION FAILED **\nMake sure you have ios-deploy installed globally.\n(e.g "npm install -g ios-deploy")` + throw new CLIError( + `Failed to install the app on the device. We've encountered an error in "ios-deploy" command: ${ + iosDeployOutput.error.message + }`, ); - } else { - logger.info('** INSTALLATION SUCCEEDED **'); } + + return logger.success('Installed the app on the device.'); } -function buildProject( - xcodeProject, - udid, - scheme, - configuration, - launchPackager = false, - verbose, - port -) { +function buildProject(xcodeProject, udid, scheme, args: FlagsT) { return new Promise((resolve, reject) => { const xcodebuildArgs = [ xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, '-configuration', - configuration, + args.configuration, '-scheme', scheme, '-destination', @@ -279,9 +257,13 @@ function buildProject( '-derivedDataPath', `build/${scheme}`, ]; - logger.info(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); + logger.info( + `Building ${chalk.dim( + `(using "xcodebuild ${xcodebuildArgs.join(' ')}")`, + )}`, + ); let xcpretty; - if (!verbose) { + if (!args.verbose) { xcpretty = xcprettyAvailable() && child_process.spawn('xcpretty', [], { @@ -291,16 +273,21 @@ function buildProject( const buildProcess = child_process.spawn( 'xcodebuild', xcodebuildArgs, - getProcessOptions(launchPackager, port) + getProcessOptions(args), ); let buildOutput = ''; let errorOutput = ''; buildProcess.stdout.on('data', data => { - buildOutput += data.toString(); + const stringData = data.toString(); + buildOutput += stringData; if (xcpretty) { xcpretty.stdin.write(data); } else { - logger.info(data.toString()); + if (logger.isVerbose()) { + logger.debug(stringData); + } else { + process.stdout.write('.'); + } } }); buildProcess.stderr.on('data', data => { @@ -309,19 +296,21 @@ function buildProject( buildProcess.on('close', code => { if (xcpretty) { xcpretty.stdin.end(); + } else { + process.stdout.write('\n'); } if (code !== 0) { reject( - new ProcessError( - [ - `Failed to build iOS project.`, - `We ran "xcodebuild" command but it exited with error code ${code}.`, - `To debug build logs further, consider building your app with Xcode.app, by opening ${ - xcodeProject.name - }`, - ].join(' '), - errorOutput - ) + new CLIError( + ` + Failed to build iOS project. + + We ran "xcodebuild" command but it exited with error code ${code}. To debug build + logs further, consider building your app with Xcode.app, by opening + ${xcodeProject.name}. + `, + buildOutput + '\n' + errorOutput, + ), ); return; } @@ -332,7 +321,7 @@ function buildProject( function bootSimulator(selectedSimulator) { const simulatorFullName = formattedDeviceName(selectedSimulator); - logger.info(`Launching ${simulatorFullName}...`); + logger.info(`Launching ${simulatorFullName}`); try { child_process.spawnSync('xcrun', [ 'instruments', @@ -356,12 +345,18 @@ function getBuildPath(configuration, appName, isDevice, scheme) { device = 'iphonesimulator'; } - return `build/${scheme}/Build/Products/${configuration}-${device}/${appName}.app`; + let buildPath = `build/${scheme}/Build/Products/${configuration}-${device}/${appName}.app`; + // Check wether app file exist, sometimes `-derivedDataPath` option of `xcodebuild` not works as expected. + if (!fs.existsSync(path.join(buildPath))) { + return `DerivedData/Build/Products/${configuration}-${device}/${appName}.app`; + } + + return buildPath; } function getProductName(buildOutput) { const productNameMatch = /export FULL_PRODUCT_NAME="?(.+).app"?$/m.exec( - buildOutput + buildOutput, ); return productNameMatch ? productNameMatch[1] : null; } @@ -377,33 +372,26 @@ function xcprettyAvailable() { return true; } -function matchingDevice(devices, deviceName) { +function matchingDevice(devices, deviceName, udid) { + if (udid) { + return matchingDeviceByUdid(devices, udid); + } if (deviceName === true && devices.length === 1) { logger.info( - `Using first available device ${ - devices[0].name - } due to lack of name supplied.` + `Using first available device named "${chalk.bold( + devices[0].name, + )}" due to lack of name supplied.`, ); return devices[0]; } - for (let i = devices.length - 1; i >= 0; i--) { - if ( - devices[i].name === deviceName || - formattedDeviceName(devices[i]) === deviceName - ) { - return devices[i]; - } - } - return null; + return devices.find( + device => + device.name === deviceName || formattedDeviceName(device) === deviceName, + ); } function matchingDeviceByUdid(devices, udid) { - for (let i = devices.length - 1; i >= 0; i--) { - if (devices[i].udid === udid) { - return devices[i]; - } - } - return null; + return devices.find(device => device.udid === udid); } function formattedDeviceName(simulator) { @@ -411,22 +399,21 @@ function formattedDeviceName(simulator) { } function printFoundDevices(devices) { - let output = ''; - for (let i = devices.length - 1; i >= 0; i--) { - output += `${devices[i].name} Udid: ${devices[i].udid}\n`; - } - return output; + return [ + 'Available devices:', + ...devices.map(device => ` - ${device.name} (${device.udid})`), + ].join('\n'); } -function getProcessOptions(launchPackager, port) { - if (launchPackager) { +function getProcessOptions({packager, terminal, port}) { + if (packager) { return { - env: { ...process.env, RCT_METRO_PORT: port }, + env: {...process.env, RCT_TERMINAL: terminal, RCT_METRO_PORT: port}, }; } return { - env: { ...process.env, RCT_NO_LAUNCH_PACKAGER: true }, + env: {...process.env, RCT_TERMINAL: terminal, RCT_NO_LAUNCH_PACKAGER: true}, }; } @@ -455,49 +442,55 @@ export default { ], options: [ { - command: '--simulator [string]', + name: '--simulator [string]', description: 'Explicitly set simulator to use. Optionally include iOS version between' + 'parenthesis at the end to match an exact version: "iPhone 6 (10.0)"', default: 'iPhone X', }, { - command: '--configuration [string]', + name: '--configuration [string]', description: 'Explicitly set the scheme configuration to use', default: 'Debug', }, { - command: '--scheme [string]', + name: '--scheme [string]', description: 'Explicitly set Xcode scheme to use', }, { - command: '--project-path [string]', + name: '--project-path [string]', description: 'Path relative to project root where the Xcode project ' + '(.xcodeproj) lives.', default: 'ios', }, { - command: '--device [string]', + name: '--device [string]', description: 'Explicitly set device to use by name. The value is not required if you have a single device connected.', }, { - command: '--udid [string]', + name: '--udid [string]', description: 'Explicitly set device to use by udid', }, { - command: '--no-packager', + name: '--no-packager', description: 'Do not launch packager while building', }, { - command: '--verbose', + name: '--verbose', description: 'Do not use xcpretty even if installed', }, { - command: '--port [number]', + name: '--port [number]', default: process.env.RCT_METRO_PORT || 8081, parse: (val: string) => Number(val), }, + { + name: '--terminal [string]', + description: + 'Launches the Metro Bundler in a new window using the specified terminal path.', + default: getDefaultUserTerminal, + }, ], }; diff --git a/packages/cli/src/commands/runIOS/parseIOSDevicesList.js b/packages/platform-ios/src/commands/runIOS/parseIOSDevicesList.js similarity index 94% rename from packages/cli/src/commands/runIOS/parseIOSDevicesList.js rename to packages/platform-ios/src/commands/runIOS/parseIOSDevicesList.js index 4bb61bff8b..2cacf661a2 100644 --- a/packages/cli/src/commands/runIOS/parseIOSDevicesList.js +++ b/packages/platform-ios/src/commands/runIOS/parseIOSDevicesList.js @@ -26,7 +26,7 @@ function parseIOSDevicesList(text: string): Array { const name = device[1]; const version = device[2]; const udid = device[3]; - devices.push({ udid, name, version }); + devices.push({udid, name, version}); } }); diff --git a/packages/platform-ios/src/config/__fixtures__/files/project.pbxproj b/packages/platform-ios/src/config/__fixtures__/files/project.pbxproj new file mode 100644 index 0000000000..b27d06606b --- /dev/null +++ b/packages/platform-ios/src/config/__fixtures__/files/project.pbxproj @@ -0,0 +1,804 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { +/* Begin PBXBuildFile section */ + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; + 00E356F31AD99517003FC87E /* androidTestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* androidTestTests.m */; }; + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 672DE8B31B124B8088D0D29F /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B5255B7628A54AC2A9B4B2A0 /* libBVLinearGradient.a */; }; + 68FEB18F24414EF981BD7940 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 53C67FE8F7294B7A83790610 /* libCodePush.a */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + C6C437D070BA42D6BE39198B /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A7396DFBAFA4CA092E367F5 /* libRCTVideo.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTActionSheet; + }; + 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTGeolocation; + }; + 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; + 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; + 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; + remoteInfo = RCTVibration; + }; + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = androidTest; + }; + 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTSettings; + }; + 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTLinking; + }; + 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; + 00E356EE1AD99517003FC87E /* androidTestTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = androidTestTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* androidTestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = androidTestTests.m; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* androidTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = androidTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = androidTest/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = androidTest/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = androidTest/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = androidTest/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = androidTest/main.m; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 53C67FE8F7294B7A83790610 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libCodePush.a; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; + B5255B7628A54AC2A9B4B2A0 /* libBVLinearGradient.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBVLinearGradient.a; sourceTree = ""; }; + 467A6CBCB2164E7D9B673D4C /* CodePush.xcodeproj */ = {isa = PBXFileReference; name = "CodePush.xcodeproj"; path = "../node_modules/react-native-code-push/CodePush.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + FD7121847BA447D8B737F22A /* BVLinearGradient.xcodeproj */ = {isa = PBXFileReference; name = "BVLinearGradient.xcodeproj"; path = "../node_modules/react-native-linear-gradient/BVLinearGradient.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 409DA945815C46DEB4F254DB /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; name = "RCTVideo.xcodeproj"; path = "../node_modules/react-native-video/RCTVideo.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 3A7396DFBAFA4CA092E367F5 /* libRCTVideo.a */ = {isa = PBXFileReference; name = "libRCTVideo.a"; path = "libRCTVideo.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 146834051AC3E58100842450 /* libReact.a in Frameworks */, + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + 672DE8B31B124B8088D0D29F /* libBVLinearGradient.a in Frameworks */, + 68FEB18F24414EF981BD7940 /* libCodePush.a in Frameworks */, + C6C437D070BA42D6BE39198B /* libRCTVideo.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00C302A81ABCB8CE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302B61ABCB90400DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302BC1ABCB91800DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302D41ABCB9D200DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302E01ABCB9EE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, + ); + name = Products; + sourceTree = ""; + }; + 00E356EF1AD99517003FC87E /* androidTestTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* androidTestTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = androidTestTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 139105B71AF99BAD00B5F7CC /* Products */ = { + isa = PBXGroup; + children = ( + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, + ); + name = Products; + sourceTree = ""; + }; + 139FDEE71B06529A00C62182 /* Products */ = { + isa = PBXGroup; + children = ( + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* androidTest */ = { + isa = PBXGroup; + children = ( + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = androidTest; + sourceTree = ""; + }; + 146834001AC3E56700842450 /* Products */ = { + isa = PBXGroup; + children = ( + 146834041AC3E56700842450 /* libReact.a */, + ); + name = Products; + sourceTree = ""; + }; + 78C398B11ACF4ADC00677621 /* Products */ = { + isa = PBXGroup; + children = ( + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, + ); + name = Products; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + 146833FF1AC3E56700842450 /* React.xcodeproj */, + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + 467A6CBCB2164E7D9B673D4C /* CodePush.xcodeproj */, + FD7121847BA447D8B737F22A /* BVLinearGradient.xcodeproj */, + 409DA945815C46DEB4F254DB /* RCTVideo.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 832341B11AAA6A8300B99B32 /* Products */ = { + isa = PBXGroup; + children = ( + 832341B51AAA6A8300B99B32 /* libRCTText.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* androidTest */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* androidTestTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* androidTest.app */, + 00E356EE1AD99517003FC87E /* androidTestTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* androidTestTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "androidTestTests" */; + buildPhases = ( + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = androidTestTests; + productName = androidTestTests; + productReference = 00E356EE1AD99517003FC87E /* androidTestTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* androidTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "androidTest" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = androidTest; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* androidTest.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "androidTest" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; + ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + }, + { + ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; + ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + }, + { + ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; + ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + }, + { + ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; + ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + }, + { + ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; + ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; + ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + }, + { + ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; + ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; + ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + }, + { + ProductGroup = 139FDEE71B06529A00C62182 /* Products */; + ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 146834001AC3E56700842450 /* Products */; + ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* androidTest */, + 00E356ED1AD99517003FC87E /* androidTestTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTActionSheet.a; + remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTGeolocation.a; + remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTVibration.a; + remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTSettings.a; + remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 146834041AC3E56700842450 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTLinking.a; + remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../node_modules/react-native/scripts/react-native-xcode.sh"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* androidTestTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* androidTest */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = androidTest; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = androidTestTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/androidTest.app/androidTest"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = androidTestTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/androidTest.app/androidTest"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEAD_CODE_STRIPPING = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)", + "$(SRCROOT)/../node_modules/react-native-code-push", + "$(SRCROOT)/../node_modules/react-native-linear-gradient/**", + "$(SRCROOT)/../node_modules/react-native-video", + ); + INFOPLIST_FILE = androidTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = androidTest; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)", + "$(SRCROOT)/../node_modules/react-native-code-push", + "$(SRCROOT)/../node_modules/react-native-linear-gradient/**", + "$(SRCROOT)/../node_modules/react-native-video", + ); + INFOPLIST_FILE = androidTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = androidTest; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)", + "$(SRCROOT)/../node_modules/react-native-code-push", + "$(SRCROOT)/../node_modules/react-native-linear-gradient/**", + "$(SRCROOT)/../node_modules/react-native-video", + ); + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)", + "$(SRCROOT)/../node_modules/react-native-code-push", + "$(SRCROOT)/../node_modules/react-native-linear-gradient/**", + "$(SRCROOT)/../node_modules/react-native-video", + ); + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "androidTestTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "androidTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "androidTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/packages/platform-ios/src/config/__fixtures__/projects.js b/packages/platform-ios/src/config/__fixtures__/projects.js new file mode 100644 index 0000000000..b347fcae0b --- /dev/null +++ b/packages/platform-ios/src/config/__fixtures__/projects.js @@ -0,0 +1,45 @@ +/** + * @flow + */ + +const path = jest.requireActual('path'); +const fs = jest.requireActual('fs'); + +const ios = { + 'demoProject.xcodeproj': { + 'project.pbxproj': fs.readFileSync( + path.join(__dirname, './files/project.pbxproj'), + ), + }, +}; + +const iosPod = { + 'demoProject.xcodeproj': { + 'project.pbxproj': fs.readFileSync( + path.join(__dirname, './files/project.pbxproj'), + ), + }, + 'TestPod.podspec': 'empty', +}; + +export const flat = { + ios, +}; + +export const nested = { + ios, +}; + +export const withExamples = { + Examples: flat, + ios, +}; + +export const withPods = { + Podfile: 'content', + ios: iosPod, +}; + +export const withoutPods = { + ios, +}; diff --git a/packages/platform-ios/src/config/__tests__/findPodfilePath-test.js b/packages/platform-ios/src/config/__tests__/findPodfilePath-test.js new file mode 100644 index 0000000000..f3da6da8ee --- /dev/null +++ b/packages/platform-ios/src/config/__tests__/findPodfilePath-test.js @@ -0,0 +1,19 @@ +import findPodfilePath from '../findPodfilePath'; +import * as projects from '../__fixtures__/projects'; + +jest.mock('path'); +jest.mock('fs'); + +const fs = require('fs'); + +describe('ios::findPodfilePath', () => { + it('returns null if there is no Podfile', () => { + fs.__setMockFilesystem(projects.withoutPods); + expect(findPodfilePath('')).toBeNull(); + }); + + it('returns Podfile path if it exists', () => { + fs.__setMockFilesystem(projects.withPods); + expect(findPodfilePath('/ios')).toContain('Podfile'); + }); +}); diff --git a/packages/cli/src/tools/__tests__/ios/findPodspecName-test.js b/packages/platform-ios/src/config/__tests__/findPodspec-test.js similarity index 63% rename from packages/cli/src/tools/__tests__/ios/findPodspecName-test.js rename to packages/platform-ios/src/config/__tests__/findPodspec-test.js index a6a5d157eb..16b05b714e 100644 --- a/packages/cli/src/tools/__tests__/ios/findPodspecName-test.js +++ b/packages/platform-ios/src/config/__tests__/findPodspec-test.js @@ -4,31 +4,32 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format - * @emails oncall+javascript_foundation + * @flow */ -import findPodspecName from '../../ios/findPodspecName'; -import projects from '../../__fixtures__/projects'; -import ios from '../../__fixtures__/ios'; +import findPodspec from '../findPodspec'; +import * as projects from '../__fixtures__/projects'; jest.mock('path'); jest.mock('fs'); const fs = require('fs'); -describe('ios::findPodspecName', () => { +describe('ios::findPodspec', () => { it('returns null if there is not podspec file', () => { + // $FlowFixMe fs.__setMockFilesystem(projects.flat); - expect(findPodspecName('')).toBeNull(); + expect(findPodspec('')).toBeNull(); }); it('returns podspec name if only one exists', () => { - fs.__setMockFilesystem(ios.pod); - expect(findPodspecName('/')).toBe('TestPod'); + // $FlowFixMe + fs.__setMockFilesystem(projects.withPods.ios); + expect(findPodspec('/')).toBe('/TestPod.podspec'); }); it('returns podspec name that match packet directory', () => { + // $FlowFixMe fs.__setMockFilesystem({ user: { PacketName: { @@ -37,10 +38,13 @@ describe('ios::findPodspecName', () => { }, }, }); - expect(findPodspecName('/user/PacketName')).toBe('PacketName'); + expect(findPodspec('/user/PacketName')).toBe( + '/user/PacketName/PacketName.podspec', + ); }); it('returns first podspec name if not match in directory', () => { + // $FlowFixMe fs.__setMockFilesystem({ user: { packet: { @@ -49,6 +53,6 @@ describe('ios::findPodspecName', () => { }, }, }); - expect(findPodspecName('/user/packet')).toBe('Another'); + expect(findPodspec('/user/packet')).toBe('/user/packet/Another.podspec'); }); }); diff --git a/packages/cli/src/tools/__tests__/ios/findProject-test.js b/packages/platform-ios/src/config/__tests__/findProject-test.js similarity index 80% rename from packages/cli/src/tools/__tests__/ios/findProject-test.js rename to packages/platform-ios/src/config/__tests__/findProject-test.js index 3f7cd0347f..8c5e029e7d 100644 --- a/packages/cli/src/tools/__tests__/ios/findProject-test.js +++ b/packages/platform-ios/src/config/__tests__/findProject-test.js @@ -8,9 +8,8 @@ * @emails oncall+javascript_foundation */ -import findProject from '../../ios/findProject'; -import projects from '../../__fixtures__/projects'; -import ios from '../../__fixtures__/ios'; +import findProject from '../findProject'; +import * as projects from '../__fixtures__/projects'; jest.mock('path'); jest.mock('fs'); @@ -24,22 +23,17 @@ describe('ios::findProject', () => { }); it('returns null if there are no projects', () => { - fs.__setMockFilesystem({ testDir: projects }); + fs.__setMockFilesystem({testDir: projects}); expect(findProject('/')).toBeNull(); }); - it('returns ios project regardless of its name', () => { - fs.__setMockFilesystem({ ios: ios.validTestName }); - expect(findProject('/')).not.toBeNull(); - }); - it('ignores node_modules', () => { - fs.__setMockFilesystem({ node_modules: projects.flat }); + fs.__setMockFilesystem({node_modules: projects.flat}); expect(findProject('/')).toBeNull(); }); it('ignores Pods', () => { - fs.__setMockFilesystem({ Pods: projects.flat }); + fs.__setMockFilesystem({Pods: projects.flat}); expect(findProject('/')).toBeNull(); }); diff --git a/packages/cli/src/tools/__tests__/ios/getProjectConfig-test.js b/packages/platform-ios/src/config/__tests__/getProjectConfig-test.js similarity index 87% rename from packages/cli/src/tools/__tests__/ios/getProjectConfig-test.js rename to packages/platform-ios/src/config/__tests__/getProjectConfig-test.js index b5cf7c5e96..e804796c3b 100644 --- a/packages/cli/src/tools/__tests__/ios/getProjectConfig-test.js +++ b/packages/platform-ios/src/config/__tests__/getProjectConfig-test.js @@ -8,20 +8,20 @@ * @emails oncall+javascript_foundation */ -import projects from '../../__fixtures__/projects'; +import * as projects from '../__fixtures__/projects'; jest.mock('path'); jest.mock('fs'); const fs = require('fs'); -const getProjectConfig = require('../../ios').projectConfig; +const getProjectConfig = require('../').projectConfig; describe('ios::getProjectConfig', () => { const userConfig = {}; beforeEach(() => { - fs.__setMockFilesystem({ testDir: projects }); + fs.__setMockFilesystem({testDir: projects}); }); it('returns an object with ios project configuration', () => { diff --git a/packages/cli/src/tools/ios/findPodfilePath.js b/packages/platform-ios/src/config/findPodfilePath.js similarity index 84% rename from packages/cli/src/tools/ios/findPodfilePath.js rename to packages/platform-ios/src/config/findPodfilePath.js index bf30d67dea..ab5e47fc7a 100644 --- a/packages/cli/src/tools/ios/findPodfilePath.js +++ b/packages/platform-ios/src/config/findPodfilePath.js @@ -5,12 +5,13 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ import fs from 'fs'; import path from 'path'; -export default function findPodfilePath(projectFolder) { +export default function findPodfilePath(projectFolder: string) { const podFilePath = path.join(projectFolder, '..', 'Podfile'); const podFileExists = fs.existsSync(podFilePath); diff --git a/packages/platform-ios/src/config/findPodspec.js b/packages/platform-ios/src/config/findPodspec.js new file mode 100644 index 0000000000..30ab98d000 --- /dev/null +++ b/packages/platform-ios/src/config/findPodspec.js @@ -0,0 +1,21 @@ +/** + * @flow + */ + +import glob from 'glob'; +import path from 'path'; + +export default function findPodspec(folder: string): string | null { + const podspecs = glob.sync('*.podspec', {cwd: folder}); + + if (podspecs.length === 0) { + return null; + } + + const packagePodspec = path.basename(folder) + '.podspec'; + const podspecFile = podspecs.includes(packagePodspec) + ? packagePodspec + : podspecs[0]; + + return path.join(folder, podspecFile); +} diff --git a/packages/cli/src/tools/ios/findProject.js b/packages/platform-ios/src/config/findProject.js similarity index 92% rename from packages/cli/src/tools/ios/findProject.js rename to packages/platform-ios/src/config/findProject.js index 62715579c0..d798fea24a 100644 --- a/packages/cli/src/tools/ios/findProject.js +++ b/packages/platform-ios/src/config/findProject.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ import glob from 'glob'; @@ -38,7 +39,7 @@ const GLOB_EXCLUDE_PATTERN = ['**/@(Pods|node_modules)/**']; * * Note: `./ios/*.xcodeproj` are returned regardless of the name */ -export default function findProject(folder) { +export default function findProject(folder: string): string | null { const projects = glob .sync(GLOB_PATTERN, { cwd: folder, @@ -46,7 +47,7 @@ export default function findProject(folder) { }) .filter( project => - path.dirname(project) === IOS_BASE || !TEST_PROJECTS.test(project) + path.dirname(project) === IOS_BASE || !TEST_PROJECTS.test(project), ) .sort(project => (path.dirname(project) === IOS_BASE ? -1 : 1)); diff --git a/packages/cli/src/commands/link/commandStub.js b/packages/platform-ios/src/config/getPodspecName.js similarity index 54% rename from packages/cli/src/commands/link/commandStub.js rename to packages/platform-ios/src/config/getPodspecName.js index 4b4cfda060..19fc35fc96 100644 --- a/packages/cli/src/commands/link/commandStub.js +++ b/packages/platform-ios/src/config/getPodspecName.js @@ -4,7 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ +import path from 'path'; -export default cb => cb(); +export default function getPodspecName(podspecFile: string) { + return path.basename(podspecFile).replace(/\.podspec$/, ''); +} diff --git a/packages/cli/src/tools/ios/index.js b/packages/platform-ios/src/config/index.js similarity index 64% rename from packages/cli/src/tools/ios/index.js rename to packages/platform-ios/src/config/index.js index 6e0c537c91..5bf40f7b8e 100644 --- a/packages/cli/src/tools/ios/index.js +++ b/packages/platform-ios/src/config/index.js @@ -5,22 +5,24 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ import path from 'path'; +import {memoize} from 'lodash'; import findProject from './findProject'; import findPodfilePath from './findPodfilePath'; -import findPodspecName from './findPodspecName'; -import linkConfigIos from '../../commands/link/ios'; +import findPodspec from './findPodspec'; +import type {UserConfigT} from 'types'; -export const linkConfig = linkConfigIos; +const memoizedFindProject = memoize(findProject); /** * For libraries specified without an extension, add '.tbd' for those that * start with 'lib' and '.framework' to the rest. */ const mapSharedLibaries = libraries => - libraries.map(name => { + libraries.map(name => { if (path.extname(name)) { return name; } @@ -31,8 +33,14 @@ const mapSharedLibaries = libraries => * Returns project config by analyzing given folder and applying some user defaults * when constructing final object */ -export function projectConfig(folder, userConfig) { - const project = userConfig.project || findProject(folder); +export function projectConfig( + folder: string, + userConfig: $PropertyType<$PropertyType, 'ios'>, +) { + if (!userConfig) { + return; + } + const project = userConfig.project || memoizedFindProject(folder); /** * No iOS config found here @@ -42,13 +50,19 @@ export function projectConfig(folder, userConfig) { } const projectPath = path.join(folder, project); + const sourceDir = path.dirname(projectPath); return { - sourceDir: path.dirname(projectPath), + sourceDir, folder, pbxprojPath: path.join(projectPath, 'project.pbxproj'), podfile: findPodfilePath(projectPath), - podspec: findPodspecName(folder), + podspecPath: + userConfig.podspecPath || + // podspecs are usually placed in the root dir of the library or in the + // iOS project path + findPodspec(folder) || + findPodspec(sourceDir), projectPath, projectName: path.basename(projectPath), libraryFolder: userConfig.libraryFolder || 'Libraries', diff --git a/packages/platform-ios/src/index.js b/packages/platform-ios/src/index.js new file mode 100644 index 0000000000..ced0990f65 --- /dev/null +++ b/packages/platform-ios/src/index.js @@ -0,0 +1,9 @@ +/** + * iOS platform files + * + * @flow + */ + +export {default as linkConfig} from './link'; +export {default as commands} from './commands'; +export {projectConfig, dependencyConfig} from './config'; diff --git a/packages/platform-ios/src/link-pods/__fixtures__/Info.plist b/packages/platform-ios/src/link-pods/__fixtures__/Info.plist new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/commands/link/__fixtures__/pods/PodfileSimple b/packages/platform-ios/src/link-pods/__fixtures__/PodfileSimple similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/pods/PodfileSimple rename to packages/platform-ios/src/link-pods/__fixtures__/PodfileSimple diff --git a/packages/cli/src/commands/link/__fixtures__/pods/PodfileWithFunction b/packages/platform-ios/src/link-pods/__fixtures__/PodfileWithFunction similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/pods/PodfileWithFunction rename to packages/platform-ios/src/link-pods/__fixtures__/PodfileWithFunction diff --git a/packages/cli/src/commands/link/__fixtures__/pods/PodfileWithMarkers b/packages/platform-ios/src/link-pods/__fixtures__/PodfileWithMarkers similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/pods/PodfileWithMarkers rename to packages/platform-ios/src/link-pods/__fixtures__/PodfileWithMarkers diff --git a/packages/cli/src/commands/link/__fixtures__/pods/PodfileWithTarget b/packages/platform-ios/src/link-pods/__fixtures__/PodfileWithTarget similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/pods/PodfileWithTarget rename to packages/platform-ios/src/link-pods/__fixtures__/PodfileWithTarget diff --git a/packages/cli/src/commands/link/__tests__/pods/findLineToAddPod-test.js b/packages/platform-ios/src/link-pods/__tests__/findLineToAddPod-test.js similarity index 71% rename from packages/cli/src/commands/link/__tests__/pods/findLineToAddPod-test.js rename to packages/platform-ios/src/link-pods/__tests__/findLineToAddPod-test.js index df12859371..a3d4e4e46d 100644 --- a/packages/cli/src/commands/link/__tests__/pods/findLineToAddPod-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/findLineToAddPod-test.js @@ -8,42 +8,42 @@ * @emails oncall+javascript_foundation */ -import findLineToAddPod from '../../pods/findLineToAddPod'; -import readPodfile from '../../pods/readPodfile'; +import findLineToAddPod from '../findLineToAddPod'; +import readPodfile from '../readPodfile'; const path = require('path'); -const PODFILES_PATH = path.join(__dirname, '../../__fixtures__/pods'); +const PODFILES_PATH = path.join(__dirname, '../__fixtures__/'); const LINE_AFTER_TARGET_IN_TEST_PODFILE = 4; describe('pods::findLineToAddPod', () => { it('returns null if file is not Podfile', () => { - const podfile = readPodfile(path.join(PODFILES_PATH, '../Info.plist')); + const podfile = readPodfile(path.join(PODFILES_PATH, 'Info.plist')); expect( - findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) + findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), ).toBeNull(); }); it('returns correct line number for Simple Podfile', () => { const podfile = readPodfile(path.join(PODFILES_PATH, 'PodfileSimple')); expect( - findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) - ).toEqual({ line: 7, indentation: 2 }); + findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), + ).toEqual({line: 7, indentation: 2}); }); it('returns correct line number for Podfile with target', () => { const podfile = readPodfile(path.join(PODFILES_PATH, 'PodfileWithTarget')); expect( - findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) - ).toEqual({ line: 21, indentation: 2 }); + findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), + ).toEqual({line: 21, indentation: 2}); }); it('returns correct line number for Podfile with function', () => { const podfile = readPodfile( - path.join(PODFILES_PATH, 'PodfileWithFunction') + path.join(PODFILES_PATH, 'PodfileWithFunction'), ); expect( - findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) - ).toEqual({ line: 26, indentation: 2 }); + findLineToAddPod(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), + ).toEqual({line: 26, indentation: 2}); }); }); diff --git a/packages/cli/src/commands/link/__tests__/pods/findMarkedLinesInPodfile-test.js b/packages/platform-ios/src/link-pods/__tests__/findMarkedLinesInPodfile-test.js similarity index 73% rename from packages/cli/src/commands/link/__tests__/pods/findMarkedLinesInPodfile-test.js rename to packages/platform-ios/src/link-pods/__tests__/findMarkedLinesInPodfile-test.js index 0b5c99eeb9..43b52ecfce 100644 --- a/packages/cli/src/commands/link/__tests__/pods/findMarkedLinesInPodfile-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/findMarkedLinesInPodfile-test.js @@ -8,35 +8,35 @@ * @emails oncall+javascript_foundation */ -import readPodfile from '../../pods/readPodfile'; -import findMarkedLinesInPodfile from '../../pods/findMarkedLinesInPodfile'; +import readPodfile from '../readPodfile'; +import findMarkedLinesInPodfile from '../findMarkedLinesInPodfile'; const path = require('path'); -const PODFILES_PATH = path.join(__dirname, '../../__fixtures__/pods'); +const PODFILES_PATH = path.join(__dirname, '../__fixtures__'); const LINE_AFTER_TARGET_IN_TEST_PODFILE = 4; describe('pods::findMarkedLinesInPodfile', () => { it('returns empty array if file is not Podfile', () => { - const podfile = readPodfile(path.join(PODFILES_PATH, '../Info.plist')); + const podfile = readPodfile(path.join(PODFILES_PATH, 'Info.plist')); expect(findMarkedLinesInPodfile(podfile)).toEqual([]); }); it('returns empty array for Simple Podfile', () => { const podfile = readPodfile(path.join(PODFILES_PATH, 'PodfileSimple')); expect( - findMarkedLinesInPodfile(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) + findMarkedLinesInPodfile(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), ).toEqual([]); }); it('returns correct line numbers for Podfile with marker', () => { const podfile = readPodfile(path.join(PODFILES_PATH, 'PodfileWithMarkers')); const expectedObject = [ - { line: 18, indentation: 2 }, - { line: 31, indentation: 4 }, + {line: 18, indentation: 2}, + {line: 31, indentation: 4}, ]; expect( - findMarkedLinesInPodfile(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE) + findMarkedLinesInPodfile(podfile, LINE_AFTER_TARGET_IN_TEST_PODFILE), ).toEqual(expectedObject); }); }); diff --git a/packages/cli/src/commands/link/__tests__/pods/findPodTargetLine-test.js b/packages/platform-ios/src/link-pods/__tests__/findPodTargetLine-test.js similarity index 77% rename from packages/cli/src/commands/link/__tests__/pods/findPodTargetLine-test.js rename to packages/platform-ios/src/link-pods/__tests__/findPodTargetLine-test.js index 86988fb387..8c45c7871c 100644 --- a/packages/cli/src/commands/link/__tests__/pods/findPodTargetLine-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/findPodTargetLine-test.js @@ -8,16 +8,16 @@ * @emails oncall+javascript_foundation */ -import findPodTargetLine from '../../pods/findPodTargetLine'; -import readPodfile from '../../pods/readPodfile'; +import findPodTargetLine from '../findPodTargetLine'; +import readPodfile from '../readPodfile'; const path = require('path'); -const PODFILES_PATH = path.join(__dirname, '../../__fixtures__/pods'); +const PODFILES_PATH = path.join(__dirname, '../__fixtures__'); describe('pods::findPodTargetLine', () => { it('returns null if file is not Podfile', () => { - const podfile = readPodfile(path.join(PODFILES_PATH, '../Info.plist')); + const podfile = readPodfile(path.join(PODFILES_PATH, 'Info.plist')); expect(findPodTargetLine(podfile, 'name')).toBeNull(); }); diff --git a/packages/cli/src/commands/link/__tests__/pods/isInstalled-test.js b/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js similarity index 61% rename from packages/cli/src/commands/link/__tests__/pods/isInstalled-test.js rename to packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js index 86fa1da48c..2b606b104c 100644 --- a/packages/cli/src/commands/link/__tests__/pods/isInstalled-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js @@ -8,28 +8,28 @@ * @emails oncall+javascript_foundation */ -import isInstalled from '../../pods/isInstalled'; +import isInstalled from '../isInstalled'; const path = require('path'); -const PODFILES_PATH = path.join(__dirname, '../../__fixtures__/pods'); +const PODFILES_PATH = path.join(__dirname, '../__fixtures__/'); describe('pods::isInstalled', () => { it('returns false if pod is missing', () => { - const project = { podfile: path.join(PODFILES_PATH, 'PodfileSimple') }; - const podspecName = { podspec: 'NotExisting' }; + const project = {podfile: path.join(PODFILES_PATH, 'PodfileSimple')}; + const podspecName = {podspecPath: '/path/NotExisting'}; expect(isInstalled(project, podspecName)).toBe(false); }); it('returns true for existing pod with version number', () => { - const project = { podfile: path.join(PODFILES_PATH, 'PodfileSimple') }; - const podspecName = { podspec: 'TestPod' }; + const project = {podfile: path.join(PODFILES_PATH, 'PodfileSimple')}; + const podspecName = {podspecPath: '/path/TestPod.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); it('returns true for existing pod with path', () => { - const project = { podfile: path.join(PODFILES_PATH, 'PodfileWithTarget') }; - const podspecName = { podspec: 'Yoga' }; + const project = {podfile: path.join(PODFILES_PATH, 'PodfileWithTarget')}; + const podspecName = {podspecPath: '/path/Yoga.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); @@ -37,7 +37,7 @@ describe('pods::isInstalled', () => { const project = { podfile: path.join(PODFILES_PATH, 'PodfileWithFunction'), }; - const podspecName = { podspec: 'React' }; + const podspecName = {podspecPath: '/path/React.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); }); diff --git a/packages/cli/src/commands/link/__tests__/pods/removePodEntry-test.js b/packages/platform-ios/src/link-pods/__tests__/removePodEntry-test.js similarity index 75% rename from packages/cli/src/commands/link/__tests__/pods/removePodEntry-test.js rename to packages/platform-ios/src/link-pods/__tests__/removePodEntry-test.js index a403c47760..525fc04224 100644 --- a/packages/cli/src/commands/link/__tests__/pods/removePodEntry-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/removePodEntry-test.js @@ -8,24 +8,24 @@ * @emails oncall+javascript_foundation */ -import removePodEntry from '../../pods/removePodEntry'; -import readPodfile from '../../pods/readPodfile'; +import removePodEntry from '../removePodEntry'; +import readPodfile from '../readPodfile'; const path = require('path'); -const PODFILES_PATH = path.join(__dirname, '../../__fixtures__/pods'); +const PODFILES_PATH = path.join(__dirname, '../__fixtures__/'); describe('pods::removePodEntry', () => { it('should remove one line from Podfile with TestPod', () => { - const { podfileContent, podLinesCount } = readTestPodFile('PodfileSimple'); + const {podfileContent, podLinesCount} = readTestPodFile('PodfileSimple'); const podFileWithRemoved = removePodEntry(podfileContent, 'TestPod'); const newLineCount = podFileWithRemoved.split('\n').length; expect(newLineCount).toBe(podLinesCount - 1); }); it('should remove one line from Podfile with Yoga', () => { - const { podfileContent, podLinesCount } = readTestPodFile( - 'PodfileWithTarget' + const {podfileContent, podLinesCount} = readTestPodFile( + 'PodfileWithTarget', ); const podFileWithRemoved = removePodEntry(podfileContent, 'Yoga'); const newLineCount = podFileWithRemoved.split('\n').length; @@ -33,8 +33,8 @@ describe('pods::removePodEntry', () => { }); it('should remove whole reference to React pod from Podfile', () => { - const { podfileContent, podLinesCount } = readTestPodFile( - 'PodfileWithTarget' + const {podfileContent, podLinesCount} = readTestPodFile( + 'PodfileWithTarget', ); const podFileWithRemoved = removePodEntry(podfileContent, 'React'); const newLineCount = podFileWithRemoved.split('\n').length; diff --git a/packages/cli/src/commands/link/pods/addPodEntry.js b/packages/platform-ios/src/link-pods/addPodEntry.js similarity index 51% rename from packages/cli/src/commands/link/pods/addPodEntry.js rename to packages/platform-ios/src/link-pods/addPodEntry.js index 45b33f275f..86d327feb0 100644 --- a/packages/cli/src/commands/link/pods/addPodEntry.js +++ b/packages/platform-ios/src/link-pods/addPodEntry.js @@ -4,27 +4,35 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ +import {logger} from '@react-native-community/cli-tools'; +import getPodspecName from '../config/getPodspecName'; + export default function addPodEntry( - podLines, - linesToAddEntry, - podName, - nodePath + podLines: Array, + linesToAddEntry?: + | Array<{line: number, indentation: number}> + | {line: number, indentation: number}, + podspecPath: string, + nodeModulePath: string, ) { - const newEntry = `pod '${podName}', :path => '../node_modules/${nodePath}'\n`; + const podName = getPodspecName(podspecPath); + const newEntry = `pod '${podName}', :path => '../node_modules/${nodeModulePath}'\n`; if (!linesToAddEntry) { return; } if (Array.isArray(linesToAddEntry)) { - linesToAddEntry.map(({ line, indentation }, idx) => - podLines.splice(line + idx, 0, getLineToAdd(newEntry, indentation)) - ); + linesToAddEntry.map(({line, indentation}, idx) => { + logger.debug(`Adding ${podName} to Pod file"`); + podLines.splice(line + idx, 0, getLineToAdd(newEntry, indentation)); + }); } else { - const { line, indentation } = linesToAddEntry; + const {line, indentation} = linesToAddEntry; + logger.debug(`Adding ${podName} to Pod file"`); podLines.splice(line, 0, getLineToAdd(newEntry, indentation)); } } diff --git a/packages/cli/src/commands/link/pods/findLineToAddPod.js b/packages/platform-ios/src/link-pods/findLineToAddPod.js similarity index 94% rename from packages/cli/src/commands/link/pods/findLineToAddPod.js rename to packages/platform-ios/src/link-pods/findLineToAddPod.js index 9f7a4c61a3..691a6629c5 100644 --- a/packages/cli/src/commands/link/pods/findLineToAddPod.js +++ b/packages/platform-ios/src/link-pods/findLineToAddPod.js @@ -15,7 +15,7 @@ export default function findLineToAddPod(podLines, firstTargetLine) { // match function definition, like: post_install do |installer| (some Podfiles have function defined inside main target const functionDefinition = /^\s*[a-z_]+\s+do(\s+\|[a-z]+\|)?/g; - for (let i = firstTargetLine, len = podLines.length; i < len; i++) { + for (let i = firstTargetLine; i < podLines.length - 1; i++) { const matchNextConstruct = podLines[i].match(nextTarget) || podLines[i].match(functionDefinition); const matchEnd = podLines[i].match(endOfCurrentTarget); diff --git a/packages/cli/src/commands/link/pods/findMarkedLinesInPodfile.js b/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js similarity index 61% rename from packages/cli/src/commands/link/pods/findMarkedLinesInPodfile.js rename to packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js index c162a59a7c..13cae2c147 100644 --- a/packages/cli/src/commands/link/pods/findMarkedLinesInPodfile.js +++ b/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js @@ -4,16 +4,16 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ -const MARKER_TEXT = '# Add new pods below this line'; +export const MARKER_TEXT = '# Add new pods below this line'; -export default function findMarkedLinesInPodfile(podLines) { +export default function findMarkedLinesInPodfile(podLines: Array) { const result = []; for (let i = 0, len = podLines.length; i < len; i++) { if (podLines[i].includes(MARKER_TEXT)) { - result.push({ line: i + 1, indentation: podLines[i].indexOf('#') }); + result.push({line: i + 1, indentation: podLines[i].indexOf('#')}); } } return result; diff --git a/packages/cli/src/commands/link/pods/findPodTargetLine.js b/packages/platform-ios/src/link-pods/findPodTargetLine.js similarity index 100% rename from packages/cli/src/commands/link/pods/findPodTargetLine.js rename to packages/platform-ios/src/link-pods/findPodTargetLine.js diff --git a/packages/cli/src/commands/link/pods/isInstalled.js b/packages/platform-ios/src/link-pods/isInstalled.js similarity index 62% rename from packages/cli/src/commands/link/pods/isInstalled.js rename to packages/platform-ios/src/link-pods/isInstalled.js index 312cc4eeec..caf97eb710 100644 --- a/packages/cli/src/commands/link/pods/isInstalled.js +++ b/packages/platform-ios/src/link-pods/isInstalled.js @@ -4,19 +4,24 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import readPodfile from './readPodfile'; +import getPodspecName from '../config/getPodspecName'; +import type {ProjectConfigIOST, DependencyConfigIOST} from 'types'; -export default function isInstalled(iOSProject, dependencyConfig) { - if (!iOSProject.podfile) { +export default function isInstalled( + iOSProject: ProjectConfigIOST, + dependencyConfig: DependencyConfigIOST, +) { + if (!iOSProject.podfile || !dependencyConfig.podspecPath) { return false; } // match line with pod declaration: pod 'dependencyPodName' (other possible parameters of pod are ignored) const dependencyRegExp = new RegExp( - `pod\\s+('|")${dependencyConfig.podspec}('|")`, - 'g' + `pod\\s+('|")${getPodspecName(dependencyConfig.podspecPath)}('|")`, + 'g', ); const podLines = readPodfile(iOSProject.podfile); for (let i = 0, len = podLines.length; i < len; i++) { diff --git a/packages/cli/src/commands/link/pods/readPodfile.js b/packages/platform-ios/src/link-pods/readPodfile.js similarity index 78% rename from packages/cli/src/commands/link/pods/readPodfile.js rename to packages/platform-ios/src/link-pods/readPodfile.js index 42fc6be4aa..ab613e2e0a 100644 --- a/packages/cli/src/commands/link/pods/readPodfile.js +++ b/packages/platform-ios/src/link-pods/readPodfile.js @@ -8,8 +8,10 @@ */ import fs from 'fs'; +import {logger} from '@react-native-community/cli-tools'; export default function readPodfile(podfilePath) { + logger.debug(`Reading ${podfilePath}`); const podContent = fs.readFileSync(podfilePath, 'utf8'); return podContent.split(/\r?\n/g); } diff --git a/packages/cli/src/commands/link/pods/registerNativeModule.js b/packages/platform-ios/src/link-pods/registerNativeModule.js similarity index 52% rename from packages/cli/src/commands/link/pods/registerNativeModule.js rename to packages/platform-ios/src/link-pods/registerNativeModule.js index 5e3ffb9760..4cbb21ba6c 100644 --- a/packages/cli/src/commands/link/pods/registerNativeModule.js +++ b/packages/platform-ios/src/link-pods/registerNativeModule.js @@ -4,32 +4,50 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ - +import chalk from 'chalk'; +import {CLIError} from '@react-native-community/cli-tools'; +import type {ProjectConfigIOST} from 'types'; import readPodfile from './readPodfile'; import findPodTargetLine from './findPodTargetLine'; import findLineToAddPod from './findLineToAddPod'; -import findMarkedLinesInPodfile from './findMarkedLinesInPodfile'; +import findMarkedLinesInPodfile, { + MARKER_TEXT, +} from './findMarkedLinesInPodfile'; import addPodEntry from './addPodEntry'; import savePodFile from './savePodFile'; export default function registerNativeModulePods( - name, - dependencyConfig, - iOSProject + name: string, + podspecPath: string, + iOSProject: ProjectConfigIOST, ) { const podLines = readPodfile(iOSProject.podfile); const linesToAddEntry = getLinesToAddEntry(podLines, iOSProject); - addPodEntry(podLines, linesToAddEntry, dependencyConfig.podspec, name); + addPodEntry(podLines, linesToAddEntry, podspecPath, name); savePodFile(iOSProject.podfile, podLines); } -function getLinesToAddEntry(podLines, { projectName }) { +function getLinesToAddEntry(podLines, {projectName}) { const linesToAddPodWithMarker = findMarkedLinesInPodfile(podLines); if (linesToAddPodWithMarker.length > 0) { return linesToAddPodWithMarker; } const firstTargetLined = findPodTargetLine(podLines, projectName); + if (firstTargetLined === null) { + throw new CLIError(` + We couldn't find a target to add a CocoaPods dependency. + + Make sure that you have a "${chalk.dim( + `target '${projectName.replace('.xcodeproj', '')}' do`, + )}" line in your Podfile. + + Alternatively, include "${chalk.dim( + MARKER_TEXT, + )}" in a Podfile where we should add + linked dependencies. + `); + } return findLineToAddPod(podLines, firstTargetLined); } diff --git a/packages/cli/src/commands/link/pods/removePodEntry.js b/packages/platform-ios/src/link-pods/removePodEntry.js similarity index 65% rename from packages/cli/src/commands/link/pods/removePodEntry.js rename to packages/platform-ios/src/link-pods/removePodEntry.js index 8a0fd00410..7ee8f9eea7 100644 --- a/packages/cli/src/commands/link/pods/removePodEntry.js +++ b/packages/platform-ios/src/link-pods/removePodEntry.js @@ -7,11 +7,16 @@ * @format */ -export default function removePodEntry(podfileContent, podName) { +import {logger} from '@react-native-community/cli-tools'; +import getPodspecName from '../config/getPodspecName'; + +export default function removePodEntry(podfileContent, podspecPath) { + const podName = getPodspecName(podspecPath); // this regex should catch line(s) with full pod definition, like: pod 'podname', :path => '../node_modules/podname', :subspecs => ['Sub2', 'Sub1'] const podRegex = new RegExp( `\\n( |\\t)*pod\\s+("|')${podName}("|')(,\\s*(:[a-z]+\\s*=>)?\\s*(("|').*?("|')|\\[[\\s\\S]*?\\]))*\\n`, - 'g' + 'g', ); + logger.debug(`Removing ${podName} from Pod file`); return podfileContent.replace(podRegex, '\n'); } diff --git a/packages/cli/src/commands/link/pods/savePodFile.js b/packages/platform-ios/src/link-pods/savePodFile.js similarity index 77% rename from packages/cli/src/commands/link/pods/savePodFile.js rename to packages/platform-ios/src/link-pods/savePodFile.js index 5148cc7749..aca3838670 100644 --- a/packages/cli/src/commands/link/pods/savePodFile.js +++ b/packages/platform-ios/src/link-pods/savePodFile.js @@ -8,8 +8,10 @@ */ import fs from 'fs'; +import {logger} from '@react-native-community/cli-tools'; export default function savePodFile(podfilePath, podLines) { const newPodfile = podLines.join('\n'); + logger.debug(`Writing changes to ${podfilePath}`); fs.writeFileSync(podfilePath, newPodfile); } diff --git a/packages/cli/src/commands/link/pods/unregisterNativeModule.js b/packages/platform-ios/src/link-pods/unregisterNativeModule.js similarity index 81% rename from packages/cli/src/commands/link/pods/unregisterNativeModule.js rename to packages/platform-ios/src/link-pods/unregisterNativeModule.js index 9e42b5e6fa..6ac7ca71d8 100644 --- a/packages/cli/src/commands/link/pods/unregisterNativeModule.js +++ b/packages/platform-ios/src/link-pods/unregisterNativeModule.js @@ -9,12 +9,14 @@ import fs from 'fs'; import removePodEntry from './removePodEntry'; +import {logger} from '@react-native-community/cli-tools'; /** * Unregister native module IOS with CocoaPods */ export default function unregisterNativeModule(dependencyConfig, iOSProject) { const podContent = fs.readFileSync(iOSProject.podfile, 'utf8'); - const removed = removePodEntry(podContent, dependencyConfig.podspec); + const removed = removePodEntry(podContent, dependencyConfig.podspecPath); + logger.debug(`Writing changes to ${iOSProject.podfile}`); fs.writeFileSync(iOSProject.podfile, removed); } diff --git a/packages/cli/src/commands/link/__fixtures__/Info.plist b/packages/platform-ios/src/link/__fixtures__/Info.plist similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/Info.plist rename to packages/platform-ios/src/link/__fixtures__/Info.plist diff --git a/packages/cli/src/commands/link/__fixtures__/linearGradient.pbxproj b/packages/platform-ios/src/link/__fixtures__/linearGradient.pbxproj similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/linearGradient.pbxproj rename to packages/platform-ios/src/link/__fixtures__/linearGradient.pbxproj diff --git a/packages/cli/src/commands/link/__fixtures__/project.pbxproj b/packages/platform-ios/src/link/__fixtures__/project.pbxproj similarity index 100% rename from packages/cli/src/commands/link/__fixtures__/project.pbxproj rename to packages/platform-ios/src/link/__fixtures__/project.pbxproj diff --git a/packages/cli/src/commands/link/__tests__/ios/addFileToProject-test.js b/packages/platform-ios/src/link/__tests__/addFileToProject-test.js similarity index 74% rename from packages/cli/src/commands/link/__tests__/ios/addFileToProject-test.js rename to packages/platform-ios/src/link/__tests__/addFileToProject-test.js index 05366ae809..100f384fb2 100644 --- a/packages/cli/src/commands/link/__tests__/ios/addFileToProject-test.js +++ b/packages/platform-ios/src/link/__tests__/addFileToProject-test.js @@ -8,14 +8,14 @@ * @emails oncall+javascript_foundation */ -import addFileToProject from '../../ios/addFileToProject'; +import addFileToProject from '../addFileToProject'; const xcode = require('xcode'); const path = require('path'); const _ = require('lodash'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::addFileToProject', () => { @@ -24,12 +24,12 @@ describe('ios::addFileToProject', () => { }); it('should add file to a project', () => { - const { fileRef } = addFileToProject( + const {fileRef} = addFileToProject( project, - '../../__fixtures__/linearGradient.pbxproj' + '../__fixtures__/linearGradient.pbxproj', ); expect( - _.includes(Object.keys(project.pbxFileReferenceSection()), fileRef) + _.includes(Object.keys(project.pbxFileReferenceSection()), fileRef), ).toBeTruthy(); }); }); diff --git a/packages/cli/src/commands/link/__tests__/ios/addProjectToLibraries-test.js b/packages/platform-ios/src/link/__tests__/addProjectToLibraries-test.js similarity index 82% rename from packages/cli/src/commands/link/__tests__/ios/addProjectToLibraries-test.js rename to packages/platform-ios/src/link/__tests__/addProjectToLibraries-test.js index 294195d3fa..c6c173ec6e 100644 --- a/packages/cli/src/commands/link/__tests__/ios/addProjectToLibraries-test.js +++ b/packages/platform-ios/src/link/__tests__/addProjectToLibraries-test.js @@ -8,15 +8,15 @@ * @emails oncall+javascript_foundation */ -import addProjectToLibraries from '../../ios/addProjectToLibraries'; +import addProjectToLibraries from '../addProjectToLibraries'; const xcode = require('xcode'); const path = require('path'); const PbxFile = require('xcode/lib/pbxFile'); -const { last } = require('lodash'); +const {last} = require('lodash'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::addProjectToLibraries', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/addSharedLibraries-test.js b/packages/platform-ios/src/link/__tests__/addSharedLibraries-test.js similarity index 89% rename from packages/cli/src/commands/link/__tests__/ios/addSharedLibraries-test.js rename to packages/platform-ios/src/link/__tests__/addSharedLibraries-test.js index c1742a4a48..9ce7e1a97d 100644 --- a/packages/cli/src/commands/link/__tests__/ios/addSharedLibraries-test.js +++ b/packages/platform-ios/src/link/__tests__/addSharedLibraries-test.js @@ -8,14 +8,14 @@ * @emails oncall+javascript_foundation */ -import addSharedLibraries from '../../ios/addSharedLibraries'; -import getGroup from '../../ios/getGroup'; +import addSharedLibraries from '../addSharedLibraries'; +import getGroup from '../getGroup'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::addSharedLibraries', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/createGroup-test.js b/packages/platform-ios/src/link/__tests__/createGroup-test.js similarity index 88% rename from packages/cli/src/commands/link/__tests__/ios/createGroup-test.js rename to packages/platform-ios/src/link/__tests__/createGroup-test.js index 924d2731ef..e23f2232fa 100644 --- a/packages/cli/src/commands/link/__tests__/ios/createGroup-test.js +++ b/packages/platform-ios/src/link/__tests__/createGroup-test.js @@ -8,15 +8,15 @@ * @emails oncall+javascript_foundation */ -import createGroup from '../../ios/createGroup'; -import getGroup from '../../ios/getGroup'; +import createGroup from '../createGroup'; +import getGroup from '../getGroup'; const xcode = require('xcode'); const path = require('path'); -const { last } = require('lodash'); +const {last} = require('lodash'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::createGroup', () => { @@ -49,7 +49,7 @@ describe('ios::createGroup', () => { const mainGroup = getGroup(project); expect( - mainGroup.children.filter(group => group.comment === 'Libraries') + mainGroup.children.filter(group => group.comment === 'Libraries'), ).toHaveLength(1); expect(last(outerGroup.children).comment).toBe(createdGroup.name); }); diff --git a/packages/cli/src/commands/link/__tests__/ios/getBuildProperty-test.js b/packages/platform-ios/src/link/__tests__/getBuildProperty-test.js similarity index 83% rename from packages/cli/src/commands/link/__tests__/ios/getBuildProperty-test.js rename to packages/platform-ios/src/link/__tests__/getBuildProperty-test.js index ca42a07be1..8b009acd19 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getBuildProperty-test.js +++ b/packages/platform-ios/src/link/__tests__/getBuildProperty-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import getBuildProperty from '../../ios/getBuildProperty'; +import getBuildProperty from '../getBuildProperty'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::getBuildProperty', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/getGroup-test.js b/packages/platform-ios/src/link/__tests__/getGroup-test.js similarity index 92% rename from packages/cli/src/commands/link/__tests__/ios/getGroup-test.js rename to packages/platform-ios/src/link/__tests__/getGroup-test.js index 0312036c61..00aa02049e 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getGroup-test.js +++ b/packages/platform-ios/src/link/__tests__/getGroup-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import getGroup from '../../ios/getGroup'; +import getGroup from '../getGroup'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::getGroup', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/getHeaderSearchPath-test.js b/packages/platform-ios/src/link/__tests__/getHeaderSearchPath-test.js similarity index 89% rename from packages/cli/src/commands/link/__tests__/ios/getHeaderSearchPath-test.js rename to packages/platform-ios/src/link/__tests__/getHeaderSearchPath-test.js index 15860797e1..60e3285286 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getHeaderSearchPath-test.js +++ b/packages/platform-ios/src/link/__tests__/getHeaderSearchPath-test.js @@ -8,7 +8,7 @@ * @emails oncall+javascript_foundation */ -import getHeaderSearchPath from '../../ios/getHeaderSearchPath'; +import getHeaderSearchPath from '../getHeaderSearchPath'; const path = require('path'); @@ -24,7 +24,7 @@ describe('ios::getHeaderSearchPath', () => { 'react-native-project', 'node_modules', 'package', - 'Gradient.h' + 'Gradient.h', ), path.join('react-native-project', 'node_modules', 'package', 'Manager.h'), ]; @@ -32,7 +32,7 @@ describe('ios::getHeaderSearchPath', () => { const searchPath = getHeaderSearchPath(SRC_DIR, files); expect(searchPath).toBe( - `"${['$(SRCROOT)', '..', 'node_modules', 'package'].join(path.sep)}"` + `"${['$(SRCROOT)', '..', 'node_modules', 'package'].join(path.sep)}"`, ); }); @@ -47,7 +47,7 @@ describe('ios::getHeaderSearchPath', () => { 'package', 'src', 'folderA', - 'Gradient.h' + 'Gradient.h', ), path.join( 'react-native-project', @@ -55,7 +55,7 @@ describe('ios::getHeaderSearchPath', () => { 'package', 'src', 'folderB', - 'Manager.h' + 'Manager.h', ), ]; @@ -63,8 +63,8 @@ describe('ios::getHeaderSearchPath', () => { expect(searchPath).toBe( `"${['$(SRCROOT)', '..', 'node_modules', 'package', 'src'].join( - path.sep - )}/**"` + path.sep, + )}/**"`, ); }); @@ -79,7 +79,7 @@ describe('ios::getHeaderSearchPath', () => { 'package', 'src', 'folderA', - 'Gradient.h' + 'Gradient.h', ), path.join( 'react-native-project', @@ -87,14 +87,14 @@ describe('ios::getHeaderSearchPath', () => { 'package', 'src', 'folderB', - 'Manager.h' + 'Manager.h', ), path.join( 'react-native-project', 'node_modules', 'package', 'src', - 'Manager.h' + 'Manager.h', ), ]; @@ -102,8 +102,8 @@ describe('ios::getHeaderSearchPath', () => { expect(searchPath).toBe( `"${['$(SRCROOT)', '..', 'node_modules', 'package', 'src'].join( - path.sep - )}/**"` + path.sep, + )}/**"`, ); }); }); diff --git a/packages/cli/src/commands/link/__tests__/ios/getHeadersInFolder-test.js b/packages/platform-ios/src/link/__tests__/getHeadersInFolder-test.js similarity index 94% rename from packages/cli/src/commands/link/__tests__/ios/getHeadersInFolder-test.js rename to packages/platform-ios/src/link/__tests__/getHeadersInFolder-test.js index e356341b12..e55a46f1b1 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getHeadersInFolder-test.js +++ b/packages/platform-ios/src/link/__tests__/getHeadersInFolder-test.js @@ -8,10 +8,11 @@ * @emails oncall+javascript_foundation */ -import getHeadersInFolder from '../../ios/getHeadersInFolder'; +import getHeadersInFolder from '../getHeadersInFolder'; jest.mock('fs'); jest.mock('path'); + const fs = require('fs'); const ROOT_DIR = '/'; diff --git a/packages/cli/src/commands/link/__tests__/ios/getPlist-test.js b/packages/platform-ios/src/link/__tests__/getPlist-test.js similarity index 85% rename from packages/cli/src/commands/link/__tests__/ios/getPlist-test.js rename to packages/platform-ios/src/link/__tests__/getPlist-test.js index aa92dae2d3..1bfa611b5d 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getPlist-test.js +++ b/packages/platform-ios/src/link/__tests__/getPlist-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import getPlist from '../../ios/getPlist'; +import getPlist from '../getPlist'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::getPlist', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/getPlistPath-test.js b/packages/platform-ios/src/link/__tests__/getPlistPath-test.js similarity index 84% rename from packages/cli/src/commands/link/__tests__/ios/getPlistPath-test.js rename to packages/platform-ios/src/link/__tests__/getPlistPath-test.js index f5fa6c6b6d..8a88f869f6 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getPlistPath-test.js +++ b/packages/platform-ios/src/link/__tests__/getPlistPath-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import getPlistPath from '../../ios/getPlistPath'; +import getPlistPath from '../getPlistPath'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::getPlistPath', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/getTargets-test.js b/packages/platform-ios/src/link/__tests__/getTargets-test.js similarity index 86% rename from packages/cli/src/commands/link/__tests__/ios/getTargets-test.js rename to packages/platform-ios/src/link/__tests__/getTargets-test.js index aad25bf60c..de704e6c53 100644 --- a/packages/cli/src/commands/link/__tests__/ios/getTargets-test.js +++ b/packages/platform-ios/src/link/__tests__/getTargets-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import getTargets from '../../ios/getTargets'; +import getTargets from '../getTargets'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::getTargets', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/hasLibraryImported-test.js b/packages/platform-ios/src/link/__tests__/hasLibraryImported-test.js similarity index 87% rename from packages/cli/src/commands/link/__tests__/ios/hasLibraryImported-test.js rename to packages/platform-ios/src/link/__tests__/hasLibraryImported-test.js index 80ba7f8df2..1256040cc7 100644 --- a/packages/cli/src/commands/link/__tests__/ios/hasLibraryImported-test.js +++ b/packages/platform-ios/src/link/__tests__/hasLibraryImported-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import hasLibraryImported from '../../ios/hasLibraryImported'; +import hasLibraryImported from '../hasLibraryImported'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::hasLibraryImported', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/isInstalled-test.js b/packages/platform-ios/src/link/__tests__/isInstalled-test.js similarity index 74% rename from packages/cli/src/commands/link/__tests__/ios/isInstalled-test.js rename to packages/platform-ios/src/link/__tests__/isInstalled-test.js index d8ca549b0a..65757214e4 100644 --- a/packages/cli/src/commands/link/__tests__/ios/isInstalled-test.js +++ b/packages/platform-ios/src/link/__tests__/isInstalled-test.js @@ -8,28 +8,28 @@ * @emails oncall+javascript_foundation */ -import isInstalled from '../../ios/isInstalled'; +import isInstalled from '../isInstalled'; const path = require('path'); const baseProjectConfig = { - pbxprojPath: path.join(__dirname, '../../__fixtures__/project.pbxproj'), + pbxprojPath: path.join(__dirname, '../__fixtures__/project.pbxproj'), libraryFolder: 'Libraries', }; describe('ios::isInstalled', () => { it('should return true when .xcodeproj in Libraries', () => { - const dependencyConfig = { projectName: 'React.xcodeproj' }; + const dependencyConfig = {projectName: 'React.xcodeproj'}; expect(isInstalled(baseProjectConfig, dependencyConfig)).toBeTruthy(); }); it('should return false when .xcodeproj not in Libraries', () => { - const dependencyConfig = { projectName: 'Missing.xcodeproj' }; + const dependencyConfig = {projectName: 'Missing.xcodeproj'}; expect(isInstalled(baseProjectConfig, dependencyConfig)).toBeFalsy(); }); it('should return false when `LibraryFolder` is missing', () => { - const dependencyConfig = { projectName: 'React.xcodeproj' }; + const dependencyConfig = {projectName: 'React.xcodeproj'}; const projectConfig = Object.assign({}, baseProjectConfig, { libraryFolder: 'Missing', }); diff --git a/packages/cli/src/commands/link/__tests__/ios/mapHeaderSearchPaths-test.js b/packages/platform-ios/src/link/__tests__/mapHeaderSearchPaths-test.js similarity index 89% rename from packages/cli/src/commands/link/__tests__/ios/mapHeaderSearchPaths-test.js rename to packages/platform-ios/src/link/__tests__/mapHeaderSearchPaths-test.js index d0bbe75a12..1d55ff318d 100644 --- a/packages/cli/src/commands/link/__tests__/ios/mapHeaderSearchPaths-test.js +++ b/packages/platform-ios/src/link/__tests__/mapHeaderSearchPaths-test.js @@ -8,13 +8,13 @@ * @emails oncall+javascript_foundation */ -import mapHeaderSearchPaths from '../../ios/mapHeaderSearchPaths'; +import mapHeaderSearchPaths from '../mapHeaderSearchPaths'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::mapHeaderSearchPaths', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/removeProjectFromLibraries-test.js b/packages/platform-ios/src/link/__tests__/removeProjectFromLibraries-test.js similarity index 76% rename from packages/cli/src/commands/link/__tests__/ios/removeProjectFromLibraries-test.js rename to packages/platform-ios/src/link/__tests__/removeProjectFromLibraries-test.js index 4e06f59b4e..62c5ae58b1 100644 --- a/packages/cli/src/commands/link/__tests__/ios/removeProjectFromLibraries-test.js +++ b/packages/platform-ios/src/link/__tests__/removeProjectFromLibraries-test.js @@ -8,16 +8,16 @@ * @emails oncall+javascript_foundation */ -import addProjectToLibraries from '../../ios/addProjectToLibraries'; -import removeProjectFromLibraries from '../../ios/removeProjectFromLibraries'; +import addProjectToLibraries from '../addProjectToLibraries'; +import removeProjectFromLibraries from '../removeProjectFromLibraries'; const xcode = require('xcode'); const PbxFile = require('xcode/lib/pbxFile'); const path = require('path'); -const { last } = require('lodash'); +const {last} = require('lodash'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::removeProjectFromLibraries', () => { @@ -26,7 +26,7 @@ describe('ios::removeProjectFromLibraries', () => { addProjectToLibraries( project.pbxGroupByName('Libraries'), - new PbxFile('fakePath') + new PbxFile('fakePath'), ); }); diff --git a/packages/cli/src/commands/link/__tests__/ios/removeProjectFromProject-test.js b/packages/platform-ios/src/link/__tests__/removeProjectFromProject-test.js similarity index 79% rename from packages/cli/src/commands/link/__tests__/ios/removeProjectFromProject-test.js rename to packages/platform-ios/src/link/__tests__/removeProjectFromProject-test.js index c0eb81af7e..1a537395d6 100644 --- a/packages/cli/src/commands/link/__tests__/ios/removeProjectFromProject-test.js +++ b/packages/platform-ios/src/link/__tests__/removeProjectFromProject-test.js @@ -8,17 +8,17 @@ * @emails oncall+javascript_foundation */ -import addFileToProject from '../../ios/addFileToProject'; -import removeProjectFromProject from '../../ios/removeProjectFromProject'; +import addFileToProject from '../addFileToProject'; +import removeProjectFromProject from '../removeProjectFromProject'; const xcode = require('xcode'); const pbxFile = require('xcode/lib/pbxFile'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); -const filePath = '../../__fixtures__/linearGradient.pbxproj'; +const filePath = '../__fixtures__/linearGradient.pbxproj'; describe('ios::addFileToProject', () => { beforeEach(() => { @@ -28,7 +28,7 @@ describe('ios::addFileToProject', () => { it('should return removed file', () => { expect( - removeProjectFromProject(project, filePath) instanceof pbxFile + removeProjectFromProject(project, filePath) instanceof pbxFile, ).toBeTruthy(); }); diff --git a/packages/cli/src/commands/link/__tests__/ios/removeSharedLibrary-test.js b/packages/platform-ios/src/link/__tests__/removeSharedLibrary-test.js similarity index 81% rename from packages/cli/src/commands/link/__tests__/ios/removeSharedLibrary-test.js rename to packages/platform-ios/src/link/__tests__/removeSharedLibrary-test.js index f23ceeee17..edfd00cfe2 100644 --- a/packages/cli/src/commands/link/__tests__/ios/removeSharedLibrary-test.js +++ b/packages/platform-ios/src/link/__tests__/removeSharedLibrary-test.js @@ -8,15 +8,15 @@ * @emails oncall+javascript_foundation */ -import addSharedLibraries from '../../ios/addSharedLibraries'; -import removeSharedLibraries from '../../ios/removeSharedLibraries'; -import getGroup from '../../ios/getGroup'; +import addSharedLibraries from '../addSharedLibraries'; +import removeSharedLibraries from '../removeSharedLibraries'; +import getGroup from '../getGroup'; const xcode = require('xcode'); const path = require('path'); const project = xcode.project( - path.join(__dirname, '../../__fixtures__/project.pbxproj') + path.join(__dirname, '../__fixtures__/project.pbxproj'), ); describe('ios::removeSharedLibraries', () => { diff --git a/packages/cli/src/commands/link/__tests__/ios/writePlist-test.js b/packages/platform-ios/src/link/__tests__/writePlist-test.js similarity index 75% rename from packages/cli/src/commands/link/__tests__/ios/writePlist-test.js rename to packages/platform-ios/src/link/__tests__/writePlist-test.js index e10077a99b..8fcf37c5fd 100644 --- a/packages/cli/src/commands/link/__tests__/ios/writePlist-test.js +++ b/packages/platform-ios/src/link/__tests__/writePlist-test.js @@ -8,28 +8,25 @@ * @emails oncall+javascript_foundation */ -import getPlistPath from '../../ios/getPlistPath'; -import writePlist from '../../ios/writePlist'; +import getPlistPath from '../getPlistPath'; +import writePlist from '../writePlist'; jest.mock('path'); jest.mock('fs'); -jest.mock('../../ios/getPlistPath', () => jest.fn(() => null)); +jest.mock('../getPlistPath', () => jest.fn(() => null)); -const { readFileSync } = jest.requireActual('fs'); +const {readFileSync} = jest.requireActual('fs'); const fs = require('fs'); const xcode = require('xcode'); const realPath = jest.requireActual('path'); -const projectPath = realPath.join( - __dirname, - '../../__fixtures__/project.pbxproj' -); -const infoPlistPath = realPath.join(__dirname, '../../__fixtures__/Info.plist'); +const projectPath = realPath.join(__dirname, '../__fixtures__/project.pbxproj'); +const infoPlistPath = realPath.join(__dirname, '../__fixtures__/Info.plist'); fs.readFileSync = jest.fn(() => readFileSync(projectPath).toString()); -const { writeFileSync } = fs; +const {writeFileSync} = fs; fs.writeFileSync = jest.fn(writeFileSync); const project = xcode.project('/Basic/project.pbxproj'); @@ -51,7 +48,7 @@ describe('ios::writePlist', () => { const infoPlist = readFileSync(infoPlistPath).toString(); expect(fs.writeFileSync).toHaveBeenCalledWith( '/Basic/Info.plist', - infoPlist + infoPlist, ); }); diff --git a/packages/cli/src/commands/link/ios/addFileToProject.js b/packages/platform-ios/src/link/addFileToProject.js similarity index 87% rename from packages/cli/src/commands/link/ios/addFileToProject.js rename to packages/platform-ios/src/link/addFileToProject.js index e5c6174913..abcbc948b0 100644 --- a/packages/cli/src/commands/link/ios/addFileToProject.js +++ b/packages/platform-ios/src/link/addFileToProject.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ import PbxFile from 'xcode/lib/pbxFile'; @@ -14,7 +15,7 @@ import PbxFile from 'xcode/lib/pbxFile'; * from path provided, adds it to the project * and returns newly created instance of a file */ -export default function addFileToProject(project, filePath) { +export default function addFileToProject(project: any, filePath: string) { const file = new PbxFile(filePath); file.uuid = project.generateUuid(); file.fileRef = project.generateUuid(); diff --git a/packages/cli/src/commands/link/ios/addProjectToLibraries.js b/packages/platform-ios/src/link/addProjectToLibraries.js similarity index 100% rename from packages/cli/src/commands/link/ios/addProjectToLibraries.js rename to packages/platform-ios/src/link/addProjectToLibraries.js diff --git a/packages/cli/src/commands/link/ios/addSharedLibraries.js b/packages/platform-ios/src/link/addSharedLibraries.js similarity index 92% rename from packages/cli/src/commands/link/ios/addSharedLibraries.js rename to packages/platform-ios/src/link/addSharedLibraries.js index 3c42aa9e4f..13d611b20e 100644 --- a/packages/cli/src/commands/link/ios/addSharedLibraries.js +++ b/packages/platform-ios/src/link/addSharedLibraries.js @@ -20,6 +20,6 @@ export default function addSharedLibraries(project, libraries) { const target = project.getFirstTarget().uuid; for (const name of libraries) { - project.addFramework(name, { target }); + project.addFramework(name, {target}); } } diff --git a/packages/cli/src/commands/link/ios/addToHeaderSearchPaths.js b/packages/platform-ios/src/link/addToHeaderSearchPaths.js similarity index 77% rename from packages/cli/src/commands/link/ios/addToHeaderSearchPaths.js rename to packages/platform-ios/src/link/addToHeaderSearchPaths.js index 280499253a..2efd5df5fa 100644 --- a/packages/cli/src/commands/link/ios/addToHeaderSearchPaths.js +++ b/packages/platform-ios/src/link/addToHeaderSearchPaths.js @@ -8,7 +8,9 @@ */ import mapHeaderSearchPaths from './mapHeaderSearchPaths'; +import {logger} from '@react-native-community/cli-tools'; export default function addToHeaderSearchPaths(project, path) { + logger.debug(`Adding ${path} to header search paths`); mapHeaderSearchPaths(project, searchPaths => searchPaths.concat(path)); } diff --git a/packages/cli/src/commands/link/ios/common/isInstalled.js b/packages/platform-ios/src/link/common/isInstalled.js similarity index 57% rename from packages/cli/src/commands/link/ios/common/isInstalled.js rename to packages/platform-ios/src/link/common/isInstalled.js index 93c018a0a2..fcb5fab008 100644 --- a/packages/cli/src/commands/link/ios/common/isInstalled.js +++ b/packages/platform-ios/src/link/common/isInstalled.js @@ -4,13 +4,18 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import isInstalledIOS from '../isInstalled'; -import isInstalledPods from '../../pods/isInstalled'; +import isInstalledPods from '../../link-pods/isInstalled'; +import type {ProjectConfigIOST, DependencyConfigIOST} from 'types'; -export default function isInstalled(projectConfig, name, dependencyConfig) { +export default function isInstalled( + projectConfig: ProjectConfigIOST, + name?: string, + dependencyConfig: DependencyConfigIOST, +) { return ( isInstalledIOS(projectConfig, dependencyConfig) || isInstalledPods(projectConfig, dependencyConfig) diff --git a/packages/platform-ios/src/link/common/registerNativeModule.js b/packages/platform-ios/src/link/common/registerNativeModule.js new file mode 100644 index 0000000000..041e60cb87 --- /dev/null +++ b/packages/platform-ios/src/link/common/registerNativeModule.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {DependencyConfigIOST, ProjectConfigIOST} from 'types'; +import registerDependencyIOS from '../registerNativeModule'; +import registerDependencyPods from '../../link-pods/registerNativeModule'; + +export default function registerNativeModule( + name: string, + dependencyConfig: DependencyConfigIOST, + params?: any, + projectConfig: ProjectConfigIOST, +) { + if (projectConfig.podfile && dependencyConfig.podspecPath) { + registerDependencyPods(name, dependencyConfig.podspecPath, projectConfig); + } else { + registerDependencyIOS(dependencyConfig, projectConfig); + } +} diff --git a/packages/cli/src/commands/link/ios/common/unregisterNativeModule.js b/packages/platform-ios/src/link/common/unregisterNativeModule.js similarity index 72% rename from packages/cli/src/commands/link/ios/common/unregisterNativeModule.js rename to packages/platform-ios/src/link/common/unregisterNativeModule.js index 65db4aa9d6..1fd689344b 100644 --- a/packages/cli/src/commands/link/ios/common/unregisterNativeModule.js +++ b/packages/platform-ios/src/link/common/unregisterNativeModule.js @@ -7,22 +7,24 @@ * @format */ -import { compact } from 'lodash'; +import {compact} from 'lodash'; import isInstalledIOS from '../isInstalled'; -import isInstalledPods from '../../pods/isInstalled'; +import isInstalledPods from '../../link-pods/isInstalled'; import unregisterDependencyIOS from '../unregisterNativeModule'; -import unregisterDependencyPods from '../../pods/unregisterNativeModule'; +import unregisterDependencyPods from '../../link-pods/unregisterNativeModule'; export default function unregisterNativeModule( name, dependencyConfig, projectConfig, - otherDependencies + otherDependencies, ) { const isIosInstalled = isInstalledIOS(projectConfig, dependencyConfig); const isPodInstalled = isInstalledPods(projectConfig, dependencyConfig); if (isIosInstalled) { - const iOSDependencies = compact(otherDependencies.map(d => d.config.ios)); + const iOSDependencies = compact( + otherDependencies.map(d => d.platforms.ios), + ); unregisterDependencyIOS(dependencyConfig, projectConfig, iOSDependencies); } else if (isPodInstalled) { unregisterDependencyPods(dependencyConfig, projectConfig); diff --git a/packages/cli/src/commands/link/ios/copyAssets.js b/packages/platform-ios/src/link/copyAssets.js similarity index 68% rename from packages/cli/src/commands/link/ios/copyAssets.js rename to packages/platform-ios/src/link/copyAssets.js index 2319735008..862aa3ed28 100644 --- a/packages/cli/src/commands/link/ios/copyAssets.js +++ b/packages/platform-ios/src/link/copyAssets.js @@ -4,22 +4,26 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ -import fs from 'fs-extra'; +import fs from 'fs'; import path from 'path'; import xcode from 'xcode'; -import groupFilesByType from '../groupFilesByType'; import createGroupWithMessage from './createGroupWithMessage'; import getPlist from './getPlist'; import writePlist from './writePlist'; +import {logger, groupFilesByType} from '@react-native-community/cli-tools'; +import type {ProjectConfigIOST} from '../../../../types'; /** * This function works in a similar manner to its Android version, * except it does not copy fonts but creates Xcode Group references */ -export default function linkAssetsIOS(files, projectConfig) { +export default function linkAssetsIOS( + files: Array, + projectConfig: ProjectConfigIOST, +) { const project = xcode.project(projectConfig.pbxprojPath).parseSync(); const assets = groupFilesByType(files); const plist = getPlist(project, projectConfig.sourceDir); @@ -28,12 +32,14 @@ export default function linkAssetsIOS(files, projectConfig) { function addResourceFile(f) { return (f || []) - .map(asset => - project.addResourceFile(path.relative(projectConfig.sourceDir, asset), { - target: project.getFirstTarget().uuid, - }) - ) - .filter(file => file) // xcode returns false if file is already there + .map(asset => { + logger.debug(`Linking asset ${asset}`); + return project.addResourceFile( + path.relative(projectConfig.sourceDir, asset), + {target: project.getFirstTarget().uuid}, + ); + }) + .filter(Boolean) // xcode returns false if file is already there .map(file => file.basename); } diff --git a/packages/cli/src/commands/link/ios/createGroup.js b/packages/platform-ios/src/link/createGroup.js similarity index 100% rename from packages/cli/src/commands/link/ios/createGroup.js rename to packages/platform-ios/src/link/createGroup.js diff --git a/packages/cli/src/commands/link/ios/createGroupWithMessage.js b/packages/platform-ios/src/link/createGroupWithMessage.js similarity index 86% rename from packages/cli/src/commands/link/ios/createGroupWithMessage.js rename to packages/platform-ios/src/link/createGroupWithMessage.js index cd2c85bacd..aad426e4f2 100644 --- a/packages/cli/src/commands/link/ios/createGroupWithMessage.js +++ b/packages/platform-ios/src/link/createGroupWithMessage.js @@ -7,7 +7,7 @@ * @format */ -import log from '../../../tools/logger'; +import {logger} from '@react-native-community/cli-tools'; import createGroup from './createGroup'; import getGroup from './getGroup'; @@ -23,8 +23,8 @@ export default function createGroupWithMessage(project, path) { if (!group) { group = createGroup(project, path); - log.warn( - `Group '${path}' does not exist in your Xcode project. We have created it automatically for you.` + logger.warn( + `Group '${path}' does not exist in your Xcode project. We have created it automatically for you.`, ); } diff --git a/packages/cli/src/commands/link/ios/getBuildProperty.js b/packages/platform-ios/src/link/getBuildProperty.js similarity index 100% rename from packages/cli/src/commands/link/ios/getBuildProperty.js rename to packages/platform-ios/src/link/getBuildProperty.js diff --git a/packages/cli/src/commands/link/ios/getGroup.js b/packages/platform-ios/src/link/getGroup.js similarity index 100% rename from packages/cli/src/commands/link/ios/getGroup.js rename to packages/platform-ios/src/link/getGroup.js diff --git a/packages/cli/src/commands/link/ios/getHeaderSearchPath.js b/packages/platform-ios/src/link/getHeaderSearchPath.js similarity index 96% rename from packages/cli/src/commands/link/ios/getHeaderSearchPath.js rename to packages/platform-ios/src/link/getHeaderSearchPath.js index b7c053694b..3518620b3e 100644 --- a/packages/cli/src/commands/link/ios/getHeaderSearchPath.js +++ b/packages/platform-ios/src/link/getHeaderSearchPath.js @@ -8,7 +8,7 @@ */ import path from 'path'; -import { last, union } from 'lodash'; +import {last, union} from 'lodash'; /** * Given an array of directories, it returns the one that contains @@ -56,6 +56,6 @@ export default function getHeaderSearchPath(sourceDir, headers) { ? `"$(SRCROOT)${path.sep}${path.relative(sourceDir, directories[0])}"` : `"$(SRCROOT)${path.sep}${path.relative( sourceDir, - getOuterDirectory(directories) + getOuterDirectory(directories), )}/**"`; } diff --git a/packages/cli/src/commands/link/ios/getHeadersInFolder.js b/packages/platform-ios/src/link/getHeadersInFolder.js similarity index 100% rename from packages/cli/src/commands/link/ios/getHeadersInFolder.js rename to packages/platform-ios/src/link/getHeadersInFolder.js diff --git a/packages/cli/src/commands/link/ios/getPlist.js b/packages/platform-ios/src/link/getPlist.js similarity index 100% rename from packages/cli/src/commands/link/ios/getPlist.js rename to packages/platform-ios/src/link/getPlist.js diff --git a/packages/cli/src/commands/link/ios/getPlistPath.js b/packages/platform-ios/src/link/getPlistPath.js similarity index 89% rename from packages/cli/src/commands/link/ios/getPlistPath.js rename to packages/platform-ios/src/link/getPlistPath.js index 64b3484537..b0e6133090 100644 --- a/packages/cli/src/commands/link/ios/getPlistPath.js +++ b/packages/platform-ios/src/link/getPlistPath.js @@ -19,6 +19,6 @@ export default function getPlistPath(project, sourceDir) { return path.join( sourceDir, - plistFile.replace(/"/g, '').replace('$(SRCROOT)', '') + plistFile.replace(/"/g, '').replace('$(SRCROOT)', ''), ); } diff --git a/packages/cli/src/commands/link/ios/getTargets.js b/packages/platform-ios/src/link/getTargets.js similarity index 97% rename from packages/cli/src/commands/link/ios/getTargets.js rename to packages/platform-ios/src/link/getTargets.js index 2e8147dc2d..3c8a841467 100644 --- a/packages/cli/src/commands/link/ios/getTargets.js +++ b/packages/platform-ios/src/link/getTargets.js @@ -12,7 +12,7 @@ */ export default function getTargets(project) { const { - firstProject: { targets }, + firstProject: {targets}, } = project.getFirstProject(); const nativeTargetSection = project.pbxNativeTargetSection(); return targets diff --git a/packages/cli/src/commands/link/ios/hasLibraryImported.js b/packages/platform-ios/src/link/hasLibraryImported.js similarity index 100% rename from packages/cli/src/commands/link/ios/hasLibraryImported.js rename to packages/platform-ios/src/link/hasLibraryImported.js diff --git a/packages/cli/src/commands/link/ios/index.js b/packages/platform-ios/src/link/index.js similarity index 85% rename from packages/cli/src/commands/link/ios/index.js rename to packages/platform-ios/src/link/index.js index b68f83b571..687e922f4d 100644 --- a/packages/cli/src/commands/link/ios/index.js +++ b/packages/platform-ios/src/link/index.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import isInstalled from './common/isInstalled'; @@ -14,7 +14,7 @@ import copyAssets from './copyAssets'; import unlinkAssets from './unlinkAssets'; export function getIOSLinkConfig() { - return { isInstalled, register, unregister, copyAssets, unlinkAssets }; + return {isInstalled, register, unregister, copyAssets, unlinkAssets}; } export default getIOSLinkConfig; diff --git a/packages/cli/src/commands/link/ios/isInstalled.js b/packages/platform-ios/src/link/isInstalled.js similarity index 56% rename from packages/cli/src/commands/link/ios/isInstalled.js rename to packages/platform-ios/src/link/isInstalled.js index cf88883bc4..13c74cdc1f 100644 --- a/packages/cli/src/commands/link/ios/isInstalled.js +++ b/packages/platform-ios/src/link/isInstalled.js @@ -4,19 +4,33 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import xcode from 'xcode'; import getGroup from './getGroup'; import hasLibraryImported from './hasLibraryImported'; +import type {ProjectConfigIOST, DependencyConfigIOST} from 'types'; + +const memo = new Map(); /** * Returns true if `xcodeproj` specified by dependencyConfig is present * in a top level `libraryFolder` */ -export default function isInstalled(projectConfig, dependencyConfig) { - const project = xcode.project(projectConfig.pbxprojPath).parseSync(); +export default function isInstalled( + projectConfig: ProjectConfigIOST, + dependencyConfig: DependencyConfigIOST, +) { + let project; + + if (memo.has(projectConfig.pbxprojPath)) { + project = memo.get(projectConfig.pbxprojPath); + } else { + project = xcode.project(projectConfig.pbxprojPath).parseSync(); + memo.set(projectConfig.pbxprojPath, project); + } + const libraries = getGroup(project, projectConfig.libraryFolder); if (!libraries) { diff --git a/packages/cli/src/commands/link/ios/mapHeaderSearchPaths.js b/packages/platform-ios/src/link/mapHeaderSearchPaths.js similarity index 97% rename from packages/cli/src/commands/link/ios/mapHeaderSearchPaths.js rename to packages/platform-ios/src/link/mapHeaderSearchPaths.js index fbe95bfc81..eda6341e82 100644 --- a/packages/cli/src/commands/link/ios/mapHeaderSearchPaths.js +++ b/packages/platform-ios/src/link/mapHeaderSearchPaths.js @@ -30,7 +30,7 @@ export default function headerSearchPathIter(project, func) { Object.keys(config) .filter(ref => ref.indexOf('_comment') === -1) .forEach(ref => { - const { buildSettings } = config[ref]; + const {buildSettings} = config[ref]; const shouldVisitBuildSettings = (Array.isArray(buildSettings.OTHER_LDFLAGS) ? buildSettings.OTHER_LDFLAGS diff --git a/packages/cli/src/commands/link/ios/registerNativeModule.js b/packages/platform-ios/src/link/registerNativeModule.js similarity index 78% rename from packages/cli/src/commands/link/ios/registerNativeModule.js rename to packages/platform-ios/src/link/registerNativeModule.js index b735b24a0d..698f89139f 100644 --- a/packages/cli/src/commands/link/ios/registerNativeModule.js +++ b/packages/platform-ios/src/link/registerNativeModule.js @@ -4,14 +4,14 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import xcode from 'xcode'; import fs from 'fs'; import path from 'path'; -import { isEmpty } from 'lodash'; - +import {isEmpty} from 'lodash'; +import type {DependencyConfigIOST, ProjectConfigIOST} from 'types'; import addToHeaderSearchPaths from './addToHeaderSearchPaths'; import getHeadersInFolder from './getHeadersInFolder'; import getHeaderSearchPath from './getHeaderSearchPath'; @@ -20,6 +20,7 @@ import createGroupWithMessage from './createGroupWithMessage'; import addFileToProject from './addFileToProject'; import addProjectToLibraries from './addProjectToLibraries'; import addSharedLibraries from './addSharedLibraries'; +import {logger} from '@react-native-community/cli-tools'; /** * Register native module IOS adds given dependency to project by adding @@ -29,9 +30,10 @@ import addSharedLibraries from './addSharedLibraries'; * If library is already linked, this action is a no-op. */ export default function registerNativeModuleIOS( - dependencyConfig, - projectConfig + dependencyConfig: DependencyConfigIOST, + projectConfig: ProjectConfigIOST, ) { + logger.debug(`Reading ${projectConfig.pbxprojPath}`); const project = xcode.project(projectConfig.pbxprojPath).parseSync(); const dependencyProject = xcode .project(dependencyConfig.pbxprojPath) @@ -39,11 +41,11 @@ export default function registerNativeModuleIOS( const libraries = createGroupWithMessage( project, - projectConfig.libraryFolder + projectConfig.libraryFolder, ); const file = addFileToProject( project, - path.relative(projectConfig.sourceDir, dependencyConfig.projectPath) + path.relative(projectConfig.sourceDir, dependencyConfig.projectPath), ); const targets = getTargets(project); @@ -55,6 +57,7 @@ export default function registerNativeModuleIOS( if (!product.isTVOS) { for (i = 0; i < targets.length; i++) { if (!targets[i].isTVOS) { + logger.debug(`Adding ${product.name} to ${targets[i].target.name}`); project.addStaticLibrary(product.name, { target: targets[i].uuid, }); @@ -65,6 +68,7 @@ export default function registerNativeModuleIOS( if (product.isTVOS) { for (i = 0; i < targets.length; i++) { if (targets[i].isTVOS) { + logger.debug(`Adding ${product.name} to ${targets[i].target.name}`); project.addStaticLibrary(product.name, { target: targets[i].uuid, }); @@ -79,9 +83,10 @@ export default function registerNativeModuleIOS( if (!isEmpty(headers)) { addToHeaderSearchPaths( project, - getHeaderSearchPath(projectConfig.sourceDir, headers) + getHeaderSearchPath(projectConfig.sourceDir, headers), ); } + logger.debug(`Writing changes to ${projectConfig.pbxprojPath}`); fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync()); } diff --git a/packages/cli/src/commands/link/ios/removeFromHeaderSearchPaths.js b/packages/platform-ios/src/link/removeFromHeaderSearchPaths.js similarity index 73% rename from packages/cli/src/commands/link/ios/removeFromHeaderSearchPaths.js rename to packages/platform-ios/src/link/removeFromHeaderSearchPaths.js index 83f3290265..0eacd74e13 100644 --- a/packages/cli/src/commands/link/ios/removeFromHeaderSearchPaths.js +++ b/packages/platform-ios/src/link/removeFromHeaderSearchPaths.js @@ -8,12 +8,14 @@ */ import mapHeaderSearchPaths from './mapHeaderSearchPaths'; +import {logger} from '@react-native-community/cli-tools'; /** * Given Xcode project and absolute path, it makes sure there are no headers referring to it */ export default function addToHeaderSearchPaths(project, path) { + logger.debug(`Removing ${path} from header search paths`); mapHeaderSearchPaths(project, searchPaths => - searchPaths.filter(searchPath => searchPath !== path) + searchPaths.filter(searchPath => searchPath !== path), ); } diff --git a/packages/cli/src/commands/link/ios/removeFromPbxItemContainerProxySection.js b/packages/platform-ios/src/link/removeFromPbxItemContainerProxySection.js similarity index 100% rename from packages/cli/src/commands/link/ios/removeFromPbxItemContainerProxySection.js rename to packages/platform-ios/src/link/removeFromPbxItemContainerProxySection.js diff --git a/packages/cli/src/commands/link/ios/removeFromPbxReferenceProxySection.js b/packages/platform-ios/src/link/removeFromPbxReferenceProxySection.js similarity index 100% rename from packages/cli/src/commands/link/ios/removeFromPbxReferenceProxySection.js rename to packages/platform-ios/src/link/removeFromPbxReferenceProxySection.js diff --git a/packages/cli/src/commands/link/ios/removeFromProjectReferences.js b/packages/platform-ios/src/link/removeFromProjectReferences.js similarity index 89% rename from packages/cli/src/commands/link/ios/removeFromProjectReferences.js rename to packages/platform-ios/src/link/removeFromProjectReferences.js index 1398bd845b..6382c844c3 100644 --- a/packages/cli/src/commands/link/ios/removeFromProjectReferences.js +++ b/packages/platform-ios/src/link/removeFromProjectReferences.js @@ -18,10 +18,10 @@ * Otherwise returns null */ export default function removeFromProjectReferences(project, file) { - const { firstProject } = project.getFirstProject(); + const {firstProject} = project.getFirstProject(); const projectRef = firstProject.projectReferences.find( - item => item.ProjectRef === file.uuid + item => item.ProjectRef === file.uuid, ); if (!projectRef) { @@ -30,7 +30,7 @@ export default function removeFromProjectReferences(project, file) { firstProject.projectReferences.splice( firstProject.projectReferences.indexOf(projectRef), - 1 + 1, ); return projectRef; diff --git a/packages/cli/src/commands/link/ios/removeFromStaticLibraries.js b/packages/platform-ios/src/link/removeFromStaticLibraries.js similarity index 100% rename from packages/cli/src/commands/link/ios/removeFromStaticLibraries.js rename to packages/platform-ios/src/link/removeFromStaticLibraries.js diff --git a/packages/cli/src/commands/link/ios/removeProductGroup.js b/packages/platform-ios/src/link/removeProductGroup.js similarity index 100% rename from packages/cli/src/commands/link/ios/removeProductGroup.js rename to packages/platform-ios/src/link/removeProductGroup.js diff --git a/packages/cli/src/commands/link/ios/removeProjectFromLibraries.js b/packages/platform-ios/src/link/removeProjectFromLibraries.js similarity index 85% rename from packages/cli/src/commands/link/ios/removeProjectFromLibraries.js rename to packages/platform-ios/src/link/removeProjectFromLibraries.js index 195c14f012..80f8068e40 100644 --- a/packages/cli/src/commands/link/ios/removeProjectFromLibraries.js +++ b/packages/platform-ios/src/link/removeProjectFromLibraries.js @@ -13,8 +13,7 @@ * It's mainly due to limitations of `xcode` library. */ export default function removeProjectFromLibraries(libraries, file) { - // eslint-disable-next-line no-param-reassign libraries.children = libraries.children.filter( - library => library.comment !== file.basename + library => library.comment !== file.basename, ); } diff --git a/packages/cli/src/commands/link/ios/removeProjectFromProject.js b/packages/platform-ios/src/link/removeProjectFromProject.js similarity index 100% rename from packages/cli/src/commands/link/ios/removeProjectFromProject.js rename to packages/platform-ios/src/link/removeProjectFromProject.js diff --git a/packages/cli/src/commands/link/ios/removeSharedLibraries.js b/packages/platform-ios/src/link/removeSharedLibraries.js similarity index 89% rename from packages/cli/src/commands/link/ios/removeSharedLibraries.js rename to packages/platform-ios/src/link/removeSharedLibraries.js index 7b5d023812..35882b08ba 100644 --- a/packages/cli/src/commands/link/ios/removeSharedLibraries.js +++ b/packages/platform-ios/src/link/removeSharedLibraries.js @@ -15,6 +15,6 @@ export default function removeSharedLibraries(project, libraries) { const target = project.getFirstTarget().uuid; for (const name of libraries) { - project.removeFramework(name, { target }); + project.removeFramework(name, {target}); } } diff --git a/packages/cli/src/commands/link/ios/unlinkAssets.js b/packages/platform-ios/src/link/unlinkAssets.js similarity index 76% rename from packages/cli/src/commands/link/ios/unlinkAssets.js rename to packages/platform-ios/src/link/unlinkAssets.js index 1c6036905b..c8ae6ab2ec 100644 --- a/packages/cli/src/commands/link/ios/unlinkAssets.js +++ b/packages/platform-ios/src/link/unlinkAssets.js @@ -6,15 +6,14 @@ * */ -import fs from 'fs-extra'; +import fs from 'fs'; import path from 'path'; import xcode from 'xcode'; -import { difference } from 'lodash'; -import log from '../../../tools/logger'; +import {difference} from 'lodash'; -import groupFilesByType from '../groupFilesByType'; import getPlist from './getPlist'; import writePlist from './writePlist'; +import {logger, groupFilesByType} from '@react-native-community/cli-tools'; /** * Unlinks assets from iOS project. Removes references for fonts from `Info.plist` @@ -26,27 +25,28 @@ export default function unlinkAssetsIOS(files, projectConfig) { const plist = getPlist(project, projectConfig.sourceDir); if (!plist) { - log.error( - 'Could not locate "Info.plist" file. Check if your project has "INFOPLIST_FILE" set properly' + logger.error( + 'Could not locate "Info.plist" file. Check if your project has "INFOPLIST_FILE" set properly', ); return; } if (!project.pbxGroupByName('Resources')) { - log.error( - 'Group "Resources" does not exist in your Xcode project. There is nothing to unlink.' + logger.error( + 'Group "Resources" does not exist in your Xcode project. There is nothing to unlink.', ); return; } const removeResourceFiles = (f = []) => (f || []) - .map(asset => - project.removeResourceFile( + .map(asset => { + logger.debug(`Unlinking asset ${asset}`); + return project.removeResourceFile( path.relative(projectConfig.sourceDir, asset), - { target: project.getFirstTarget().uuid } - ) - ) + {target: project.getFirstTarget().uuid}, + ); + }) .map(file => file.basename); removeResourceFiles(assets.image); diff --git a/packages/cli/src/commands/link/ios/unregisterNativeModule.js b/packages/platform-ios/src/link/unregisterNativeModule.js similarity index 80% rename from packages/cli/src/commands/link/ios/unregisterNativeModule.js rename to packages/platform-ios/src/link/unregisterNativeModule.js index 8eebe59298..442c59c22f 100644 --- a/packages/cli/src/commands/link/ios/unregisterNativeModule.js +++ b/packages/platform-ios/src/link/unregisterNativeModule.js @@ -10,7 +10,7 @@ import xcode from 'xcode'; import path from 'path'; import fs from 'fs'; -import { difference, isEmpty } from 'lodash'; +import {difference, isEmpty} from 'lodash'; import getGroup from './getGroup'; import getTargets from './getTargets'; @@ -21,6 +21,7 @@ import removeProjectFromLibraries from './removeProjectFromLibraries'; import removeFromStaticLibraries from './removeFromStaticLibraries'; import removeFromHeaderSearchPaths from './removeFromHeaderSearchPaths'; import removeSharedLibraries from './removeSharedLibraries'; +import {logger} from '@react-native-community/cli-tools'; /** * Unregister native module IOS @@ -30,8 +31,9 @@ import removeSharedLibraries from './removeSharedLibraries'; export default function unregisterNativeModule( dependencyConfig, projectConfig, - iOSDependencies + iOSDependencies, ) { + logger.debug(`Reading ${projectConfig.pbxprojPath}`); const project = xcode.project(projectConfig.pbxprojPath).parseSync(); const dependencyProject = xcode .project(dependencyConfig.pbxprojPath) @@ -41,12 +43,17 @@ export default function unregisterNativeModule( const file = removeProjectFromProject( project, - path.relative(projectConfig.sourceDir, dependencyConfig.projectPath) + path.relative(projectConfig.sourceDir, dependencyConfig.projectPath), ); removeProjectFromLibraries(libraries, file); getTargets(dependencyProject).forEach(target => { + logger.debug( + `Removing ${target.name} from ${ + project.getFirstTarget().firstTarget.name + }`, + ); removeFromStaticLibraries(project, target.name, { target: project.getFirstTarget().uuid, }); @@ -56,8 +63,8 @@ export default function unregisterNativeModule( dependencyConfig.sharedLibraries, iOSDependencies.reduce( (libs, dependency) => libs.concat(dependency.sharedLibraries), - projectConfig.sharedLibraries - ) + projectConfig.sharedLibraries, + ), ); removeSharedLibraries(project, sharedLibraries); @@ -66,9 +73,10 @@ export default function unregisterNativeModule( if (!isEmpty(headers)) { removeFromHeaderSearchPaths( project, - getHeaderSearchPath(projectConfig.sourceDir, headers) + getHeaderSearchPath(projectConfig.sourceDir, headers), ); } + logger.debug(`Writing changes to ${projectConfig.pbxprojPath}`); fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync()); } diff --git a/packages/platform-ios/src/link/warnAboutManuallyLinkedLibs.js b/packages/platform-ios/src/link/warnAboutManuallyLinkedLibs.js new file mode 100644 index 0000000000..78023df9cb --- /dev/null +++ b/packages/platform-ios/src/link/warnAboutManuallyLinkedLibs.js @@ -0,0 +1,53 @@ +// @flow + +import chalk from 'chalk'; +import {logger} from '@react-native-community/cli-tools'; +import type {ConfigT} from 'types'; +import getLinkConfig from './index'; + +// TODO: move to cli-tools once platform-ios and platform-android are migrated +// to TS and unify with Android implementation +export default function warnAboutManuallyLinkedLibs( + config: ConfigT, + platform?: string = 'ios', + linkConfig: $Call = getLinkConfig(), +) { + let deps = []; + + for (let key in config.dependencies) { + const dependency = config.dependencies[key]; + try { + const projectConfig = config.project[platform]; + const dependencyConfig = dependency.platforms[platform]; + if (projectConfig && dependencyConfig) { + const x = linkConfig.isInstalled( + projectConfig, + dependency.name, + dependencyConfig, + ); + deps = deps.concat(x ? dependency.name : []); + } + } catch (error) { + logger.debug('Checking manually linked modules failed.', error); + } + } + + const installedModules = [...new Set(deps)]; + + if (installedModules.length) { + logger.error( + `React Native CLI uses autolinking for native dependencies, but the following modules are linked manually: \n${installedModules + .map( + x => + ` - ${chalk.bold(x)} ${chalk.dim( + `(to unlink run: "react-native unlink ${x}")`, + )}`, + ) + .join( + '\n', + )}\nThis is likely happening when upgrading React Native from below 0.60 to 0.60 or above. Going forward, you can unlink this dependency via "react-native unlink " and it will be included in your app automatically. If a library isn't compatible with autolinking, disregard this message and notify the library maintainers.\nRead more about autolinking: ${chalk.dim.underline( + 'https://github.com/react-native-community/cli/blob/master/docs/autolinking.md', + )}`, + ); + } +} diff --git a/packages/cli/src/commands/link/ios/writePlist.js b/packages/platform-ios/src/link/writePlist.js similarity index 92% rename from packages/cli/src/commands/link/ios/writePlist.js rename to packages/platform-ios/src/link/writePlist.js index eb5d54c5da..38aaf6467f 100644 --- a/packages/cli/src/commands/link/ios/writePlist.js +++ b/packages/platform-ios/src/link/writePlist.js @@ -28,6 +28,6 @@ export default function writePlist(project, sourceDir, plist) { // Ref: https://github.com/facebook/react-native/issues/11668 return fs.writeFileSync( plistPath, - `${plistParser.build(plist, { indent: '\t', offset: -1 })}\n` + `${plistParser.build(plist, {indent: '\t', offset: -1})}\n`, ); } diff --git a/packages/tools/package.json b/packages/tools/package.json new file mode 100644 index 0000000000..3ef5b4ac6d --- /dev/null +++ b/packages/tools/package.json @@ -0,0 +1,20 @@ +{ + "name": "@react-native-community/cli-tools", + "version": "2.4.1", + "license": "MIT", + "main": "build/index.js", + "dependencies": { + "chalk": "^2.4.2", + "lodash": "^4.17.5", + "mime": "^2.4.1", + "node-fetch": "^2.5.0" + }, + "devDependencies": { + "@types/lodash": "^4.14.123", + "@types/mime": "^2.0.1", + "@types/node-fetch": "^2.3.3" + }, + "files": [ + "build" + ] +} diff --git a/packages/cli/src/tools/__mocks__/log.js b/packages/tools/src/__mocks__/logger.ts similarity index 96% rename from packages/cli/src/tools/__mocks__/log.js rename to packages/tools/src/__mocks__/logger.ts index 33dbe25a25..8cc725657d 100644 --- a/packages/cli/src/tools/__mocks__/log.js +++ b/packages/tools/src/__mocks__/logger.ts @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format */ module.exports.out = () => jest.fn(); diff --git a/packages/cli/src/commands/link/__tests__/groupFilesByType-test.js b/packages/tools/src/__tests__/groupFilesByType.test.ts similarity index 92% rename from packages/cli/src/commands/link/__tests__/groupFilesByType-test.js rename to packages/tools/src/__tests__/groupFilesByType.test.ts index 17f02ed59b..e15a985cc7 100644 --- a/packages/cli/src/commands/link/__tests__/groupFilesByType-test.js +++ b/packages/tools/src/__tests__/groupFilesByType.test.ts @@ -4,8 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format - * @emails oncall+javascript_foundation */ import groupFilesByType from '../groupFilesByType'; diff --git a/packages/tools/src/errors.ts b/packages/tools/src/errors.ts new file mode 100644 index 0000000000..17339a1715 --- /dev/null +++ b/packages/tools/src/errors.ts @@ -0,0 +1,27 @@ +/** + * A custom Error that creates a single-lined message to match current styling inside CLI. + * Uses original stack trace when `originalError` is passed or erase the stack if it's not defined. + */ +export class CLIError extends Error { + constructor(msg: string, originalError?: Error | string) { + super(inlineString(msg)); + if (originalError) { + this.stack = + typeof originalError === 'string' + ? originalError + : originalError.stack || + '' + .split('\n') + .slice(0, 2) + .join('\n'); + } else { + // When the "originalError" is not passed, it means that we know exactly + // what went wrong and provide means to fix it. In such cases showing the + // stack is an unnecessary clutter to the CLI output, hence removing it. + delete this.stack; + } + } +} + +export const inlineString = (str: string) => + str.replace(/(\s{2,})/gm, ' ').trim(); diff --git a/packages/tools/src/getDefaultUserTerminal.ts b/packages/tools/src/getDefaultUserTerminal.ts new file mode 100644 index 0000000000..a5bf91914b --- /dev/null +++ b/packages/tools/src/getDefaultUserTerminal.ts @@ -0,0 +1,4 @@ +const getDefaultUserTerminal = (): string | undefined => + process.env.REACT_TERMINAL || process.env.TERM_PROGRAM; + +export default getDefaultUserTerminal; diff --git a/packages/cli/src/commands/link/groupFilesByType.js b/packages/tools/src/groupFilesByType.ts similarity index 62% rename from packages/cli/src/commands/link/groupFilesByType.js rename to packages/tools/src/groupFilesByType.ts index 4de668bdbd..c42215252f 100644 --- a/packages/cli/src/commands/link/groupFilesByType.js +++ b/packages/tools/src/groupFilesByType.ts @@ -4,22 +4,11 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format */ -import { groupBy } from 'lodash'; +import {groupBy} from 'lodash'; import mime from 'mime'; -/** - * Since there are no officially registered MIME types - * for ttf/otf yet http://www.iana.org/assignments/media-types/media-types.xhtml, - * we define two non-standard ones for the sake of parsing - */ -mime.define({ - 'font/opentype': ['otf'], - 'font/truetype': ['ttf'], -}); - /** * Given an array of files, it groups it by it's type. * Type of the file is inferred from it's mimetype based on the extension @@ -31,6 +20,6 @@ mime.define({ * Given an array ['fonts/a.ttf', 'images/b.jpg'], * the returned object will be: {font: ['fonts/a.ttf'], image: ['images/b.jpg']} */ -export default function groupFilesByType(assets) { - return groupBy(assets, type => mime.lookup(type).split('/')[0]); +export default function groupFilesByType(assets: Array) { + return groupBy(assets, type => (mime.getType(type) || '').split('/')[0]); } diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts new file mode 100644 index 0000000000..d99e20bf08 --- /dev/null +++ b/packages/tools/src/index.ts @@ -0,0 +1,6 @@ +export {default as logger} from './logger'; +export {default as groupFilesByType} from './groupFilesByType'; +export {default as isPackagerRunning} from './isPackagerRunning'; +export {default as getDefaultUserTerminal} from './getDefaultUserTerminal'; + +export * from './errors'; diff --git a/packages/cli/src/tools/isPackagerRunning.js b/packages/tools/src/isPackagerRunning.ts similarity index 50% rename from packages/cli/src/tools/isPackagerRunning.js rename to packages/tools/src/isPackagerRunning.ts index c08ca41425..11b2763687 100644 --- a/packages/cli/src/tools/isPackagerRunning.js +++ b/packages/tools/src/isPackagerRunning.ts @@ -4,30 +4,28 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format */ import fetch from 'node-fetch'; /** * Indicates whether or not the packager is running. It returns a promise that - * when fulfilled can returns one out of these possible values: + * returns one of these possible values: * - `running`: the packager is running - * - `not_running`: the packager nor any process is running on the expected - * port. - * - `unrecognized`: one other process is running on the port we expect the - * packager to be running. + * - `not_running`: the packager nor any process is running on the expected port. + * - `unrecognized`: one other process is running on the port we expect the packager to be running. */ -function isPackagerRunning(packagerPort = process.env.RCT_METRO_PORT || 8081) { - return fetch(`http://localhost:${packagerPort}/status`).then( - res => - res - .text() - .then(body => - body === 'packager-status:running' ? 'running' : 'unrecognized' - ), - () => 'not_running' - ); +async function isPackagerRunning( + packagerPort: string = process.env.RCT_METRO_PORT || '8081', +): Promise<'running' | 'not_running' | 'unrecognized'> { + try { + const result = await fetch(`http://localhost:${packagerPort}/status`); + const body = await result.text(); + + return body === 'packager-status:running' ? 'running' : 'unrecognized'; + } catch (_error) { + return 'not_running'; + } } export default isPackagerRunning; diff --git a/packages/tools/src/logger.ts b/packages/tools/src/logger.ts new file mode 100644 index 0000000000..6ad30997f5 --- /dev/null +++ b/packages/tools/src/logger.ts @@ -0,0 +1,72 @@ +import chalk from 'chalk'; + +const SEPARATOR = ', '; + +let verbose = false; +let disabled = false; + +const formatMessages = (messages: Array) => + chalk.reset(messages.join(SEPARATOR)); + +const success = (...messages: Array) => { + if (!disabled) { + console.log(`${chalk.green.bold('success')} ${formatMessages(messages)}`); + } +}; + +const info = (...messages: Array) => { + if (!disabled) { + console.log(`${chalk.cyan.bold('info')} ${formatMessages(messages)}`); + } +}; + +const warn = (...messages: Array) => { + if (!disabled) { + console.warn(`${chalk.yellow.bold('warn')} ${formatMessages(messages)}`); + } +}; + +const error = (...messages: Array) => { + if (!disabled) { + console.error(`${chalk.red.bold('error')} ${formatMessages(messages)}`); + } +}; + +const debug = (...messages: Array) => { + if (verbose && !disabled) { + console.log(`${chalk.gray.bold('debug')} ${formatMessages(messages)}`); + } +}; + +const log = (...messages: Array) => { + if (!disabled) { + console.log(`${formatMessages(messages)}`); + } +}; + +const setVerbose = (level: boolean) => { + verbose = level; +}; + +const isVerbose = () => verbose; + +const disable = () => { + disabled = true; +}; + +const enable = () => { + disabled = false; +}; + +export default { + success, + info, + warn, + error, + debug, + log, + setVerbose, + isVerbose, + disable, + enable, +}; diff --git a/packages/tools/tsconfig.json b/packages/tools/tsconfig.json new file mode 100644 index 0000000000..7bb06bce6d --- /dev/null +++ b/packages/tools/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + } +} diff --git a/scripts/build.js b/scripts/build.js index 689ba6d6a6..b0c10568d8 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -25,36 +25,21 @@ const mkdirp = require('mkdirp'); const babel = require('@babel/core'); const chalk = require('chalk'); const micromatch = require('micromatch'); -const prettier = require('prettier'); -const stringLength = require('string-length'); -const { PACKAGES_DIR, getPackages } = require('./helpers'); +const { + PACKAGES_DIR, + getPackages, + OK, + adjustToTerminalWidth, +} = require('./helpers'); -const OK = chalk.reset.inverse.bold.green(' DONE '); const SRC_DIR = 'src'; const BUILD_DIR = 'build'; const JS_FILES_PATTERN = '**/*.js'; +const TS_FILE_PATTERN = '**/*.ts'; const IGNORE_PATTERN = '**/__{tests,mocks,fixtures}__/**'; const transformOptions = require('../babel.config.js'); -const prettierConfig = prettier.resolveConfig.sync(__filename); -prettierConfig.trailingComma = 'none'; -prettierConfig.parser = 'babel'; - -const adjustToTerminalWidth = str => { - const columns = process.stdout.columns || 80; - const WIDTH = columns - stringLength(OK) + 1; - const strs = str.match(new RegExp(`(.{1,${WIDTH}})`, 'g')); - let lastString = strs[strs.length - 1]; - if (lastString.length < WIDTH) { - lastString += Array(WIDTH - lastString.length).join(chalk.dim('.')); - } - return strs - .slice(0, -1) - .concat(lastString) - .join('\n'); -}; - function getPackageName(file) { return path.relative(PACKAGES_DIR, file).split(path.sep)[0]; } @@ -64,7 +49,7 @@ function getBuildPath(file, buildFolder) { const pkgSrcPath = path.resolve(PACKAGES_DIR, pkgName, SRC_DIR); const pkgBuildPath = path.resolve(PACKAGES_DIR, pkgName, buildFolder); const relativeToSrcPath = path.relative(pkgSrcPath, file); - return path.resolve(pkgBuildPath, relativeToSrcPath); + return path.resolve(pkgBuildPath, relativeToSrcPath).replace(/\.ts$/, '.js'); } function buildNodePackage(p) { @@ -87,35 +72,37 @@ function buildFile(file, silent) { silent || process.stdout.write( `${chalk.dim(' \u2022 ') + - path.relative(PACKAGES_DIR, file)} (ignore)\n` + path.relative(PACKAGES_DIR, file)} (ignore)\n`, ); return; } mkdirp.sync(path.dirname(destPath), '777'); - if (!micromatch.isMatch(file, JS_FILES_PATTERN)) { + if ( + !micromatch.isMatch(file, JS_FILES_PATTERN) && + !micromatch.isMatch(file, TS_FILE_PATTERN) + ) { fs.createReadStream(file).pipe(fs.createWriteStream(destPath)); silent || process.stdout.write( `${chalk.red(' \u2022 ') + path.relative(PACKAGES_DIR, file) + chalk.red(' \u21D2 ') + - path.relative(PACKAGES_DIR, destPath)} (copy)\n` + path.relative(PACKAGES_DIR, destPath)} (copy)\n`, ); } else { const options = Object.assign({}, transformOptions); const transformed = babel.transformFileSync(file, options).code; - const prettyCode = prettier.format(transformed, prettierConfig); - fs.writeFileSync(destPath, prettyCode); + fs.writeFileSync(destPath, transformed); silent || process.stdout.write( `${chalk.green(' \u2022 ') + path.relative(PACKAGES_DIR, file) + chalk.green(' \u21D2 ') + - path.relative(PACKAGES_DIR, destPath)}\n` + path.relative(PACKAGES_DIR, destPath)}\n`, ); } } diff --git a/scripts/buildTs.js b/scripts/buildTs.js new file mode 100644 index 0000000000..5ab6c6c8f1 --- /dev/null +++ b/scripts/buildTs.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const chalk = require('chalk'); +const execa = require('execa'); +const {getPackages, adjustToTerminalWidth, OK} = require('./helpers'); + +const packages = getPackages(); + +const packagesWithTs = packages.filter(p => + fs.existsSync(path.resolve(p, 'tsconfig.json')), +); + +const args = [ + path.resolve( + require.resolve('typescript/package.json'), + '..', + require('typescript/package.json').bin.tsc, + ), + '-b', + ...packagesWithTs, + ...process.argv.slice(2), +]; + +console.log(chalk.inverse('Building TypeScript definition files')); +process.stdout.write(adjustToTerminalWidth('Building\n')); + +try { + execa.sync('node', args, {stdio: 'inherit'}); + process.stdout.write(`${OK}\n`); +} catch (e) { + process.stdout.write('\n'); + console.error( + chalk.inverse.red('Unable to build TypeScript definition files'), + ); + console.error(e.stack); + process.exitCode = 1; +} diff --git a/scripts/helpers.js b/scripts/helpers.js index 3dfdf7f3cb..97c108ba15 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -1,8 +1,19 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + const fs = require('fs'); const path = require('path'); +const chalk = require('chalk'); +const stringLength = require('string-length'); const PACKAGES_DIR = path.resolve(__dirname, '../packages'); +const OK = chalk.reset.inverse.bold.green(' DONE '); + function getPackages() { return fs .readdirSync(PACKAGES_DIR) @@ -10,7 +21,23 @@ function getPackages() { .filter(f => fs.lstatSync(path.resolve(f)).isDirectory()); } +function adjustToTerminalWidth(str) { + const columns = process.stdout.columns || 80; + const WIDTH = columns - stringLength(OK) + 1; + const strs = str.match(new RegExp(`(.{1,${WIDTH}})`, 'g')); + let lastString = strs[strs.length - 1]; + if (lastString.length < WIDTH) { + lastString += Array(WIDTH - lastString.length).join(chalk.dim('.')); + } + return strs + .slice(0, -1) + .concat(lastString) + .join('\n'); +} + module.exports = { getPackages, PACKAGES_DIR, + adjustToTerminalWidth, + OK, }; diff --git a/scripts/watch.js b/scripts/watch.js index 4da6e2fd82..20f711590b 100644 --- a/scripts/watch.js +++ b/scripts/watch.js @@ -10,10 +10,10 @@ */ const fs = require('fs'); -const { execSync } = require('child_process'); +const {execSync} = require('child_process'); const path = require('path'); const chalk = require('chalk'); -const { getPackages } = require('./helpers'); +const {getPackages} = require('./helpers'); const BUILD_CMD = `node ${path.resolve(__dirname, './build.js')}`; @@ -33,7 +33,7 @@ getPackages().forEach(p => { const srcDir = path.resolve(p, 'src'); try { fs.accessSync(srcDir, fs.F_OK); - fs.watch(path.resolve(p, 'src'), { recursive: true }, (event, filename) => { + fs.watch(path.resolve(p, 'src'), {recursive: true}, (event, filename) => { const filePath = path.resolve(srcDir, filename); if ((event === 'change' || event === 'rename') && exists(filePath)) { @@ -47,8 +47,8 @@ getPackages().forEach(p => { `${chalk.red(' \u2022 ') + path.relative( path.resolve(srcDir, '..', '..'), - buildFile - )} (deleted)\n` + buildFile, + )} (deleted)\n`, ); } catch (e) { // omit @@ -65,7 +65,7 @@ setInterval(() => { if (files.length) { filesToBuild = new Map(); try { - execSync(`${BUILD_CMD} ${files.join(' ')}`, { stdio: [0, 1, 2] }); + execSync(`${BUILD_CMD} ${files.join(' ')}`, {stdio: [0, 1, 2]}); } catch (e) { // omit } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..bc0c608808 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "lib": ["es2017"], + "declaration": true, + "declarationMap": true, + "composite": true, + "emitDeclarationOnly": true, + + "strict": true, + + /* Additional Checks */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + + /* Module Resolution Options */ + "moduleResolution": "node", + "esModuleInterop": true, + "resolveJsonModule": true + }, + "exclude": ["**/__tests__/**/*", "**/build/**/*"] +} diff --git a/types/index.js b/types/index.js new file mode 100644 index 0000000000..32ba63ef24 --- /dev/null +++ b/types/index.js @@ -0,0 +1,257 @@ +/** + * @flow + */ +export type CommandT = { + name: string, + description?: string, + func: (argv: Array, ctx: ConfigT, args: Object) => ?Promise, + options?: Array<{ + name: string, + description?: string, + parse?: (val: string) => any, + default?: + | string + | boolean + | number + | ((ctx: ConfigT) => string | boolean | number), + }>, + examples?: Array<{ + desc: string, + cmd: string, + }>, +}; + +/** + * Opaque type that describes the Inquirer question format. Not typed, since we just + * pass it directly to Inquirer. Validation is done with Joi in `schema.js` + */ +export type InquirerPromptT = any; + +/** + * Settings that a library author can define in the configuration bundled with + * dependency for Android + * + * See UserDependencyConfigT for details + */ +type DependencyParamsAndroidT = { + sourceDir?: string, + manifestPath?: string, + packageImportPath?: string, + packageInstance?: string, +}; + +/** + * Settings that user can define in the project configuration for Android + * + * See UserConfigT for details + */ +type ProjectParamsAndroidT = { + sourceDir?: string, + manifestPath?: string, + packageName?: string, + packageFolder?: string, + mainFilePath?: string, + stringsPath?: string, + settingsGradlePath?: string, + assetsPath?: string, + buildGradlePath?: string, + packageName?: string, +}; + +/** + * Settings that user can define in the project configuration for iOS. + * Same for dependency - we share the type. + * + * See UserDependencyConfigT and UserConfigT for details + */ +type ProjectParamsIOST = { + project?: string, + podspecPath?: string, + sharedLibraries?: string[], + libraryFolder?: string, + plist: any[], +}; + +type PlatformConfig< + ProjectParams, + DependencyParams, + ProjectConfig, + DependencyConfig, +> = { + projectConfig: (string, ?ProjectParams) => ?ProjectConfig, + dependencyConfig: (string, ?DependencyParams) => ?DependencyConfig, + linkConfig: () => { + isInstalled: (ProjectConfig, string, DependencyConfig) => boolean, + register: (string, DependencyConfig, Object, ProjectConfig) => void, + unregister: ( + string, + DependencyConfig, + ProjectConfig, + Array, + ) => void, + copyAssets: (string[], ProjectConfig) => void, + unlinkAssets: (string[], ProjectConfig) => void, + }, +}; + +/** + * Final configuration object + */ +export type ConfigT = {| + // Root where the configuration has been resolved from + root: string, + + // Path to React Native source + reactNativePath: string, + + // Object that contains configuration for a project (null, when platform not available) + project: { + android?: ProjectConfigAndroidT, + ios?: ?ProjectConfigIOST, + [key: string]: ?Object, + }, + + // An array of assets as defined by the user + assets: string[], + + // Map of the dependencies that are present in the project + dependencies: { + [key: string]: { + name: string, + root: string, + platforms: { + android?: DependencyConfigAndroidT | null, + ios?: DependencyConfigIOST | null, + [key: string]: any, + }, + assets: string[], + hooks: { + [key: string]: string, + prelink?: string, + postlink?: string, + }, + params: InquirerPromptT[], + }, + }, + + // Map of available platforms (built-ins and dynamically loaded) + platforms: { + [name: string]: PlatformConfig, + ios?: PlatformConfig< + ProjectParamsIOST, + ProjectParamsIOST, // DependencyParams are the same as ProjectParams on iOS + ProjectConfigIOST, + DependencyConfigIOST, + >, + android?: PlatformConfig< + ProjectParamsAndroidT, + DependencyParamsAndroidT, + ProjectConfigAndroidT, + DependencyConfigAndroidT, + >, + }, + + // An array of commands that are present in 3rd party packages + commands: CommandT[], + + // Haste configuration resolved based on available plugins + haste: { + platforms: Array, + providesModuleNodeModules: Array, + }, +|}; + +/** + * Aliases + */ +export type DependencyConfigT = $PropertyType< + $PropertyType, + '[key: string]', +>; +export type HooksT = $PropertyType; +export type ProjectConfigT = $PropertyType; +export type PlatformsT = $PropertyType; + +/** + * Config defined by a developer for a library + */ +export type UserDependencyConfigT = { + // Additional dependency settings + dependency: { + platforms: { + android?: DependencyParamsAndroidT, + ios?: ProjectParamsIOST, + [key: string]: any, + }, + assets: string[], + hooks: HooksT, + params: InquirerPromptT[], + }, + + // An array of commands that ship with the dependency + commands: CommandT[], + + // An array of extra platforms to load + platforms: { + [name: string]: any, + }, + + // Haste config defined by legacy `rnpm` + haste?: { + platforms: string[], + providesModuleNodeModules: string[], + }, +}; + +/** + * Config defined by a developer for the project + */ +export type UserConfigT = { + /** + * Shares some structure with ConfigT, except that haste and root + * are calculated and can't be defined + */ + ...$Diff, + reactNativePath: ?string, + + // Additional project settings + project: { + android?: ProjectParamsAndroidT, + ios?: ProjectParamsIOST, + [key: string]: any, + }, +}; + +// The following types are used in untyped-parts of the codebase, so I am leaving them +// until we actually need them. +export type ProjectConfigIOST = { + sourceDir: string, + folder: string, + pbxprojPath: string, + podfile: null, + podspecPath: null | string, + projectPath: string, + projectName: string, + libraryFolder: string, + sharedLibraries: Array, + plist: Array, +}; +export type DependencyConfigIOST = ProjectConfigIOST; +type ProjectConfigAndroidT = { + sourceDir: string, + isFlat: boolean, + folder: string, + stringsPath: string, + manifestPath: string, + buildGradlePath: string, + settingsGradlePath: string, + assetsPath: string, + mainFilePath: string, + packageName: string, +}; +type DependencyConfigAndroidT = { + sourceDir: string, + folder: string, + packageImportPath: string, + packageInstance: string, +}; diff --git a/yarn.lock b/yarn.lock index 3e1667e424..a7f24014fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,7 @@ "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: "@babel/highlight" "^7.0.0" @@ -28,51 +29,41 @@ source-map "^0.5.0" "@babel/core@^7.1.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" - integrity sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw== + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.3.tgz#198d6d3af4567be3989550d97e068de94503074f" + integrity sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" - "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.2.2" - "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/generator" "^7.4.0" + "@babel/helpers" "^7.4.3" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" - lodash "^4.17.10" + lodash "^4.17.11" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0", "@babel/generator@^7.1.2", "@babel/generator@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" - dependencies: - "@babel/types" "^7.1.3" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.5.tgz#615f064d13d95f8f9157c7261f68eddf32ec15b3" +"@babel/generator@^7.0.0", "@babel/generator@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" + integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ== dependencies: - "@babel/types" "^7.1.5" + "@babel/types" "^7.4.0" jsesc "^2.5.1" - lodash "^4.17.10" + lodash "^4.17.11" source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" - integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg== +"@babel/generator@^7.1.2": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" dependencies: - "@babel/types" "^7.2.2" + "@babel/types" "^7.1.3" jsesc "^2.5.1" lodash "^4.17.10" source-map "^0.5.0" @@ -124,6 +115,7 @@ "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== dependencies: "@babel/helper-get-function-arity" "^7.0.0" "@babel/template" "^7.1.0" @@ -132,6 +124,7 @@ "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== dependencies: "@babel/types" "^7.0.0" @@ -173,6 +166,7 @@ "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== "@babel/helper-regex@^7.0.0": version "7.0.0" @@ -206,11 +200,12 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-split-export-declaration@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" +"@babel/helper-split-export-declaration@^7.0.0", "@babel/helper-split-export-declaration@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz#571bfd52701f492920d63b7f735030e9a3e10b55" + integrity sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.4.0" "@babel/helper-wrap-function@^7.1.0": version "7.1.0" @@ -229,35 +224,28 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.1.2" -"@babel/helpers@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21" - integrity sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A== +"@babel/helpers@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.3.tgz#7b1d354363494b31cb9a2417ae86af32b7853a3b" + integrity sha512-BMh7X0oZqb36CfyhvtbSmcWc3GXocfxv3yNsAEuM0l+fAqSO22rQrUpijr3oE/10jCTrB6/0b9kzmG4VetCj8Q== dependencies: - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.5" - "@babel/types" "^7.2.0" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.2", "@babel/parser@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.3.tgz#2c92469bac2b7fbff810b67fca07bd138b48af77" - -"@babel/parser@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.5.tgz#20b7d5e7e1811ba996f8a868962ea7dd2bfcd2fc" - -"@babel/parser@^7.2.2", "@babel/parser@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" - integrity sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.2", "@babel/parser@^7.4.0", "@babel/parser@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.3.tgz#eb3ac80f64aa101c907d4ce5406360fe75b7895b" + integrity sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ== "@babel/plugin-external-helpers@^7.0.0": version "7.0.0" @@ -384,6 +372,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-flow@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c" + integrity sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" @@ -403,13 +398,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-object-rest-spread@^7.2.0": +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== @@ -441,6 +430,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-typescript@^7.2.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" + integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" @@ -454,6 +450,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-async-to-generator@^7.0.0": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c" + integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-transform-async-to-generator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" @@ -833,6 +838,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript" "^7.0.0" +"@babel/plugin-transform-typescript@^7.3.2": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.0.tgz#0389ec53a34e80f99f708c4ca311181449a68eb1" + integrity sha512-U7/+zKnRZg04ggM/Bm+xmu2B/PrwyDQTT/V89FXWYWNMxBDwSx56u6jtk9SEbfLFbZaEI72L+5LPvQjeZgFCrQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" + "@babel/plugin-transform-unicode-regex@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" @@ -904,153 +917,285 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-flow-strip-types" "^7.0.0" -"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.1.2" - "@babel/types" "^7.1.2" - -"@babel/template@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" - integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== +"@babel/preset-typescript@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a" + integrity sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.3.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" +"@babel/register@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.0.0.tgz#fa634bae1bfa429f60615b754fc1f1d745edd827" + integrity sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.3" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.3" - "@babel/types" "^7.1.3" - debug "^3.1.0" - globals "^11.1.0" + core-js "^2.5.7" + find-cache-dir "^1.0.0" + home-or-tmp "^3.0.0" lodash "^4.17.10" + mkdirp "^0.5.1" + pirates "^4.0.0" + source-map-support "^0.5.9" -"@babel/traverse@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.5.tgz#5aafca2039aa058c104cf2bfeb9fc4a857ccbca9" +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" + integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.5" - "@babel/types" "^7.1.5" - debug "^3.1.0" - globals "^11.1.0" - lodash "^4.17.10" + "@babel/parser" "^7.4.0" + "@babel/types" "^7.4.0" -"@babel/traverse@^7.2.2": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" - integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" + integrity sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" + "@babel/generator" "^7.4.0" "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.2.3" - "@babel/types" "^7.2.2" + "@babel/helper-split-export-declaration" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/types" "^7.4.0" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.10" + lodash "^4.17.11" -"@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" +"@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3", "@babel/types@^7.3.0", "@babel/types@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" + integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== dependencies: esutils "^2.0.2" - lodash "^4.17.10" + lodash "^4.17.11" to-fast-properties "^2.0.0" -"@babel/types@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.5.tgz#12fe64e91a431234b7017b4227a78cc0eec4e081" +"@cnakazawa/watch@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" + integrity sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA== dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" + exec-sh "^0.3.2" + minimist "^1.2.0" -"@babel/types@^7.2.0", "@babel/types@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" - integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg== +"@hapi/address@2.x.x": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a" + integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw== + +"@hapi/hoek@6.x.x": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-6.2.1.tgz#d3a66329159af879bfdf0b0cff2229c43c5a3451" + integrity sha512-+ryw4GU9pjr1uT6lBuErHJg3NYqzwJTvZ75nKuJijEzpd00Uqi6oiawTGDDf5Hl0zWmI7qHfOtaqB0kpQZJQzA== + +"@hapi/joi@^15.0.3": + version "15.0.3" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.0.3.tgz#e94568fd859e5e945126d5675e7dd218484638a7" + integrity sha512-z6CesJ2YBwgVCi+ci8SI8zixoj8bGFn/vZb9MBPbSyoxsS2PnWYjHcyTM17VLK6tx64YVK38SDIh10hJypB+ig== dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" + "@hapi/address" "2.x.x" + "@hapi/hoek" "6.x.x" + "@hapi/topo" "3.x.x" -"@callstack/eslint-config@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@callstack/eslint-config/-/eslint-config-3.0.2.tgz#e40fcf73749aa8fb0b83bf243a2d6fdbc416fbd2" - integrity sha512-Frzn1E/egdqppp/2OLi76SMa6Z3yv4oRDjXDdYPCPtEJDyjzUh2lfTpURqziKbACUexTXMxAA+XMN0BSJ9RgUw== - dependencies: - babel-eslint "^10.0.1" - eslint-config-airbnb "^17.1.0" - eslint-config-prettier "^3.0.1" - eslint-plugin-flowtype "^3.0.0" - eslint-plugin-import "^2.14.0" - eslint-plugin-jest "^21.21.0" - eslint-plugin-jsx-a11y "^6.1.1" - eslint-plugin-prettier "^3.0.0" - eslint-plugin-react "^7.5.1" - prettier "^1.14.2" - -"@lerna/add@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.10.6.tgz#6f2c6b26eb905c40fef4180f3ffa34ad9dbb860b" - integrity sha512-FxQ5Bmyb5fF+3BQiNffM6cTeGCrl4uaAuGvxFIWF6Pgz6U14tUc1e16xgKDvVb1CurzJgIV5sLOT5xmCOqv1kA== - dependencies: - "@lerna/bootstrap" "3.10.6" - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/npm-conf" "3.7.0" - "@lerna/validation-error" "3.6.0" +"@hapi/topo@3.x.x": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.0.tgz#5c47cd9637c2953db185aa957a27bcb2a8b7a6f8" + integrity sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww== + dependencies: + "@hapi/hoek" "6.x.x" + +"@jest/console@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" + integrity sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg== + dependencies: + "@jest/source-map" "^24.3.0" + chalk "^2.0.1" + slash "^2.0.0" + +"@jest/core@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.7.1.tgz#6707f50db238d0c5988860680e2e414df0032024" + integrity sha512-ivlZ8HX/FOASfHcb5DJpSPFps8ydfUYzLZfgFFqjkLijYysnIEOieg72YRhO4ZUB32xu40hsSMmaw+IGYeKONA== + dependencies: + "@jest/console" "^24.7.1" + "@jest/reporters" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/transform" "^24.7.1" + "@jest/types" "^24.7.0" + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + graceful-fs "^4.1.15" + jest-changed-files "^24.7.0" + jest-config "^24.7.1" + jest-haste-map "^24.7.1" + jest-message-util "^24.7.1" + jest-regex-util "^24.3.0" + jest-resolve-dependencies "^24.7.1" + jest-runner "^24.7.1" + jest-runtime "^24.7.1" + jest-snapshot "^24.7.1" + jest-util "^24.7.1" + jest-validate "^24.7.0" + jest-watcher "^24.7.1" + micromatch "^3.1.10" + p-each-series "^1.0.0" + pirates "^4.0.1" + realpath-native "^1.1.0" + rimraf "^2.5.4" + strip-ansi "^5.0.0" + +"@jest/environment@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.7.1.tgz#9b9196bc737561f67ac07817d4c5ece772e33135" + integrity sha512-wmcTTYc4/KqA+U5h1zQd5FXXynfa7VGP2NfF+c6QeGJ7c+2nStgh65RQWNX62SC716dTtqheTRrZl0j+54oGHw== + dependencies: + "@jest/fake-timers" "^24.7.1" + "@jest/transform" "^24.7.1" + "@jest/types" "^24.7.0" + jest-mock "^24.7.0" + +"@jest/fake-timers@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.7.1.tgz#56e5d09bdec09ee81050eaff2794b26c71d19db2" + integrity sha512-4vSQJDKfR2jScOe12L9282uiwuwQv9Lk7mgrCSZHA9evB9efB/qx8i0KJxsAKtp8fgJYBJdYY7ZU6u3F4/pyjA== + dependencies: + "@jest/types" "^24.7.0" + jest-message-util "^24.7.1" + jest-mock "^24.7.0" + +"@jest/reporters@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.7.1.tgz#38ac0b096cd691bbbe3051ddc25988d42e37773a" + integrity sha512-bO+WYNwHLNhrjB9EbPL4kX/mCCG4ZhhfWmO3m4FSpbgr7N83MFejayz30kKjgqr7smLyeaRFCBQMbXpUgnhAJw== + dependencies: + "@jest/environment" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/transform" "^24.7.1" + "@jest/types" "^24.7.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + istanbul-api "^2.1.1" + istanbul-lib-coverage "^2.0.2" + istanbul-lib-instrument "^3.0.1" + istanbul-lib-source-maps "^3.0.1" + jest-haste-map "^24.7.1" + jest-resolve "^24.7.1" + jest-runtime "^24.7.1" + jest-util "^24.7.1" + jest-worker "^24.6.0" + node-notifier "^5.2.1" + slash "^2.0.0" + source-map "^0.6.0" + string-length "^2.0.0" + +"@jest/source-map@^24.3.0": + version "24.3.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.3.0.tgz#563be3aa4d224caf65ff77edc95cd1ca4da67f28" + integrity sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.1.15" + source-map "^0.6.0" + +"@jest/test-result@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.7.1.tgz#19eacdb29a114300aed24db651e5d975f08b6bbe" + integrity sha512-3U7wITxstdEc2HMfBX7Yx3JZgiNBubwDqQMh+BXmZXHa3G13YWF3p6cK+5g0hGkN3iufg/vGPl3hLxQXD74Npg== + dependencies: + "@jest/console" "^24.7.1" + "@jest/types" "^24.7.0" + "@types/istanbul-lib-coverage" "^2.0.0" + +"@jest/test-sequencer@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.7.1.tgz#9c18e428e1ad945fa74f6233a9d35745ca0e63e0" + integrity sha512-84HQkCpVZI/G1zq53gHJvSmhUer4aMYp9tTaffW28Ih5OxfCg8hGr3nTSbL1OhVDRrFZwvF+/R9gY6JRkDUpUA== + dependencies: + "@jest/test-result" "^24.7.1" + jest-haste-map "^24.7.1" + jest-runner "^24.7.1" + jest-runtime "^24.7.1" + +"@jest/transform@^24.7.1": + version "24.7.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.7.1.tgz#872318f125bcfab2de11f53b465ab1aa780789c2" + integrity sha512-EsOUqP9ULuJ66IkZQhI5LufCHlTbi7hrcllRMUEV/tOgqBVQi93+9qEvkX0n8mYpVXQ8VjwmICeRgg58mrtIEw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^24.7.0" + babel-plugin-istanbul "^5.1.0" + chalk "^2.0.1" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.15" + jest-haste-map "^24.7.1" + jest-regex-util "^24.3.0" + jest-util "^24.7.1" + micromatch "^3.1.10" + realpath-native "^1.1.0" + slash "^2.0.0" + source-map "^0.6.1" + write-file-atomic "2.4.1" + +"@jest/types@^24.7.0": + version "24.7.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.7.0.tgz#c4ec8d1828cdf23234d9b4ee31f5482a3f04f48b" + integrity sha512-ipJUa2rFWiKoBqMKP63Myb6h9+iT3FHRTF2M8OR6irxWzItisa8i4dcSg14IbvmXUnBlHBlUQPYUHWyX3UPpYA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/yargs" "^12.0.9" + +"@lerna/add@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.14.0.tgz#799d416e67d48c285967abf883be746557aefa48" + integrity sha512-Sa79Ju6HqF3heSVpBiYPNrGtuS56U/jMzVq4CcVvhNwB34USLrzJJncGFVcfnuUvsjKeFJv+jHxUycHeRE8XYw== + dependencies: + "@lerna/bootstrap" "3.14.0" + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/npm-conf" "3.13.0" + "@lerna/validation-error" "3.13.0" dedent "^0.7.0" - libnpm "^2.0.1" + npm-package-arg "^6.1.0" p-map "^1.2.0" + pacote "^9.5.0" semver "^5.5.0" -"@lerna/batch-packages@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/batch-packages/-/batch-packages-3.10.6.tgz#2d6dfc9be13ea4da49244dd84bfcd46c3d62f4d0" - integrity sha512-sInr3ZQJFMh9Zq+ZUoVjX8R67j9ViRkVy0uEMsOfG+jZlXj1lRPRMPRiRgU0jXSYEwCdwuAB5pTd9tTx0VCJUw== - dependencies: - "@lerna/package-graph" "3.10.6" - "@lerna/validation-error" "3.6.0" - libnpm "^2.0.1" - -"@lerna/bootstrap@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-3.10.6.tgz#d250baa9cfe9026c4f78e6cf7c9761a90b24e363" - integrity sha512-qbGjAxRpV/eiI9CboUIpsPPGpSogs8mN2/iDaAUBTaWVFVz/YyU64nui84Gll0kbdaHOyPput+kk2S8NCSCCdg== - dependencies: - "@lerna/batch-packages" "3.10.6" - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/has-npm-version" "3.10.0" - "@lerna/npm-install" "3.10.0" - "@lerna/package-graph" "3.10.6" - "@lerna/pulse-till-done" "3.7.1" - "@lerna/rimraf-dir" "3.10.0" - "@lerna/run-lifecycle" "3.10.5" - "@lerna/run-parallel-batches" "3.0.0" - "@lerna/symlink-binary" "3.10.0" - "@lerna/symlink-dependencies" "3.10.0" - "@lerna/validation-error" "3.6.0" +"@lerna/batch-packages@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/batch-packages/-/batch-packages-3.14.0.tgz#0208663bab3ddbf57956b370aaec4c9ebee6c800" + integrity sha512-RlBkQVNTqk1qvn6PFWiWNiskllUHh6tXbTVm43mZRNd+vhAyvrQC8RWJxH0ECVvnFAt9rSNGRIVbEJ31WnNQLg== + dependencies: + "@lerna/package-graph" "3.14.0" + npmlog "^4.1.2" + +"@lerna/bootstrap@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-3.14.0.tgz#dde35eac0a912097033e1daea237a50e5c3cb75b" + integrity sha512-AvnuDp8b0kX4zZgqD3v7ItPABhUsN5CmTEvZBD2JqM+xkQKhzCfz5ABcHEwDwOPWnNQmtH+/2iQdwaD7xBcAXw== + dependencies: + "@lerna/batch-packages" "3.14.0" + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/has-npm-version" "3.13.3" + "@lerna/npm-install" "3.13.3" + "@lerna/package-graph" "3.14.0" + "@lerna/pulse-till-done" "3.13.0" + "@lerna/rimraf-dir" "3.13.3" + "@lerna/run-lifecycle" "3.14.0" + "@lerna/run-parallel-batches" "3.13.0" + "@lerna/symlink-binary" "3.14.0" + "@lerna/symlink-dependencies" "3.14.0" + "@lerna/validation-error" "3.13.0" dedent "^0.7.0" get-port "^3.2.0" - libnpm "^2.0.1" multimatch "^2.1.0" + npm-package-arg "^6.1.0" + npmlog "^4.1.2" p-finally "^1.0.0" p-map "^1.2.0" p-map-series "^1.0.0" @@ -1058,124 +1203,136 @@ read-package-tree "^5.1.6" semver "^5.5.0" -"@lerna/changed@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.10.6.tgz#48fed2e6c890b39a71f1dac29e42a6f853956d71" - integrity sha512-nZDVq/sKdhgoAg1BVnpqjqUUz5+zedG+AnU+6mjEN2f23YVtRCsW55N4I9eEdW2pxXUaCY85Hj/HPSA74BYaFg== +"@lerna/changed@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.14.0.tgz#b3cff6e5d9f1b0c46fb66ede3e95b12ca3b6038f" + integrity sha512-K8PG1iSYhfVt09yQIteO/qwWBIGTeukYx93LQjiTyC8IqLEvjByajN9YH4Gpu1ADKCHeChlwnCHr+2UwQkm0RQ== dependencies: - "@lerna/collect-updates" "3.10.1" - "@lerna/command" "3.10.6" - "@lerna/listable" "3.10.6" - "@lerna/output" "3.6.0" - "@lerna/version" "3.10.6" + "@lerna/collect-updates" "3.14.0" + "@lerna/command" "3.14.0" + "@lerna/listable" "3.14.0" + "@lerna/output" "3.13.0" + "@lerna/version" "3.14.0" -"@lerna/check-working-tree@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-3.10.0.tgz#5ed9f2c5c942bee92afcd8cb5361be44ed0251e3" - integrity sha512-NdIPhDgEtGHfeGjB9F0oAoPLywgMpjnJhLLwTNQkelDHo2xNAVpG8kV+A2UJ+cU5UXCZA4RZFxKNmw86rO+Drw== +"@lerna/check-working-tree@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-3.14.0.tgz#b37c35376b176fa2378a13f009a7575ea0c73bea" + integrity sha512-8PIy2Ia02a0OKES1TiktTIxovzJaFqJcJujBbjjjxaFsXbvSgKp8x1oEHuGIWqPogcxWrmzNd8KAqQMc7iespw== dependencies: - "@lerna/describe-ref" "3.10.0" - "@lerna/validation-error" "3.6.0" + "@lerna/collect-uncommitted" "3.14.0" + "@lerna/describe-ref" "3.13.3" + "@lerna/validation-error" "3.13.0" -"@lerna/child-process@3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-3.3.0.tgz#71184a763105b6c8ece27f43f166498d90fe680f" - integrity sha512-q2d/OPlNX/cBXB6Iz1932RFzOmOHq6ZzPjqebkINNaTojHWuuRpvJJY4Uz3NGpJ3kEtPDvBemkZqUBTSO5wb1g== +"@lerna/child-process@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-3.13.3.tgz#6c084ee5cca9fc9e04d6bf4fc3f743ed26ff190c" + integrity sha512-3/e2uCLnbU+bydDnDwyadpOmuzazS01EcnOleAnuj9235CU2U97DH6OyoG1EW/fU59x11J+HjIqovh5vBaMQjQ== dependencies: chalk "^2.3.1" execa "^1.0.0" strong-log-transformer "^2.0.0" -"@lerna/clean@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-3.10.6.tgz#31e4a12a722e57ca7adc0c9bc30ba70d55572bb8" - integrity sha512-MuL8HOwnyvVtr6GOiAN/Ofjbx+BJdCrtjrM1Uuh8FFnbnZTPVf+0MPxL2jVzPMo0PmoIrX3fvlwvzKNk/lH0Ug== +"@lerna/clean@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-3.14.0.tgz#4399f4a3289106b0b8ffbffd4a6cfd2e3fe935f2" + integrity sha512-wEuAqOS9VMqh2C20KD63IySzyEnyVDqDI3LUsXw+ByUf9AJDgEHv0TCOxbDjDYaaQw1tjSBNZMyYInNeoASwhA== dependencies: - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/prompt" "3.6.0" - "@lerna/pulse-till-done" "3.7.1" - "@lerna/rimraf-dir" "3.10.0" + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/prompt" "3.13.0" + "@lerna/pulse-till-done" "3.13.0" + "@lerna/rimraf-dir" "3.13.3" p-map "^1.2.0" p-map-series "^1.0.0" p-waterfall "^1.0.0" -"@lerna/cli@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-3.10.6.tgz#3ec601d18d0dbaefdee4668d81ce4c4a9488ecf7" - integrity sha512-GtmzJztjrcb5k1Qi/GKNs8xbQBgRpEBoPpt1Udgo23GkepVrQQo45QjM9hyqOhJ6LrV/lfXAv111kDBN/43jLw== +"@lerna/cli@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-3.13.0.tgz#3d7b357fdd7818423e9681a7b7f2abd106c8a266" + integrity sha512-HgFGlyCZbYaYrjOr3w/EsY18PdvtsTmDfpUQe8HwDjXlPeCCUgliZjXLOVBxSjiOvPeOSwvopwIHKWQmYbwywg== dependencies: - "@lerna/global-options" "3.10.6" + "@lerna/global-options" "3.13.0" dedent "^0.7.0" - libnpm "^2.0.1" + npmlog "^4.1.2" yargs "^12.0.1" -"@lerna/collect-updates@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-3.10.1.tgz#3ad60aa31826c0c0cfdf8bf41e58e6c5c86aeb3a" - integrity sha512-vb0wEJ8k63G+2CR/ud1WeVHNJ21Fs6Ew6lbdGZXnF4ZvaFWxWJZpoHeWwzjhMdJ75QdTzUaIhTG1hnH9faQNMw== +"@lerna/collect-uncommitted@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-3.14.0.tgz#7fb4f1eee205de4168aba5218ac81cfc9aeeff9c" + integrity sha512-ermeTGemXEBx1buBDjvQT7ghN32rgOm7nbdxq+TvwVOS52F/c1QVsvN3xu/ZJVMBFXug72cnbJeaHCddl0zhIw== + dependencies: + "@lerna/child-process" "3.13.3" + chalk "^2.3.1" + +"@lerna/collect-updates@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-3.14.0.tgz#64d64ff1ec05ac53dfe6851be49d2ad261e6795e" + integrity sha512-siRHo2atAwj5KpKVOo6QTVIYDYbNs7dzTG6ow9VcFMLKX5shuaEyFA22Z3LmnxQ3sakVFdgvvVeediEz6cM3VA== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/describe-ref" "3.10.0" - libnpm "^2.0.1" + "@lerna/child-process" "3.13.3" + "@lerna/describe-ref" "3.13.3" minimatch "^3.0.4" + npmlog "^4.1.2" slash "^1.0.0" -"@lerna/command@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-3.10.6.tgz#709bd1c66220da67f65dbe1fc88bb7ba5bb85446" - integrity sha512-jPZswMZXOpAaIuSF5hrz+eaWQzbDrvwbrkCoRJKfiAHx7URAkE6MQe9DeAnqrTKMqwfg0RciSrZLc8kWYfrzCQ== +"@lerna/command@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/command/-/command-3.14.0.tgz#5f5e68293c0ff1e85a20b4e96fa6bea33b7632df" + integrity sha512-PtFi5EtXB2VuSruoLsjfZdus56d7oKlZAI4iSRoaS/BBxE2Wyfn7//vW7Ow4hZCzuqb9tBcpDq+4u2pdXN1d2Q== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/package-graph" "3.10.6" - "@lerna/project" "3.10.0" - "@lerna/validation-error" "3.6.0" - "@lerna/write-log-file" "3.6.0" + "@lerna/child-process" "3.13.3" + "@lerna/package-graph" "3.14.0" + "@lerna/project" "3.13.1" + "@lerna/validation-error" "3.13.0" + "@lerna/write-log-file" "3.13.0" dedent "^0.7.0" execa "^1.0.0" is-ci "^1.0.10" - libnpm "^2.0.1" lodash "^4.17.5" + npmlog "^4.1.2" -"@lerna/conventional-commits@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.10.0.tgz#284cc16bd3c387f841ff6bec42bcadaa2d13d8e4" - integrity sha512-8FvO0eR8g/tEgkb6eRVYaD39TsqMKsOXp17EV48jciciEqcrF/d1Ypu6ilK1GDp6R/1m2mbjt/b52a/qrO+xaw== +"@lerna/conventional-commits@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.14.0.tgz#24f643550dc29d4f1249cc26d0eb453d7a1c513d" + integrity sha512-hGZ2qQZ9uEGf2eeIiIpEodSs9Qkkf/2uYEtNT7QN1RYISPUh6/lKGBssc5dpbCF64aEuxmemWLdlDf1ogG6++w== dependencies: - "@lerna/validation-error" "3.6.0" - conventional-changelog-angular "^5.0.2" - conventional-changelog-core "^3.1.5" + "@lerna/validation-error" "3.13.0" + conventional-changelog-angular "^5.0.3" + conventional-changelog-core "^3.1.6" conventional-recommended-bump "^4.0.4" fs-extra "^7.0.0" get-stream "^4.0.0" - libnpm "^2.0.1" + npm-package-arg "^6.1.0" + npmlog "^4.1.2" + pify "^3.0.0" semver "^5.5.0" -"@lerna/create-symlink@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-3.6.0.tgz#f1815cde2fc9d8d2315dfea44ee880f2f1bc65f1" - integrity sha512-YG3lTb6zylvmGqKU+QYA3ylSnoLn+FyLH5XZmUsD0i85R884+EyJJeHx/zUk+yrL2ZwHS4RBUgJfC24fqzgPoA== +"@lerna/create-symlink@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-3.14.0.tgz#f40ae06e8cebe70c694368ebf9a4af5ab380fbea" + integrity sha512-Kw51HYOOi6UfCKncqkgEU1k/SYueSBXgkNL91FR8HAZH7EPSRTEtp9mnJo568g0+Hog5C+3cOaWySwhHpRG29A== dependencies: cmd-shim "^2.0.2" fs-extra "^7.0.0" - libnpm "^2.0.1" + npmlog "^4.1.2" -"@lerna/create@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.10.6.tgz#85c7398cad912516c0ac6054a5c0c4145ab6cadb" - integrity sha512-OddQtGBHM2/eJONggLWoTE6275XGbnJ6dIVF+fLsKS93o4GC6g+qcc6Y7lUWHm5bfpeOwNOVKwj0tvqBZ6MgoA== +"@lerna/create@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.14.0.tgz#ec7a0d4aa81e60c918ea2ba06f3c71ee2855a936" + integrity sha512-J4PeGnzVBOSV7Cih8Uhv9xIauljR9bGcfSDN9aMzFtJhSX0xFXNvmnpXRORp7xNHV2lbxk7mNxRQxzR9CQRMuw== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/command" "3.10.6" - "@lerna/npm-conf" "3.7.0" - "@lerna/validation-error" "3.6.0" - camelcase "^4.1.0" + "@lerna/child-process" "3.13.3" + "@lerna/command" "3.14.0" + "@lerna/npm-conf" "3.13.0" + "@lerna/validation-error" "3.13.0" + camelcase "^5.0.0" dedent "^0.7.0" fs-extra "^7.0.0" globby "^8.0.1" init-package-json "^1.10.3" - libnpm "^2.0.1" + npm-package-arg "^6.1.0" p-reduce "^1.0.0" + pacote "^9.5.0" pify "^3.0.0" semver "^5.5.0" slash "^1.0.0" @@ -1183,404 +1340,464 @@ validate-npm-package-name "^3.0.0" whatwg-url "^7.0.0" -"@lerna/describe-ref@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-3.10.0.tgz#266380feece6013ab9674f52bd35bf0be5b0460d" - integrity sha512-fouh3FQS07QxJJp/mW8LkGnH0xMRAzpBlejtZaiRwfDkW2kd6EuHaj8I/2/p21Wsprcvuu4dqmyia2YS1xFb/w== - dependencies: - "@lerna/child-process" "3.3.0" - libnpm "^2.0.1" - -"@lerna/diff@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-3.10.6.tgz#b4c5a50d8c7e79619376e2c913ec1c627dfd0cdf" - integrity sha512-0MqFhosjrqsIdXiKIu7t3CiJELqiU9mkjFBhYPB7JruAzpPwjMXJnC6/Ur5/7LXJYYVpqGQwZI9ZaZlOYJhhrw== - dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/command" "3.10.6" - "@lerna/validation-error" "3.6.0" - libnpm "^2.0.1" - -"@lerna/exec@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-3.10.6.tgz#5564b614b7e39c1f034f5e0736c9e020945f2f12" - integrity sha512-cdHqaRBMYceJu8rZLO8b4ZeR27O+xKPHgzi13OOOfBJQjrTuacjMWyHgmpy8jWc/0f7QnTl4VsHks7VJ3UK+vw== - dependencies: - "@lerna/batch-packages" "3.10.6" - "@lerna/child-process" "3.3.0" - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/run-parallel-batches" "3.0.0" - "@lerna/validation-error" "3.6.0" - -"@lerna/filter-options@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-3.10.6.tgz#e05a8b8de6efc16c47c83f0ac58291008efba4b8" - integrity sha512-r/dQbqN+RGFKZNn+DyWehswFmAkny/fkdMB2sRM2YVe7zRTtSl95YxD9DtdYnpJTG/jbOVICS/L5QJakrI6SSw== - dependencies: - "@lerna/collect-updates" "3.10.1" - "@lerna/filter-packages" "3.10.0" +"@lerna/describe-ref@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-3.13.3.tgz#13318513613f6a407d37fc5dc025ec2cfb705606" + integrity sha512-5KcLTvjdS4gU5evW8ESbZ0BF44NM5HrP3dQNtWnOUSKJRgsES8Gj0lq9AlB2+YglZfjEftFT03uOYOxnKto4Uw== + dependencies: + "@lerna/child-process" "3.13.3" + npmlog "^4.1.2" + +"@lerna/diff@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-3.14.0.tgz#a4860c062faf990dd3c208dcf1c6fbde5a042bdb" + integrity sha512-H6FSj0jOiQ6unVCwOK6ReT5uZN6ZIn/j/cx4YwuOtU3SMcs3UfuQRIFNeKg/tKmOcQGd39Mn9zDhmt3TAYGROA== + dependencies: + "@lerna/child-process" "3.13.3" + "@lerna/command" "3.14.0" + "@lerna/validation-error" "3.13.0" + npmlog "^4.1.2" + +"@lerna/exec@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-3.14.0.tgz#da632dac4a86d59f7fe8c566af8648f8272241ff" + integrity sha512-cNFO8hWsBVLeqVQ7LsQ4rYKbbQ2eN+Ne+hWKTlUQoyRbYzgJ22TXhjKR6IMr68q0xtclcDlasfcNO+XEWESh0g== + dependencies: + "@lerna/child-process" "3.13.3" + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/run-topologically" "3.14.0" + "@lerna/validation-error" "3.13.0" + p-map "^1.2.0" + +"@lerna/filter-options@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-3.14.0.tgz#6a2e60708633f54973bf31262b58e53efb537ef2" + integrity sha512-ZmNZK9m8evxHc+2ZnDyCm8XFIKVDKpIASG1wtizr3R14t49fuYE7nR+rm4t82u9oSSmER8gb8bGzh0SKZme/jg== + dependencies: + "@lerna/collect-updates" "3.14.0" + "@lerna/filter-packages" "3.13.0" dedent "^0.7.0" -"@lerna/filter-packages@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-3.10.0.tgz#75f9a08184fc4046da2057e0218253cd6f493f05" - integrity sha512-3Acdj+jbany6LnQSuImU4ttcK5ULHSVug8Gh/EvwTewKCDpHAuoI3eyuzZOnSBdMvDOjE03uIESQK0dNNsn6Ow== +"@lerna/filter-packages@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-3.13.0.tgz#f5371249e7e1a15928e5e88c544a242e0162c21c" + integrity sha512-RWiZWyGy3Mp7GRVBn//CacSnE3Kw82PxE4+H6bQ3pDUw/9atXn7NRX+gkBVQIYeKamh7HyumJtyOKq3Pp9BADQ== dependencies: - "@lerna/validation-error" "3.6.0" - libnpm "^2.0.1" + "@lerna/validation-error" "3.13.0" multimatch "^2.1.0" + npmlog "^4.1.2" -"@lerna/get-npm-exec-opts@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.6.0.tgz#ea595eb28d1f34ba61a92ee8391f374282b4b76e" - integrity sha512-ruH6KuLlt75aCObXfUIdVJqmfVq7sgWGq5mXa05vc1MEqxTIiU23YiJdWzofQOOUOACaZkzZ4K4Nu7wXEg4Xgg== +"@lerna/get-npm-exec-opts@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz#d1b552cb0088199fc3e7e126f914e39a08df9ea5" + integrity sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw== dependencies: - libnpm "^2.0.1" + npmlog "^4.1.2" -"@lerna/get-packed@3.7.0": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-3.7.0.tgz#549c7738f7be5e3b1433e82ed9cda9123bcd1ed5" - integrity sha512-yuFtjsUZIHjeIvIYQ/QuytC+FQcHwo3peB+yGBST2uWCLUCR5rx6knoQcPzbxdFDCuUb5IFccFGd3B1fHFg3RQ== +"@lerna/get-packed@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-3.13.0.tgz#335e40d77f3c1855aa248587d3e0b2d8f4b06e16" + integrity sha512-EgSim24sjIjqQDC57bgXD9l22/HCS93uQBbGpkzEOzxAVzEgpZVm7Fm1t8BVlRcT2P2zwGnRadIvxTbpQuDPTg== dependencies: fs-extra "^7.0.0" ssri "^6.0.1" tar "^4.4.8" -"@lerna/global-options@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-3.10.6.tgz#c491a64b0be47eca4ffc875011958a5ee70a9a3e" - integrity sha512-k5Xkq1M/uREFC2R9uwN5gcvIgjj4iOXo0YyeEXCMWBiW3j2GL9xN4d1MmAIcrYlAzVYh6kLlWaFWl/rNIneHIw== +"@lerna/github-client@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-3.13.3.tgz#bcf9b4ff40bdd104cb40cd257322f052b41bb9ce" + integrity sha512-fcJkjab4kX0zcLLSa/DCUNvU3v8wmy2c1lhdIbL7s7gABmDcV0QZq93LhnEee3VkC9UpnJ6GKG4EkD7eIifBnA== + dependencies: + "@lerna/child-process" "3.13.3" + "@octokit/plugin-enterprise-rest" "^2.1.1" + "@octokit/rest" "^16.16.0" + git-url-parse "^11.1.2" + npmlog "^4.1.2" + +"@lerna/global-options@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-3.13.0.tgz#217662290db06ad9cf2c49d8e3100ee28eaebae1" + integrity sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ== -"@lerna/has-npm-version@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-3.10.0.tgz#d3a73c0fedd2f2e9c6fbe166c41809131dc939d2" - integrity sha512-N4RRYxGeivuaKgPDzrhkQOQs1Sg4tOnxnEe3akfqu1wDA4Ng5V6Y2uW3DbkAjFL3aNJhWF5Vbf7sBsGtfgDQ8w== +"@lerna/has-npm-version@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-3.13.3.tgz#167e3f602a2fb58f84f93cf5df39705ca6432a2d" + integrity sha512-mQzoghRw4dBg0R9FFfHrj0TH0glvXyzdEZmYZ8Isvx5BSuEEwpsryoywuZSdppcvLu8o7NAdU5Tac8cJ/mT52w== dependencies: - "@lerna/child-process" "3.3.0" + "@lerna/child-process" "3.13.3" semver "^5.5.0" -"@lerna/import@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.10.6.tgz#36b65854857e8ab5dfd98a1caea4d365ecc06578" - integrity sha512-LlGxhfDhovoNoBJLF3PYd3j/G2GFTnfLh0V38+hBQ6lomMNJbjkACfiLVomQxPWWpYLk0GTlpWYR8YGv6L7Ifw== +"@lerna/import@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.14.0.tgz#de5727dc18d21c50af14b481e47b424c5bbe107c" + integrity sha512-j8z/m85FX1QYPgl5TzMNupdxsQF/NFZSmdCR19HQzqiVKC8ULGzF30WJEk66+KeZ94wYMSakINtYD+41s34pNQ== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/command" "3.10.6" - "@lerna/prompt" "3.6.0" - "@lerna/pulse-till-done" "3.7.1" - "@lerna/validation-error" "3.6.0" + "@lerna/child-process" "3.13.3" + "@lerna/command" "3.14.0" + "@lerna/prompt" "3.13.0" + "@lerna/pulse-till-done" "3.13.0" + "@lerna/validation-error" "3.13.0" dedent "^0.7.0" fs-extra "^7.0.0" p-map-series "^1.0.0" -"@lerna/init@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-3.10.6.tgz#b5c5166b2ddf00ea0f2742a1f53f59221478cf9a" - integrity sha512-RIlEx+ofWLYRNjxCkkV3G0XQPM+/KA5RXRDb5wKQLYO1f+tZAaHoUh8fHDIvxGf/ohY/OIjYYGSsU+ysimfwiQ== +"@lerna/init@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/init/-/init-3.14.0.tgz#f5b92f171f9ed4168bd3d9305fffe6a46460a1d2" + integrity sha512-X3PQkQZds5ozA1xiarmVzAK6LPLNK3bBu24Api0w2KJXO7Ccs9ob/VcGdevZuzqdJo1Xg2H6oBhEqIClU9Uqqw== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/command" "3.10.6" + "@lerna/child-process" "3.13.3" + "@lerna/command" "3.14.0" fs-extra "^7.0.0" p-map "^1.2.0" write-json-file "^2.3.0" -"@lerna/link@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-3.10.6.tgz#4201cabbfc27bebaf1a400f8cfbd238f285dd3c7" - integrity sha512-dwD6qftRWitgLDYbqtDrgO7c8uF5C0fHVew5M6gU5m9tBJidqd7cDwHv/bXboLEI63U7tt5y6LY+wEpYUFsBRw== +"@lerna/link@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/link/-/link-3.14.0.tgz#817243559b3d460a08bd65582e7632b1dbc6df69" + integrity sha512-xlwQhWTVOZrgAuoONY3/OIBWehDfZXmf5qFhnOy7lIxByRhEX5Vwx0ApaGxHTv3Flv7T+oI4s8UZVq5F6dT8Aw== dependencies: - "@lerna/command" "3.10.6" - "@lerna/package-graph" "3.10.6" - "@lerna/symlink-dependencies" "3.10.0" + "@lerna/command" "3.14.0" + "@lerna/package-graph" "3.14.0" + "@lerna/symlink-dependencies" "3.14.0" p-map "^1.2.0" slash "^1.0.0" -"@lerna/list@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-3.10.6.tgz#7c43c09301ea01528f4dab3b22666f021e8ba9a5" - integrity sha512-3ElQBj2dOB4uUkpsjC1bxdeZwEzRBuV1pBBs5E1LncwsZf7D9D99Z32fuZsDaCHpEMgHAD4/j8juI3/7m5dkaQ== +"@lerna/list@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/list/-/list-3.14.0.tgz#cfe826937c63a3652003639eb7fd36bf4b0a3660" + integrity sha512-Gp+9gaIkBfXBwc9Ng0Y74IEfAqpQpLiXwOP4IOpdINxOeDpllhMaYP6SzLaMvrfSyHRayM7Cq5/PRnHkXQ5uuQ== dependencies: - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/listable" "3.10.6" - "@lerna/output" "3.6.0" + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/listable" "3.14.0" + "@lerna/output" "3.13.0" -"@lerna/listable@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-3.10.6.tgz#cea92de89d9f293c6d63e00be662bed03f85c496" - integrity sha512-F7ZuvesSgeuMiJf99eOum5p1MQGQStykcmHH1ek+LQRMiGGF1o3PkBxPvHTZBADGOFarek8bFA5TVmRAMX7NIw== +"@lerna/listable@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-3.14.0.tgz#08f4c78e0466568e8e8a57d4ad09537f2bb7bbb9" + integrity sha512-ZK44Mo8xf/N97eQZ236SPSq0ek6+gk4HqHIx05foEMZVV1iIDH4a/nblLsJNjGQVsIdMYFPaqNJ0z+ZQfiJazQ== dependencies: - "@lerna/batch-packages" "3.10.6" + "@lerna/query-graph" "3.14.0" chalk "^2.3.1" columnify "^1.5.4" -"@lerna/log-packed@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-3.6.0.tgz#bed96c2bdd47f076d9957d0c6069b2edc1518145" - integrity sha512-T/J41zMkzpWB5nbiTRS5PmYTFn74mJXe6RQA2qhkdLi0UqnTp97Pux1loz3jsJf2yJtiQUnyMM7KuKIAge0Vlw== +"@lerna/log-packed@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-3.13.0.tgz#497b5f692a8d0e3f669125da97b0dadfd9e480f3" + integrity sha512-Rmjrcz+6aM6AEcEVWmurbo8+AnHOvYtDpoeMMJh9IZ9SmZr2ClXzmD7wSvjTQc8BwOaiWjjC/ukcT0UYA2m7wg== dependencies: byte-size "^4.0.3" columnify "^1.5.4" has-unicode "^2.0.1" - libnpm "^2.0.1" + npmlog "^4.1.2" -"@lerna/npm-conf@3.7.0": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-3.7.0.tgz#f101d4fdf07cefcf1161bcfaf3c0f105b420a450" - integrity sha512-+WSMDfPKcKzMfqq283ydz9RRpOU6p9wfx0wy4hVSUY/6YUpsyuk8SShjcRtY8zTM5AOrxvFBuuV90H4YpZ5+Ng== +"@lerna/npm-conf@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-3.13.0.tgz#6b434ed75ff757e8c14381b9bbfe5d5ddec134a7" + integrity sha512-Jg2kANsGnhg+fbPEzE0X9nX5oviEAvWj0nYyOkcE+cgWuT7W0zpnPXC4hA4C5IPQGhwhhh0IxhWNNHtjTuw53g== dependencies: config-chain "^1.1.11" pify "^3.0.0" -"@lerna/npm-dist-tag@3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-3.8.5.tgz#5ce22a72576badc8cb6baf85550043d63e66ea44" - integrity sha512-VO57yKTB4NC2LZuTd4w0LmlRpoFm/gejQ1gqqLGzSJuSZaBXmieElFovzl21S07cqiy7FNVdz75x7/a6WCZ6XA== +"@lerna/npm-dist-tag@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-3.14.0.tgz#69b1f99ce9d777782afe646522cb14293d986eb5" + integrity sha512-DEyYEdufTGIC6E4RTJUsYPgqlz1Bs/XPeEQ5fd+ojWnICevj7dRrr2DfHucPiUCADlm2jbAraAQc3QPU0dXRhw== dependencies: + "@lerna/otplease" "3.14.0" figgy-pudding "^3.5.1" - libnpm "^2.0.1" + npm-package-arg "^6.1.0" + npm-registry-fetch "^3.9.0" + npmlog "^4.1.2" -"@lerna/npm-install@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-3.10.0.tgz#fcd6688a3a2cd0e702a03c54c22eb7ae8b3dacb0" - integrity sha512-/6/XyLY9/4jaMPBOVYUr4wZxQURIfwoELY0qCQ8gZ5zv4cOiFiiCUxZ0i4fxqFtD7nJ084zq1DsZW0aH0CIWYw== +"@lerna/npm-install@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-3.13.3.tgz#9b09852732e51c16d2e060ff2fd8bfbbb49cf7ba" + integrity sha512-7Jig9MLpwAfcsdQ5UeanAjndChUjiTjTp50zJ+UZz4CbIBIDhoBehvNMTCL2G6pOEC7sGEg6sAqJINAqred6Tg== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/get-npm-exec-opts" "3.6.0" + "@lerna/child-process" "3.13.3" + "@lerna/get-npm-exec-opts" "3.13.0" fs-extra "^7.0.0" - libnpm "^2.0.1" + npm-package-arg "^6.1.0" + npmlog "^4.1.2" signal-exit "^3.0.2" write-pkg "^3.1.0" -"@lerna/npm-publish@3.10.5": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-3.10.5.tgz#b2eb47cd7f3d1cdbfe32a13140017348ffe0e204" - integrity sha512-6wpgTfu5A5jJeB8RnH2n01HzfaB4Y9aKC0Tq0AAkw37PZ12LTgEL9I+ZZPqhUVFIFLB8/Ekpnj3AcKznJLG5xQ== +"@lerna/npm-publish@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-3.14.0.tgz#e3fc5613a2dd08cdd3323347ba87fad5dc5f11fb" + integrity sha512-ShG0qEnGkWxtjQvIRATgm/CzeoVaSyyoNRag5t8gDSR/r2u9ux72oROKQUEaE8OwcTS4rL2cyBECts8XMNmyYw== dependencies: - "@lerna/run-lifecycle" "3.10.5" + "@lerna/otplease" "3.14.0" + "@lerna/run-lifecycle" "3.14.0" figgy-pudding "^3.5.1" fs-extra "^7.0.0" - libnpm "^2.0.1" + libnpmpublish "^1.1.1" + npm-package-arg "^6.1.0" + npmlog "^4.1.2" + pify "^3.0.0" + read-package-json "^2.0.13" -"@lerna/npm-run-script@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-3.10.0.tgz#49a9204eddea136da15a8d8d9eba2c3175b77ddd" - integrity sha512-c21tBXLF1Wje4tx/Td9jKIMrlZo/8QQiyyadjdKpwyyo7orSMsVNXGyJwvZ4JVVDcwC3GPU6HQvkt63v7rcyaw== +"@lerna/npm-run-script@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-3.13.3.tgz#9bb6389ed70cd506905d6b05b6eab336b4266caf" + integrity sha512-qR4o9BFt5hI8Od5/DqLalOJydnKpiQFEeN0h9xZi7MwzuX1Ukwh3X22vqsX4YRbipIelSFtrDzleNVUm5jj0ow== dependencies: - "@lerna/child-process" "3.3.0" - "@lerna/get-npm-exec-opts" "3.6.0" - libnpm "^2.0.1" + "@lerna/child-process" "3.13.3" + "@lerna/get-npm-exec-opts" "3.13.0" + npmlog "^4.1.2" -"@lerna/output@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-3.6.0.tgz#a69384bc685cf3b21aa1bfc697eb2b9db3333d0b" - integrity sha512-9sjQouf6p7VQtVCRnzoTGlZyURd48i3ha3WBHC/UBJnHZFuXMqWVPKNuvnMf2kRXDyoQD+2mNywpmEJg5jOnRg== +"@lerna/otplease@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-3.14.0.tgz#b539fd3e7a08452fc0db3b10010ca3cf0e4a73e7" + integrity sha512-rYAWzaYZ81bwnrmTkYWGgcc13bl/6DlG7pjWQWNGAJNLzO5zzj0xmXN5sMFJnNvDpSiS/ZS1sIuPvb4xnwLUkg== + dependencies: + "@lerna/prompt" "3.13.0" + figgy-pudding "^3.5.1" + +"@lerna/output@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/output/-/output-3.13.0.tgz#3ded7cc908b27a9872228a630d950aedae7a4989" + integrity sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg== dependencies: - libnpm "^2.0.1" + npmlog "^4.1.2" -"@lerna/pack-directory@3.10.5": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-3.10.5.tgz#9bdabceacb74e1f54e47bae925e193978f2aae51" - integrity sha512-Ulj24L9XdgjJIxBr6ZjRJEoBULVH3c10lqunUdW41bswXhzhirRtQIxv0+5shngNjDwgMmJfOBcuCVKPSez4tg== +"@lerna/pack-directory@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-3.14.0.tgz#229446c2e3f307a7932f2f779d7fb8b8ff7d93b0" + integrity sha512-E9PmC1oWYjYN8Z0Oeoj7X98NruMg/pcdDiRxnwJ5awnB0d/kyfoquHXCYwCQQFCnWUfto7m5lM4CSostcolEVQ== dependencies: - "@lerna/get-packed" "3.7.0" - "@lerna/package" "3.7.2" - "@lerna/run-lifecycle" "3.10.5" + "@lerna/get-packed" "3.13.0" + "@lerna/package" "3.13.0" + "@lerna/run-lifecycle" "3.14.0" figgy-pudding "^3.5.1" - libnpm "^2.0.1" - npm-packlist "^1.1.12" + npm-packlist "^1.4.1" + npmlog "^4.1.2" tar "^4.4.8" temp-write "^3.4.0" -"@lerna/package-graph@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-3.10.6.tgz#8940d1ed7003100117cb1b618f7690585c00db81" - integrity sha512-mpIOJbhi+xLqT9BcUrLVD4We8WUdousQf/QndbEWl8DWAW1ethtRHVsCm9ufdBB3F9nj4PH/hqnDWWwqE+rS4w== +"@lerna/package-graph@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-3.14.0.tgz#4ccdf446dccedfbbeb4efff3eb720cb6fcb109fc" + integrity sha512-dNpA/64STD5YXhaSlg4gT6Z474WPJVCHoX1ibsVIFu0fVgH609Y69bsdmbvTRdI7r6Dcu4ZfGxdR636RTrH+Eg== dependencies: - "@lerna/validation-error" "3.6.0" - libnpm "^2.0.1" + "@lerna/prerelease-id-from-version" "3.14.0" + "@lerna/validation-error" "3.13.0" + npm-package-arg "^6.1.0" + npmlog "^4.1.2" semver "^5.5.0" -"@lerna/package@3.7.2": - version "3.7.2" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-3.7.2.tgz#03c69fd7fb965c372c8c969165a2f7d6dfe2dfcb" - integrity sha512-8A5hN2CekM1a0Ix4VUO/g+REo+MsnXb8lnQ0bGjr1YGWzSL5NxYJ0Z9+0pwTfDpvRDYlFYO0rMVwBUW44b4dUw== +"@lerna/package@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/package/-/package-3.13.0.tgz#4baeebc49a57fc9b31062cc59f5ee38384429fc8" + integrity sha512-kSKO0RJQy093BufCQnkhf1jB4kZnBvL7kK5Ewolhk5gwejN+Jofjd8DGRVUDUJfQ0CkW1o6GbUeZvs8w8VIZDg== dependencies: - libnpm "^2.0.1" load-json-file "^4.0.0" + npm-package-arg "^6.1.0" write-pkg "^3.1.0" -"@lerna/project@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-3.10.0.tgz#98272bf2eb93e9b21850edae568d696bf7fdebda" - integrity sha512-9QRl8aGHuyU4zVEELQmNPnJTlS7XHqX7w9I9isCXdnilKc2R0MyvUs21lj6Yyt6xTuQnqD158TR9tbS4QufYQQ== +"@lerna/prerelease-id-from-version@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.14.0.tgz#d5da9c26ac4a0d0ecde09018f06e41ca4dd444c2" + integrity sha512-Ap3Z/dNhqQuSrKmK+JmzYvQYI2vowxHvUVxZJiDVilW8dyNnxkCsYFmkuZytk5sxVz4VeGLNPS2RSsU5eeSS+Q== dependencies: - "@lerna/package" "3.7.2" - "@lerna/validation-error" "3.6.0" - cosmiconfig "^5.0.2" + semver "^5.5.0" + +"@lerna/project@3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@lerna/project/-/project-3.13.1.tgz#bce890f60187bd950bcf36c04b5260642e295e79" + integrity sha512-/GoCrpsCCTyb9sizk1+pMBrIYchtb+F1uCOn3cjn9yenyG/MfYEnlfrbV5k/UDud0Ei75YBLbmwCbigHkAKazQ== + dependencies: + "@lerna/package" "3.13.0" + "@lerna/validation-error" "3.13.0" + cosmiconfig "^5.1.0" dedent "^0.7.0" dot-prop "^4.2.0" glob-parent "^3.1.0" globby "^8.0.1" - libnpm "^2.0.1" load-json-file "^4.0.0" + npmlog "^4.1.2" p-map "^1.2.0" resolve-from "^4.0.0" write-json-file "^2.3.0" -"@lerna/prompt@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-3.6.0.tgz#b17cc464dec9d830619723e879dc747367378217" - integrity sha512-nyAjPMolJ/ZRAAVcXrUH89C4n1SiWvLh4xWNvWYKLcf3PI5yges35sDFP/HYrM4+cEbkNFuJCRq6CxaET4PRsg== +"@lerna/prompt@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-3.13.0.tgz#53571462bb3f5399cc1ca6d335a411fe093426a5" + integrity sha512-P+lWSFokdyvYpkwC3it9cE0IF2U5yy2mOUbGvvE4iDb9K7TyXGE+7lwtx2thtPvBAfIb7O13POMkv7df03HJeA== dependencies: inquirer "^6.2.0" - libnpm "^2.0.1" - -"@lerna/publish@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.10.6.tgz#bebd0d8fd820e1e63f6e9e6673aa41e9c4c61b3b" - integrity sha512-Wrmgf82rtZWdHSrTzZGOi1/QbkPJduUSmVMhZsdnLC814WHrNGYKbayvFBOo1RAAJ4EKggZ2ReOWXKhg/IZYUw== - dependencies: - "@lerna/batch-packages" "3.10.6" - "@lerna/check-working-tree" "3.10.0" - "@lerna/child-process" "3.3.0" - "@lerna/collect-updates" "3.10.1" - "@lerna/command" "3.10.6" - "@lerna/describe-ref" "3.10.0" - "@lerna/log-packed" "3.6.0" - "@lerna/npm-conf" "3.7.0" - "@lerna/npm-dist-tag" "3.8.5" - "@lerna/npm-publish" "3.10.5" - "@lerna/output" "3.6.0" - "@lerna/pack-directory" "3.10.5" - "@lerna/prompt" "3.6.0" - "@lerna/pulse-till-done" "3.7.1" - "@lerna/run-lifecycle" "3.10.5" - "@lerna/run-parallel-batches" "3.0.0" - "@lerna/validation-error" "3.6.0" - "@lerna/version" "3.10.6" + npmlog "^4.1.2" + +"@lerna/publish@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.14.0.tgz#3473c6de9ad7d614cc2a734eaf4ea505e8fedc4f" + integrity sha512-nLL0eDF/rgijPoLGGdHkuKQ4ktLZZDmPpj5n4aIZHf56AZRUYL0NgzLVPqg3btYQ/Zze9Wst1CB08DnBwJOzTw== + dependencies: + "@lerna/check-working-tree" "3.14.0" + "@lerna/child-process" "3.13.3" + "@lerna/collect-updates" "3.14.0" + "@lerna/command" "3.14.0" + "@lerna/describe-ref" "3.13.3" + "@lerna/log-packed" "3.13.0" + "@lerna/npm-conf" "3.13.0" + "@lerna/npm-dist-tag" "3.14.0" + "@lerna/npm-publish" "3.14.0" + "@lerna/output" "3.13.0" + "@lerna/pack-directory" "3.14.0" + "@lerna/prerelease-id-from-version" "3.14.0" + "@lerna/prompt" "3.13.0" + "@lerna/pulse-till-done" "3.13.0" + "@lerna/run-lifecycle" "3.14.0" + "@lerna/run-topologically" "3.14.0" + "@lerna/validation-error" "3.13.0" + "@lerna/version" "3.14.0" figgy-pudding "^3.5.1" fs-extra "^7.0.0" - libnpm "^2.0.1" + libnpmaccess "^3.0.1" + npm-package-arg "^6.1.0" + npm-registry-fetch "^3.9.0" + npmlog "^4.1.2" p-finally "^1.0.0" p-map "^1.2.0" p-pipe "^1.2.0" - p-reduce "^1.0.0" + pacote "^9.5.0" semver "^5.5.0" -"@lerna/pulse-till-done@3.7.1": - version "3.7.1" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-3.7.1.tgz#a9e55380fa18f6896a3e5b23621a4227adfb8f85" - integrity sha512-MzpesZeW3Mc+CiAq4zUt9qTXI9uEBBKrubYHE36voQTSkHvu/Rox6YOvfUr+U7P6k8frFPeCgGpfMDTLhiqe6w== +"@lerna/pulse-till-done@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz#c8e9ce5bafaf10d930a67d7ed0ccb5d958fe0110" + integrity sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA== dependencies: - libnpm "^2.0.1" + npmlog "^4.1.2" -"@lerna/resolve-symlink@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-3.6.0.tgz#985344796b704ff32afa923901e795e80741b86e" - integrity sha512-TVOAEqHJSQVhNDMFCwEUZPaOETqHDQV1TQWQfC8ZlOqyaUQ7veZUbg0yfG7RPNzlSpvF0ZaGFeR0YhYDAW03GA== +"@lerna/query-graph@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-3.14.0.tgz#2abb36f445bd924d0f85ac7aec1445e9ef1e2c6c" + integrity sha512-6YTh3vDMW2hUxHdKeRvx4bosc9lZClKaN+DzC1XKTkwDbWrsjmEzLcemKL6QnyyeuryN2f/eto7P9iSe3z3pQQ== + dependencies: + "@lerna/package-graph" "3.14.0" + figgy-pudding "^3.5.1" + +"@lerna/resolve-symlink@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-3.13.0.tgz#3e6809ef53b63fe914814bfa071cd68012e22fbb" + integrity sha512-Lc0USSFxwDxUs5JvIisS8JegjA6SHSAWJCMvi2osZx6wVRkEDlWG2B1JAfXUzCMNfHoZX0/XX9iYZ+4JIpjAtg== dependencies: fs-extra "^7.0.0" - libnpm "^2.0.1" + npmlog "^4.1.2" read-cmd-shim "^1.0.1" -"@lerna/rimraf-dir@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-3.10.0.tgz#2d9435054ab7bbc5519db0a2654c5d8cacd27f98" - integrity sha512-RSKSfxPURc58ERCD/PuzorR86lWEvIWNclXYGvIYM76yNGrWiDF44pGHQvB4J+Lxa5M+52ZtZC/eOC7A7YCH4g== +"@lerna/rimraf-dir@3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-3.13.3.tgz#3a8e71317fde853893ef0262bc9bba6a180b7227" + integrity sha512-d0T1Hxwu3gpYVv73ytSL+/Oy8JitsmvOYUR5ouRSABsmqS7ZZCh5t6FgVDDGVXeuhbw82+vuny1Og6Q0k4ilqw== dependencies: - "@lerna/child-process" "3.3.0" - libnpm "^2.0.1" + "@lerna/child-process" "3.13.3" + npmlog "^4.1.2" path-exists "^3.0.0" rimraf "^2.6.2" -"@lerna/run-lifecycle@3.10.5": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-3.10.5.tgz#ea4422bb70c0f8d4382ecb2a626c8ba0ca88550b" - integrity sha512-YPmXviaxVlhcKM6IkDTIpTq24mxOuMCilo+MTr1RLoafgB9ZTmP2AHRiFt/sy14wOsq2Zqr0wJyj8KFlDYLTkA== +"@lerna/run-lifecycle@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-3.14.0.tgz#0499eca0e7f393faf4e24e6c8737302a9059c22b" + integrity sha512-GUM3L9MzGRSW0WQ8wbLW1+SYStU1OFjW0GBzShhBnFrO4nGRrU7VchsLpcLu0hk2uCzyhsrDKzifEdOdUyMoEQ== dependencies: - "@lerna/npm-conf" "3.7.0" + "@lerna/npm-conf" "3.13.0" figgy-pudding "^3.5.1" - libnpm "^2.0.1" + npm-lifecycle "^2.1.1" + npmlog "^4.1.2" -"@lerna/run-parallel-batches@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-parallel-batches/-/run-parallel-batches-3.0.0.tgz#468704934084c74991d3124d80607857d4dfa840" - integrity sha512-Mj1ravlXF7AkkewKd9YFq9BtVrsStNrvVLedD/b2wIVbNqcxp8lS68vehXVOzoL/VWNEDotvqCQtyDBilCodGw== +"@lerna/run-parallel-batches@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/run-parallel-batches/-/run-parallel-batches-3.13.0.tgz#0276bb4e7cd0995297db82d134ca2bd08d63e311" + integrity sha512-bICFBR+cYVF1FFW+Tlm0EhWDioTUTM6dOiVziDEGE1UZha1dFkMYqzqdSf4bQzfLS31UW/KBd/2z8jy2OIjEjg== dependencies: p-map "^1.2.0" p-map-series "^1.0.0" -"@lerna/run@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-3.10.6.tgz#4c159a719b0ec010409dfe8f9535c9a3c3f3e06a" - integrity sha512-KS2lWbu/8WUUscQPi9U8sPO6yYpzf/0GmODjpruR1nRi1u/tuncdjTiG+hjGAeFC1BD7YktT9Za6imIpE8RXmA== - dependencies: - "@lerna/batch-packages" "3.10.6" - "@lerna/command" "3.10.6" - "@lerna/filter-options" "3.10.6" - "@lerna/npm-run-script" "3.10.0" - "@lerna/output" "3.6.0" - "@lerna/run-parallel-batches" "3.0.0" - "@lerna/timer" "3.5.0" - "@lerna/validation-error" "3.6.0" +"@lerna/run-topologically@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-3.14.0.tgz#2a560cb657f0ef1565c680b6001b4b01b872dc07" + integrity sha512-y+KBpC1YExFzGynovt9MY4O/bc3RrJaKeuXieiPfKGKxrdtmZe/r33oj/xePTXZq65jnw3SaU3H8S5CrrdkwDg== + dependencies: + "@lerna/query-graph" "3.14.0" + figgy-pudding "^3.5.1" + p-queue "^4.0.0" + +"@lerna/run@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/run/-/run-3.14.0.tgz#1a5d3330149fbf5092012707b775d5f57d9d0057" + integrity sha512-kGGFGLYPKozAN07CSJ7kOyLY6W3oLCQcxCathg1isSkBqQH29tWUg8qNduOlhIFLmnq/nf1JEJxxoXnF6IRLjQ== + dependencies: + "@lerna/command" "3.14.0" + "@lerna/filter-options" "3.14.0" + "@lerna/npm-run-script" "3.13.3" + "@lerna/output" "3.13.0" + "@lerna/run-topologically" "3.14.0" + "@lerna/timer" "3.13.0" + "@lerna/validation-error" "3.13.0" p-map "^1.2.0" -"@lerna/symlink-binary@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-3.10.0.tgz#5acdde86dfd50c9270d7d2a93bade203cff41b3d" - integrity sha512-6mQsG+iVjBo8cD8s24O+YgFrwDyUGfUQbK4ryalAXFHI817Zd4xlI3tjg3W99whCt6rt6D0s1fpf8eslMN6dSw== +"@lerna/symlink-binary@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-3.14.0.tgz#db1c3204b83d91c4b43386302ee76cea4d20bc3f" + integrity sha512-AHFb4NlazxYmC+7guoamM3laIRbMSeKERMooKHJ7moe0ayGPBWsCGOH+ZFKZ+eXSDek+FnxdzayR3wf8B3LkTg== dependencies: - "@lerna/create-symlink" "3.6.0" - "@lerna/package" "3.7.2" + "@lerna/create-symlink" "3.14.0" + "@lerna/package" "3.13.0" fs-extra "^7.0.0" p-map "^1.2.0" -"@lerna/symlink-dependencies@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-3.10.0.tgz#a20226e8e97af6a6bc4b416bfc28c0c5e3ba9ddd" - integrity sha512-vGpg5ydwGgQCuWNX5y7CRL38mGpuLhf1GRq9wMm7IGwnctEsdSNqvvE+LDgqtwEZASu5+vffYUkL0VlFXl8uWA== +"@lerna/symlink-dependencies@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-3.14.0.tgz#f17e5cd704a0f067636038dafeaf42b5d2f28802" + integrity sha512-kuSXxwAWiVZqFcXfUBKH4yLUH3lrnGyZmCYon7UnZitw3AK3LQY7HvV2LNNw/oatfjOAiKhPBxnYjYijKiV4oA== dependencies: - "@lerna/create-symlink" "3.6.0" - "@lerna/resolve-symlink" "3.6.0" - "@lerna/symlink-binary" "3.10.0" + "@lerna/create-symlink" "3.14.0" + "@lerna/resolve-symlink" "3.13.0" + "@lerna/symlink-binary" "3.14.0" fs-extra "^7.0.0" p-finally "^1.0.0" p-map "^1.2.0" p-map-series "^1.0.0" -"@lerna/timer@3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-3.5.0.tgz#8dee6acf002c55de64678c66ef37ca52143f1b9b" - integrity sha512-TAb99hqQN6E3JBGtG9iyZNPq1/DbmqgBOeNrKtdJsGvIeX/NGLgUDWMrj2h04V4O+jpBFmSf6HIld6triKmxCA== +"@lerna/timer@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-3.13.0.tgz#bcd0904551db16e08364d6c18e5e2160fc870781" + integrity sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw== -"@lerna/validation-error@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-3.6.0.tgz#550cf66bb2ef88edc02e36017b575a7a9100d5d8" - integrity sha512-MWltncGO5VgMS0QedTlZCjFUMF/evRjDMMHrtVorkIB2Cp5xy0rkKa8iDBG43qpUWeG1giwi58yUlETBcWfILw== - dependencies: - libnpm "^2.0.1" - -"@lerna/version@3.10.6": - version "3.10.6" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.10.6.tgz#c31c2bb1aabbdc851407534155567b5cdf48e0fb" - integrity sha512-77peW2ROlHHl1e/tHBUmhpb8tsO6CIdlx34XapZhUuIVykrkOuqVFFxqMecrGG8SJe0e3l1G+Fah7bJTQcG0kw== - dependencies: - "@lerna/batch-packages" "3.10.6" - "@lerna/check-working-tree" "3.10.0" - "@lerna/child-process" "3.3.0" - "@lerna/collect-updates" "3.10.1" - "@lerna/command" "3.10.6" - "@lerna/conventional-commits" "3.10.0" - "@lerna/output" "3.6.0" - "@lerna/prompt" "3.6.0" - "@lerna/run-lifecycle" "3.10.5" - "@lerna/validation-error" "3.6.0" +"@lerna/validation-error@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-3.13.0.tgz#c86b8f07c5ab9539f775bd8a54976e926f3759c3" + integrity sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA== + dependencies: + npmlog "^4.1.2" + +"@lerna/version@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.14.0.tgz#3b3ed1da7241383e22f506198f35e4bb61c146c8" + integrity sha512-51ae6sriSLONV1NnPtDNuC81fGQhQBL1FhSKbw+5WuNdJxJwG8bgEdS1xvUdETZT4WrwMCX3nzzSpu4owlH2nQ== + dependencies: + "@lerna/batch-packages" "3.14.0" + "@lerna/check-working-tree" "3.14.0" + "@lerna/child-process" "3.13.3" + "@lerna/collect-updates" "3.14.0" + "@lerna/command" "3.14.0" + "@lerna/conventional-commits" "3.14.0" + "@lerna/github-client" "3.13.3" + "@lerna/output" "3.13.0" + "@lerna/prerelease-id-from-version" "3.14.0" + "@lerna/prompt" "3.13.0" + "@lerna/run-lifecycle" "3.14.0" + "@lerna/run-topologically" "3.14.0" + "@lerna/validation-error" "3.13.0" chalk "^2.3.1" dedent "^0.7.0" - libnpm "^2.0.1" minimatch "^3.0.4" + npmlog "^4.1.2" p-map "^1.2.0" p-pipe "^1.2.0" p-reduce "^1.0.0" @@ -1589,12 +1806,12 @@ slash "^1.0.0" temp-write "^3.4.0" -"@lerna/write-log-file@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-3.6.0.tgz#b8d5a7efc84fa93cbd67d724d11120343b2a849a" - integrity sha512-OkLK99V6sYXsJsYg+O9wtiFS3z6eUPaiz2e6cXJt80mfIIdI1t2dnmyua0Ib5cZWExQvx2z6Y32Wlf0MnsoNsA== +"@lerna/write-log-file@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-3.13.0.tgz#b78d9e4cfc1349a8be64d91324c4c8199e822a26" + integrity sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A== dependencies: - libnpm "^2.0.1" + npmlog "^4.1.2" write-file-atomic "^2.3.0" "@mrmlnc/readdir-enhanced@^2.2.1": @@ -1610,29 +1827,232 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -JSONStream@^1.0.4, JSONStream@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== +"@octokit/endpoint@^3.2.0": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-3.2.3.tgz#bd9aea60cd94ce336656b57a5c9cb7f10be8f4f3" + integrity sha512-yUPCt4vMIOclox13CUxzuKiPJIFo46b/6GhUnUTw5QySczN1L0DtSxgmIZrZV4SAb9EyAqrceoyrWoYVnfF2AA== dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -abab@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + deepmerge "3.2.0" + is-plain-object "^2.0.4" + universal-user-agent "^2.0.1" + url-template "^2.0.8" -absolute-path@^0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/absolute-path/-/absolute-path-0.0.0.tgz#a78762fbdadfb5297be99b15d35a785b2f095bf7" +"@octokit/plugin-enterprise-rest@^2.1.1": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-2.2.2.tgz#c0e22067a043e19f96ff9c7832e2a3019f9be75c" + integrity sha512-CTZr64jZYhGWNTDGlSJ2mvIlFsm9OEO3LqWn9I/gmoHI4jRBp4kpHoFYNemG4oA75zUAcmbuWblb7jjP877YZw== -accepts@~1.3.3, accepts@~1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" +"@octokit/request@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-2.4.2.tgz#87c36e820dd1e43b1629f4f35c95b00cd456320b" + integrity sha512-lxVlYYvwGbKSHXfbPk5vxEA8w4zHOH1wobado4a9EfsyD3Cbhuhus1w0Ye9Ro0eMubGO8kNy5d+xNFisM3Tvaw== + dependencies: + "@octokit/endpoint" "^3.2.0" + deprecation "^1.0.1" + is-plain-object "^2.0.4" + node-fetch "^2.3.0" + once "^1.4.0" + universal-user-agent "^2.0.1" + +"@octokit/rest@^15.2.6": + version "15.18.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.18.1.tgz#ec7fb0f8775ef64dc095fae6635411d3fbff9b62" + integrity sha512-g2tecjp2TEtYV8bKAFvfQtu+W29HM7ektmWmw8zrMy9/XCKDEYRErR2YvvhN9+IxkLC4O3lDqYP4b6WgsL6Utw== + dependencies: + before-after-hook "^1.1.0" + btoa-lite "^1.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lodash "^4.17.4" + node-fetch "^2.1.1" + universal-user-agent "^2.0.0" + url-template "^2.0.8" + +"@octokit/rest@^16.16.0": + version "16.20.0" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.20.0.tgz#54462b6e540b5d40063850d370ce8e084cf127d6" + integrity sha512-tN5j64P6QymlMzKo94DG1LRNHCwMnLg5poZlVhsCfkHhEWKpofZ1qBDr2/0w6qDLav4EA1XXMmZdNpvGhc9BDQ== + dependencies: + "@octokit/request" "2.4.2" + before-after-hook "^1.4.0" + btoa-lite "^1.0.0" + deprecation "^1.0.1" + lodash.get "^4.4.2" + lodash.set "^4.3.2" + lodash.uniq "^4.5.0" + octokit-pagination-methods "^1.1.0" + once "^1.4.0" + universal-user-agent "^2.0.0" + url-template "^2.0.8" + +"@react-native-community/eslint-config@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@react-native-community/eslint-config/-/eslint-config-0.0.5.tgz#584f6493258202a57efc22e7be66966e43832795" + integrity sha512-jwO2tnKaTPTLX5XYXMHGEnFdf543SU7jz98/OF5mDH3b7lP+BOaCD+jVfqqHoDRkcqyPlYiR1CgwVGWpi0vMWg== + dependencies: + "@typescript-eslint/eslint-plugin" "^1.5.0" + "@typescript-eslint/parser" "^1.5.0" + babel-eslint "10.0.1" + eslint-plugin-eslint-comments "^3.1.1" + eslint-plugin-flowtype "2.50.3" + eslint-plugin-jest "22.4.1" + eslint-plugin-prettier "2.6.2" + eslint-plugin-react "7.12.4" + eslint-plugin-react-hooks "^1.5.1" + eslint-plugin-react-native "3.6.0" + prettier "1.16.4" + +"@types/babel__core@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.0.tgz#710f2487dda4dcfd010ca6abb2b4dc7394365c51" + integrity sha512-wJTeJRt7BToFx3USrCDs2BhEi4ijBInTQjOIukj6a/5tEkwpFMVZ+1ppgmE+Q/FQyc5P/VWUbx7I9NELrKruHA== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.0.2.tgz#d2112a6b21fad600d7674274293c85dce0cb47fc" + integrity sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.6.tgz#328dd1a8fc4cfe3c8458be9477b219ea158fd7b2" + integrity sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw== + dependencies: + "@babel/types" "^7.3.0" + +"@types/istanbul-lib-coverage@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz#1eb8c033e98cf4e1a4cedcaf8bcafe8cb7591e85" + integrity sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg== + +"@types/jest-diff@*": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" + integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== + +"@types/jest@^24.0.11": + version "24.0.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.11.tgz#1f099bea332c228ea6505a88159bfa86a5858340" + integrity sha512-2kLuPC5FDnWIDvaJBzsGTBQaBbnDweznicvK7UGYzlIJP4RJR2a4A/ByLUXEyEgag6jz8eHdlWExGDtH3EYUXQ== + dependencies: + "@types/jest-diff" "*" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/lodash@^4.14.123": + version "4.14.123" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d" + integrity sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q== + +"@types/mime@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + +"@types/node-fetch@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.3.3.tgz#eb9c2a0ce8e9424ebe0c0cbe6f1e8ea7576c1310" + integrity sha512-MIplfRxrDTsIbOLGyFqNWTmxho5Fs710Kul35tEcaqkx9He86mGbSCDvILL0LCMfmm+oJ8tDg51crE9+pJGgiQ== + dependencies: + "@types/node" "*" + +"@types/node-fetch@^2.3.7": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.3.7.tgz#b7212e895100f8642dbdab698472bab5f3c1d2f1" + integrity sha512-+bKtuxhj/TYSSP1r4CZhfmyA0vm/aDRQNo7vbAgf6/cZajn0SAniGGST07yvI4Q+q169WTa2/x9gEHfJrkcALw== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5" + integrity sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg== + +"@types/node@^11.13.0": + version "11.13.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1" + integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng== + +"@types/stack-utils@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" + integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== + +"@types/yargs@^12.0.2", "@types/yargs@^12.0.9": + version "12.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916" + integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw== + +"@typescript-eslint/eslint-plugin@^1.5.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.6.0.tgz#a5ff3128c692393fb16efa403ec7c8a5593dab0f" + integrity sha512-U224c29E2lo861TQZs6GSmyC0OYeRNg6bE9UVIiFBxN2MlA0nq2dCrgIVyyRbC05UOcrgf2Wk/CF2gGOPQKUSQ== + dependencies: + "@typescript-eslint/parser" "1.6.0" + "@typescript-eslint/typescript-estree" "1.6.0" + requireindex "^1.2.0" + tsutils "^3.7.0" + +"@typescript-eslint/parser@1.6.0", "@typescript-eslint/parser@^1.5.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.6.0.tgz#f01189c8b90848e3b8e45a6cdad27870529d1804" + integrity sha512-VB9xmSbfafI+/kI4gUK3PfrkGmrJQfh0N4EScT1gZXSZyUxpsBirPL99EWZg9MmPG0pzq/gMtgkk7/rAHj4aQw== + dependencies: + "@typescript-eslint/typescript-estree" "1.6.0" + eslint-scope "^4.0.0" + eslint-visitor-keys "^1.0.0" + +"@typescript-eslint/typescript-estree@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz#6cf43a07fee08b8eb52e4513b428c8cdc9751ef0" + integrity sha512-A4CanUwfaG4oXobD5y7EXbsOHjCwn8tj1RDd820etpPAjH+Icjc2K9e/DQM1Hac5zH2BSy+u6bjvvF2wwREvYA== + dependencies: + lodash.unescape "4.0.1" + semver "5.5.0" + +JSONStream@^1.0.4, JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abab@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" + integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +absolute-path@^0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/absolute-path/-/absolute-path-0.0.0.tgz#a78762fbdadfb5297be99b15d35a785b2f095bf7" + +accepts@~1.3.3, accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -1640,6 +2060,7 @@ accepts@~1.3.3, accepts@~1.3.5: acorn-globals@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.0.tgz#e3b6f8da3c1552a95ae627571f7dd6923bb54103" + integrity sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw== dependencies: acorn "^6.0.1" acorn-walk "^6.0.1" @@ -1649,14 +2070,21 @@ acorn-jsx@^5.0.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.0.tgz#958584ddb60990c02c97c1bd9d521fce433bb101" acorn-walk@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.0.tgz#c957f4a1460da46af4a0388ce28b4c99355b0cbc" + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" + integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== acorn@^5.5.3: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + +acorn@^6.0.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" + integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== -acorn@^6.0.1, acorn@^6.0.2: +acorn@^6.0.2: version "6.0.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" @@ -1674,14 +2102,20 @@ agentkeepalive@^3.4.1: dependencies: humanize-ms "^1.2.1" -ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" +ajv-keywords@^3.0.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" + integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== + +ajv@^6.0.1, ajv@^6.5.5: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" + fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" ajv@^6.5.3: version "6.5.5" @@ -1693,20 +2127,33 @@ ajv@^6.5.3: uri-js "^4.2.2" ansi-escapes@^3.0.0: - version "3.1.0" - resolved "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-fragments@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-fragments/-/ansi-fragments-0.2.1.tgz#24409c56c4cc37817c3d7caa99d8969e2de5a05e" + integrity sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w== + dependencies: + colorette "^1.0.7" + slice-ansi "^2.0.0" + strip-ansi "^5.0.0" ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" +ansi-regex@^4.0.0, ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== ansi-styles@^2.2.1: version "2.2.1" @@ -1715,12 +2162,14 @@ ansi-styles@^2.2.1: ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" @@ -1732,11 +2181,11 @@ append-transform@^1.0.0: dependencies: default-require-extensions "^2.0.0" -aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" -"aproba@^1.1.2 || 2", aproba@^2.0.0: +aproba@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== @@ -1751,34 +2200,24 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" -aria-query@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" - integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= - dependencies: - ast-types-flow "0.0.7" - commander "^2.11.0" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-differ@^1.0.0: version "1.0.0" @@ -1788,6 +2227,7 @@ array-differ@^1.0.0: array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= array-filter@~0.0.0: version "0.0.1" @@ -1829,13 +2269,10 @@ array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" @@ -1848,21 +2285,19 @@ asap@^2.0.0, asap@~2.0.3: asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - -ast-types-flow@0.0.7, ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= astral-regex@^1.0.0: version "1.0.0" @@ -1871,41 +2306,46 @@ astral-regex@^1.0.0: async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== async@0.2.x, async@~0.2.9: version "0.2.10" resolved "http://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" -async@^2.4.0, async@^2.5.0, async@^2.6.1: +async@^2.4.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: lodash "^4.17.10" +async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== -axobject-query@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" - integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== - dependencies: - ast-types-flow "0.0.7" - -babel-eslint@^10.0.1: +babel-eslint@10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== @@ -1917,35 +2357,63 @@ babel-eslint@^10.0.1: eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" -babel-jest@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.0.0.tgz#8a0c767f03f4a595fb921afdab13ff126edd00da" - integrity sha512-YGKRbZUjoRmNIAyG7x4wYxUyHvHPFpYXj6Mx1A5cslhaQOUgP/+LF3wtFgMuOQkIpjbVNBufmOnVY0QVwB5v9Q== +babel-jest@^24.6.0, babel-jest@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.7.1.tgz#73902c9ff15a7dfbdc9994b0b17fcefd96042178" + integrity sha512-GPnLqfk8Mtt0i4OemjWkChi73A3ALs4w2/QbG64uAj8b5mmwzxc7jbJVRZt8NJkxi6FopVHog9S3xX6UJKb2qg== dependencies: + "@jest/transform" "^24.7.1" + "@jest/types" "^24.7.0" + "@types/babel__core" "^7.1.0" babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.0.0" + babel-preset-jest "^24.6.0" + chalk "^2.4.2" + slash "^2.0.0" babel-plugin-istanbul@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz#6892f529eff65a3e2d33d87dc5888ffa2ecd4a30" - integrity sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw== + version "5.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz#7981590f1956d75d67630ba46f0c22493588c893" + integrity sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ== dependencies: find-up "^3.0.0" istanbul-lib-instrument "^3.0.0" test-exclude "^5.0.0" -babel-plugin-jest-hoist@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.0.0.tgz#3adf030b6fd67e4311479a54b24077bdfc226ec9" - integrity sha512-ipefE7YWNyRNVaV/MonUb/I5nef53ZRFR74P9meMGmJxqt8s1BJmfhw11YeIMbcjXN4fxtWUaskZZe8yreXE1Q== +babel-plugin-jest-hoist@^24.6.0: + version "24.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz#f7f7f7ad150ee96d7a5e8e2c5da8319579e78019" + integrity sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w== + dependencies: + "@types/babel__traverse" "^7.0.6" + +babel-plugin-module-resolver@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" + integrity sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA== + dependencies: + find-babel-config "^1.1.0" + glob "^7.1.2" + pkg-up "^2.0.0" + reselect "^3.0.1" + resolve "^1.4.0" babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" -babel-preset-fbjs@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.1.0.tgz#6d1438207369d96384d09257b01602dd0dda6608" +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-fbjs@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.2.0.tgz#c0e6347d3e0379ed84b3c2434d3467567aa05297" + integrity sha512-5Jo+JeWiVz2wHUUyAlvb/sSYnXNig9r+HqGAOSfh5Fzxp7SnAaR/tEGRJ1ZX7C77kfk82658w6R5Z+uPATTD9g== dependencies: "@babel/plugin-proposal-class-properties" "^7.0.0" "@babel/plugin-proposal-object-rest-spread" "^7.0.0" @@ -1975,17 +2443,26 @@ babel-preset-fbjs@^3.0.1: "@babel/plugin-transform-template-literals" "^7.0.0" babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" -babel-preset-jest@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.0.0.tgz#d23782e5e036cff517859640a80960bd628bd82b" - integrity sha512-ECMMOLvNDCmsn3geBa3JkwzylcfpThMpAdfreONQm8EmXcs4tXUpXZDQPxiIMg7nMobTuAC2zDGIKrbrBXW2Vg== +babel-preset-jest@^24.6.0: + version "24.6.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984" + integrity sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw== dependencies: "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.0.0" + babel-plugin-jest-hoist "^24.6.0" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base64-js@^1.2.3: version "1.3.0" @@ -1994,6 +2471,7 @@ base64-js@^1.2.3: base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -2012,36 +2490,42 @@ basic-auth@~2.0.0: bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" +before-after-hook@^1.1.0, before-after-hook@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.4.0.tgz#2b6bf23dca4f32e628fd2747c10a37c74a4b484d" + integrity sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg== + +big-integer@^1.6.17: + version "1.6.43" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.43.tgz#8ac15bf13e93e509500859061233e19d8d0d99d1" + integrity sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg== + big-integer@^1.6.7: version "1.6.36" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36" -bin-links@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757" - integrity sha512-8eEHVgYP03nILphilltWjeIjMbKyJo3wvp9K816pHbhP301ismzw15mxAAEVQ/USUwcP++1uNrbERbp8lOA6Fg== - dependencies: - bluebird "^3.5.0" - cmd-shim "^2.0.2" - gentle-fs "^2.0.0" - graceful-fs "^4.1.11" - write-file-atomic "^2.3.0" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= dependencies: - inherits "~2.0.0" + buffers "~0.1.1" + chainsaw "~0.1.0" -bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3: +bluebird@^3.5.1, bluebird@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= + bplist-creator@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.0.7.tgz#37df1536092824b87c42f957b01344117372ae45" @@ -2057,21 +2541,15 @@ bplist-parser@0.1.1: brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -2087,10 +2565,12 @@ braces@^2.3.1: browser-process-hrtime@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4" + integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== browser-resolve@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== dependencies: resolve "1.1.7" @@ -2106,9 +2586,15 @@ browserslist@^4.3.4: bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= dependencies: node-int64 "^0.4.0" +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= + buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -2116,10 +2602,27 @@ buffer-crc32@^0.2.13: buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof-polyfill@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz#a9fb806ce8145d5428510ce72f278bb363a638bf" + integrity sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8= + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + integrity sha1-mXjOMXOIxkmth5MCjDR37wRKi1E= + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtins@^1.0.3: version "1.0.3" @@ -2163,6 +2666,7 @@ cacache@^11.0.1, cacache@^11.3.2: cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -2208,9 +2712,9 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" callsites@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" - integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase-keys@^2.0.0: version "2.1.0" @@ -2234,29 +2738,43 @@ camelcase@^2.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" camelcase@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30000929: version "1.0.30000929" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000929.tgz#7b391b781a9c3097ecc39ea053301aea8ea16317" integrity sha512-n2w1gPQSsYyorSVYqPMqbSaz1w7o9ZC8VhOEGI9T5MfGDzp7sbopQxG6GaQmYsaq13Xfx/mkxJUWC1Dz3oZfzw== -capture-exit@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== dependencies: - rsvp "^3.3.3" + rsvp "^4.8.4" caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= + dependencies: + traverse ">=0.3.0 <0.4" chalk@^1.1.1: version "1.1.3" @@ -2268,18 +2786,18 @@ chalk@^1.1.1: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^2.3.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +chalk@^2.1.0, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -2293,6 +2811,11 @@ chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -2314,6 +2837,7 @@ circular-json@^0.3.1: class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -2326,6 +2850,11 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-spinners@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.0.0.tgz#4b078756fc17a8f72043fdc9f1f14bf4fa87e2df" + integrity sha512-yiEBmhaKPPeBj7wWm4GEdtPZK940p9pl3EANIrnJ3JnvWyrPjcFcsEq6qRUuQ7fzB0+Y82ld3p6B34xo95foWw== + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -2341,6 +2870,7 @@ cliui@^3.2.0: cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" @@ -2362,14 +2892,17 @@ cmd-shim@^2.0.2: co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -2377,17 +2910,29 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +colorette@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.0.7.tgz#7adf43c445ee63a541b4a4aef7d13f03df1e0cc0" + integrity sha512-KeK4klsvAgdODAjFPm6QLzvStizJqlxMBtVo4KQMCgk5tt/tf9rAzxmxLHNRynJg3tJjkKGKbHx3j4HLox27Lw== colors@0.6.x: version "0.6.2" resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" +colors@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== + columnify@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" @@ -2399,20 +2944,24 @@ columnify@^1.5.4: combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" -commander@^2.11.0, commander@^2.9.0: +commander@^2.19.0, commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== -commander@~2.17.1: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= compare-func@^1.3.1: version "1.3.2" @@ -2430,6 +2979,7 @@ compare-versions@^3.2.1: component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= compressible@~2.0.14: version "2.0.15" @@ -2452,6 +3002,7 @@ compression@^1.7.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" @@ -2488,20 +3039,20 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= -conventional-changelog-angular@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.2.tgz#39d945635e03b6d0c9d4078b1df74e06163dc66a" - integrity sha512-yx7m7lVrXmt4nKWQgWZqxSALEiAKZhOAcbxdUaU9575mB0CzXVbgrgpfSnSP7OqWDUTYGD0YVJ0MSRdyOPgAwA== +conventional-changelog-angular@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz#299fdd43df5a1f095283ac16aeedfb0a682ecab0" + integrity sha512-YD1xzH7r9yXQte/HF9JBuEDfvjxxwDGGwZU1+ndanbY0oFgA+Po1T9JDSpPLdP0pZT6MhCAsdvFKC4TJ4MTJTA== dependencies: compare-func "^1.3.1" q "^1.5.1" -conventional-changelog-core@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.1.5.tgz#c2edf928539308b54fe1b90a2fc731abc021852c" - integrity sha512-iwqAotS4zk0wA4S84YY1JCUG7X3LxaRjJxuUo6GI4dZuIy243j5nOg/Ora35ExT4DOiw5dQbMMQvw2SUjh6moQ== +conventional-changelog-core@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.1.6.tgz#ac1731a461c50d150d29c1ad4f33143293bcd32f" + integrity sha512-5teTAZOtJ4HLR6384h50nPAaKdDr+IaU0rnD2Gg2C3MS7hKsEPH8pZxrDNqam9eOSPQg9tET6uZY79zzgSz+ig== dependencies: - conventional-changelog-writer "^4.0.2" + conventional-changelog-writer "^4.0.3" conventional-commits-parser "^3.0.1" dateformat "^3.0.0" get-pkg-repo "^1.0.0" @@ -2520,15 +3071,15 @@ conventional-changelog-preset-loader@^2.0.2: resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.0.2.tgz#81d1a07523913f3d17da3a49f0091f967ad345b0" integrity sha512-pBY+qnUoJPXAXXqVGwQaVmcye05xi6z231QM98wHWamGAmu/ghkBprQAwmF5bdmyobdVxiLhPY3PrCfSeUNzRQ== -conventional-changelog-writer@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.2.tgz#eb493ed84269e7a663da36e49af51c54639c9a67" - integrity sha512-d8/FQY/fix2xXEBUhOo8u3DCbyEw3UOQgYHxLsPDw+wHUDma/GQGAGsGtoH876WyNs32fViHmTOUrgRKVLvBug== +conventional-changelog-writer@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.3.tgz#916a2b302d0bb5ef18efd236a034c13fb273cde1" + integrity sha512-bIlpSiQtQZ1+nDVHEEh798Erj2jhN/wEjyw9sfxY9es6h7pREE5BNJjfv0hXGH/FTrAsEpHUq4xzK99eePpwuA== dependencies: compare-func "^1.3.1" conventional-commits-filter "^2.0.1" dateformat "^3.0.0" - handlebars "^4.0.2" + handlebars "^4.1.0" json-stringify-safe "^5.0.1" lodash "^4.2.1" meow "^4.0.0" @@ -2574,6 +3125,7 @@ conventional-recommended-bump@^4.0.4: convert-source-map@^1.1.0, convert-source-map@^1.4.0: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== dependencies: safe-buffer "~5.1.1" @@ -2592,6 +3144,12 @@ copy-concurrently@^1.0.0: copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js@^2.2.2, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== core-js@^2.4.1: version "2.5.7" @@ -2600,23 +3158,24 @@ core-js@^2.4.1: core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cosmiconfig@^5.0.2: - version "5.0.7" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.7.tgz#39826b292ee0d78eda137dfa3173bd1c21a43b04" - integrity sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA== +cosmiconfig@^5.0.5: + version "5.0.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39" dependencies: - import-fresh "^2.0.0" is-directory "^0.3.1" js-yaml "^3.9.0" parse-json "^4.0.0" -cosmiconfig@^5.0.5: - version "5.0.6" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39" +cosmiconfig@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.0.tgz#45038e4d28a7fe787203aede9c25bca4a08b12c8" + integrity sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g== dependencies: + import-fresh "^2.0.0" is-directory "^0.3.1" - js-yaml "^3.9.0" + js-yaml "^3.13.0" parse-json "^4.0.0" cross-spawn@^5.0.1: @@ -2637,13 +3196,20 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" + version "0.3.6" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.6.tgz#f85206cee04efa841f3c5982a74ba96ab20d65ad" + integrity sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A== cssstyle@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.1.1.tgz#18b038a9c44d65f7a8e428a653b9f6fe42faf5fb" + version "1.2.2" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.2.2.tgz#427ea4d585b18624f6fdbf9de7a2a1a3ba713077" + integrity sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow== dependencies: cssom "0.3.x" @@ -2663,11 +3229,6 @@ cyclist@~0.2.2: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= -damerau-levenshtein@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" - integrity sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ= - dargs@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" @@ -2678,12 +3239,14 @@ dargs@^4.0.1: dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" data-urls@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== dependencies: abab "^2.0.0" whatwg-mimetype "^2.2.0" @@ -2710,6 +3273,7 @@ debug@3.1.0: debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: ms "^2.1.1" @@ -2719,7 +3283,7 @@ debug@^4.0.1: dependencies: ms "^2.1.1" -debug@^4.1.0: +debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -2743,15 +3307,17 @@ decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -decamelize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" - dependencies: - xregexp "4.0.0" - decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" dedent@^0.7.0: version "0.7.0" @@ -2769,6 +3335,17 @@ deep-extend@^0.6.0: deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +deepmerge@3.2.0, deepmerge@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e" + integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow== + +deepmerge@^2.0.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== default-require-extensions@^2.0.0: version "2.0.0" @@ -2787,24 +3364,28 @@ defaults@^1.0.3: define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== dependencies: object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" @@ -2824,6 +3405,7 @@ del@^2.0.2: delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" @@ -2837,6 +3419,11 @@ depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" +deprecation@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-1.0.1.tgz#2df79b79005752180816b7b6e079cbd80490d711" + integrity sha512-ccVHpE72+tcIKaGMql33x5MAjKQIZrk+3x2GbJ7TeraUCZWHoT+KSZpoC+JQFsUBlSTXUrBaGiF0j6zVTepPLg== + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2853,6 +3440,7 @@ detect-libc@^1.0.2: detect-newline@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= dezalgo@^1.0.0: version "1.0.3" @@ -2862,10 +3450,10 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diff-sequences@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.0.0.tgz#cdf8e27ed20d8b8d3caccb4e0c0d8fe31a173013" - integrity sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw== +diff-sequences@^24.3.0: + version "24.3.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975" + integrity sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw== dir-glob@2.0.0: version "2.0.0" @@ -2886,6 +3474,7 @@ doctrine@1.5.0: doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" @@ -2896,6 +3485,7 @@ dom-walk@^0.1.0: domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== dependencies: webidl-conversions "^4.0.2" @@ -2913,6 +3503,18 @@ dot-prop@^4.2.0: dependencies: is-obj "^1.0.0" +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + duplexer@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" @@ -2931,6 +3533,7 @@ duplexify@^3.4.2, duplexify@^3.6.0: ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -2944,11 +3547,6 @@ electron-to-chromium@^1.3.103: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.103.tgz#a695777efdbc419cad6cbb0e58458251302cd52f" integrity sha512-tObPqGmY9X8MUM8i3MEimYmbnLLf05/QV5gPlkR8MQ3Uj8G8B2govE1U4cQcBYtv3ymck9Y8cIOu4waoiykMZQ== -emoji-regex@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" - integrity sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ== - encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2965,9 +3563,10 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -envinfo@^5.7.0: - version "5.11.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-5.11.1.tgz#a1c2cb55196931b2ac6d4110fa7f0003697ad9df" +envinfo@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.1.0.tgz#c64f80bbf5faaafc962eef76c0d871c6c672eec0" + integrity sha512-38LJhrmyQafVInoYlaEDxomIfjtK+HUtp1JsInWdKtpxk0MlTU60fqYHg0LrKgxxJuq6H89ddw4IkxfQejZ77g== err-code@^1.0.0: version "1.1.2" @@ -2987,7 +3586,19 @@ errorhandler@^1.5.0: accepts "~1.3.3" escape-html "~1.0.3" -es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0: +es-abstract@^1.11.0, es-abstract@^1.5.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-abstract@^1.7.0: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: @@ -2997,7 +3608,7 @@ es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0: is-callable "^1.1.3" is-regex "^1.0.4" -es-to-primitive@^1.1.1: +es-to-primitive@^1.1.1, es-to-primitive@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" dependencies: @@ -3026,8 +3637,9 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" escodegen@^1.9.1: - version "1.11.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" + version "1.11.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.1.tgz#c485ff8d6b4cdb89e27f4a856e91f118401ca510" + integrity sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw== dependencies: esprima "^3.1.3" estraverse "^4.2.0" @@ -3036,32 +3648,12 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" -eslint-config-airbnb-base@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" - integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== - dependencies: - eslint-restricted-globals "^0.1.1" - object.assign "^4.1.0" - object.entries "^1.0.4" - -eslint-config-airbnb@^17.1.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" - integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== - dependencies: - eslint-config-airbnb-base "^13.1.0" - object.assign "^4.1.0" - object.entries "^1.0.4" - -eslint-config-prettier@^3.0.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.3.0.tgz#41afc8d3b852e757f06274ed6c44ca16f939a57d" - integrity sha512-Bc3bh5bAcKNvs3HOpSi6EfGA2IIp7EzWcg2tS4vP7stnXu/J1opihHDM7jI9JCIckyIDTgZLSWn7J3HY0j2JfA== - dependencies: - get-stdin "^6.0.0" +eslint-import-resolver-alias@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97" + integrity sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w== -eslint-import-resolver-node@^0.3.1: +eslint-import-resolver-node@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== @@ -3069,85 +3661,97 @@ eslint-import-resolver-node@^0.3.1: debug "^2.6.9" resolve "^1.5.0" -eslint-module-utils@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746" - integrity sha1-snA2LNiLGkitMIl2zn+lTphBF0Y= +eslint-import-resolver-typescript@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-1.1.1.tgz#e6d42172b95144ef16610fe104ef38340edea591" + integrity sha512-jqSfumQ+H5y3FUJ6NjRkbOQSUOlbBucGTN3ELymOtcDBbPjVdm/luvJuCfCaIXGh8sEF26ma1qVdtDgl9ndhUg== + dependencies: + debug "^4.0.1" + resolve "^1.4.0" + tsconfig-paths "^3.6.0" + +eslint-module-utils@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49" + integrity sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w== dependencies: debug "^2.6.8" - pkg-dir "^1.0.0" + pkg-dir "^2.0.0" -eslint-plugin-flowtype@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-3.2.0.tgz#824364ed5940a404b91326fdb5a313a2a74760df" - integrity sha512-baJmzngM6UKbEkJ5OY3aGw2zjXBt5L2QKZvTsOlXX7yHKIjNRrlJx2ods8Rng6EdqPR9rVNIQNYHpTs0qfn2qA== +eslint-plugin-eslint-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.1.1.tgz#32ff0afba8a48e17073817e6d03fbc5622f735b7" + integrity sha512-GZDKhOFqJLKlaABX+kdoLskcTINMrVOWxGca54KcFb1QCPd0CLmqgAMRxkkUfGSmN+5NJUMGh7NGccIMcWPSfQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + +eslint-plugin-flowtype@2.50.3: + version "2.50.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.3.tgz#61379d6dce1d010370acd6681740fd913d68175f" + integrity sha512-X+AoKVOr7Re0ko/yEXyM5SSZ0tazc6ffdIOocp2fFUlWoDt7DV0Bz99mngOkAFLOAWjqRA5jPwqUCbrx13XoxQ== dependencies: lodash "^4.17.10" -eslint-plugin-import@^2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz#6b17626d2e3e6ad52cfce8807a845d15e22111a8" - integrity sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g== +eslint-plugin-import@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.0.tgz#bdf6598aded839a27454d824b0758fd46f80eb72" + integrity sha512-JCsOtNwPYUoeZPlSr8t0+uCU5OVlHh+dIBn8Rw7FiOPjCECG+QzDIKDqshbyJE6CYoj9wpcstEl8vUY7rXkqVA== dependencies: + array-includes "^3.0.3" contains-path "^0.1.0" - debug "^2.6.8" + debug "^2.6.9" doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.2.0" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.3.0" + has "^1.0.3" + lodash "^4.17.11" + minimatch "^3.0.4" read-pkg-up "^2.0.0" - resolve "^1.6.0" + resolve "^1.10.0" -eslint-plugin-jest@^21.21.0: - version "21.27.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.27.2.tgz#2a795b7c3b5e707df48a953d651042bd01d7b0a8" - integrity sha512-0E4OIgBJVlAmf1KfYFtZ3gYxgUzC5Eb3Jzmrc9ikI1OY+/cM8Kh72Ti7KfpeHNeD3HJNf9SmEfmvQLIz44Hrhw== +eslint-plugin-jest@22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.4.1.tgz#a5fd6f7a2a41388d16f527073b778013c5189a9c" + integrity sha512-gcLfn6P2PrFAVx3AobaOzlIEevpAEf9chTpFZz7bYfc7pz8XRv7vuKTIE4hxPKZSha6XWKKplDQ0x9Pq8xX2mg== -eslint-plugin-jsx-a11y@^6.1.1: - version "6.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz#69bca4890b36dcf0fe16dd2129d2d88b98f33f88" - integrity sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw== +eslint-plugin-prettier@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz#71998c60aedfa2141f7bfcbf9d1c459bf98b4fad" + integrity sha512-tGek5clmW5swrAx1mdPYM8oThrBE83ePh7LeseZHBWfHVGrHPhKn7Y5zgRMbU/9D5Td9K4CEmUPjGxA7iw98Og== dependencies: - aria-query "^3.0.0" - array-includes "^3.0.3" - ast-types-flow "^0.0.7" - axobject-query "^2.0.1" - damerau-levenshtein "^1.0.4" - emoji-regex "^6.5.1" - has "^1.0.3" - jsx-ast-utils "^2.0.1" + fast-diff "^1.1.1" + jest-docblock "^21.0.0" -eslint-plugin-prettier@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz#f6b823e065f8c36529918cdb766d7a0e975ec30c" - integrity sha512-4g11opzhqq/8+AMmo5Vc2Gn7z9alZ4JqrbZ+D4i8KlSyxeQhZHlmIrY8U9Akf514MoEhogPa87Jgkq87aZ2Ohw== - dependencies: - prettier-linter-helpers "^1.0.0" +eslint-plugin-react-hooks@^1.5.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.0.tgz#348efcda8fb426399ac7b8609607c7b4025a6f5f" + integrity sha512-lHBVRIaz5ibnIgNG07JNiAuBUeKhEf8l4etNx5vfAEwqQ5tcuK3jV9yjmopPgQDagQb7HwIuQVsE3IVcGrRnag== -eslint-plugin-prettier@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz#19d521e3981f69dd6d14f64aec8c6a6ac6eb0b0d" - integrity sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ== +eslint-plugin-react-native-globals@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" + integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g== + +eslint-plugin-react-native@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.6.0.tgz#7cad3b7c6159df6d26fe3252c6c5417a17f27b4b" + integrity sha512-BEQcHZ06hZSBYWFVuNEq0xuui5VEsWpHDsZGBtfadHfCRqRMUrkYPgdDb3bpc60qShHE83kqIv59uKdinEg91Q== dependencies: - prettier-linter-helpers "^1.0.0" + eslint-plugin-react-native-globals "^0.1.1" -eslint-plugin-react@^7.5.1: - version "7.11.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz#c01a7af6f17519457d6116aa94fc6d2ccad5443c" - integrity sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw== +eslint-plugin-react@7.12.4: + version "7.12.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz#b1ecf26479d61aee650da612e425c53a99f48c8c" + integrity sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ== dependencies: array-includes "^3.0.3" doctrine "^2.1.0" has "^1.0.3" jsx-ast-utils "^2.0.1" + object.fromentries "^2.0.0" prop-types "^15.6.2" - -eslint-restricted-globals@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" - integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc= + resolve "^1.9.0" eslint-scope@3.7.1: version "3.7.1" @@ -3227,10 +3831,12 @@ espree@^5.0.0: esprima@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.0.1: version "1.0.1" @@ -3260,15 +3866,20 @@ eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - dependencies: - merge "^1.2.0" +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +exec-sh@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" + integrity sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg== execa@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -3306,16 +3917,12 @@ execa@^1.0.0: exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3325,32 +3932,29 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -expect@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.0.0.tgz#71f71d88a4202746fc79849bb4c6498008b5ef03" - integrity sha512-qDHRU4lGsme0xjg8dXp/RQhvO9XIo9FWqVo7dTHDPBwzy25JGEHAWFsnpmRYErB50tgi/6euo3ir5e/kF9LUTA== +expect@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.7.1.tgz#d91defbab4e627470a152feaf35b3c31aa1c7c14" + integrity sha512-mGfvMTPduksV3xoI0xur56pQsg2vJjNf5+a+bXOjqCkiCBbmCayrBbHS/75y9K430cfqyocPr2ZjiNiRx4SRKw== dependencies: + "@jest/types" "^24.7.0" ansi-styles "^3.2.0" - jest-get-type "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" + jest-get-type "^24.3.0" + jest-matcher-utils "^24.7.0" + jest-message-util "^24.7.1" + jest-regex-util "^24.3.0" extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -3358,6 +3962,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^2.0.4: version "2.2.0" @@ -3375,15 +3980,10 @@ external-editor@^3.0.0: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -3397,24 +3997,22 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= eyes@0.1.x: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" -fast-diff@^1.1.2: +fast-diff@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== @@ -3434,14 +4032,17 @@ fast-glob@^2.0.2: fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= dependencies: bser "^2.0.0" @@ -3480,30 +4081,18 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - fileset@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= dependencies: glob "^7.0.3" minimatch "^3.0.3" -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -3522,10 +4111,22 @@ finalhandler@1.1.0: statuses "~1.3.1" unpipe "~1.0.0" -find-npm-prefix@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" - integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA== +find-babel-config@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" + integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" find-up@^1.0.0: version "1.1.2" @@ -3543,6 +4144,7 @@ find-up@^2.0.0, find-up@^2.1.0: find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" @@ -3555,10 +4157,31 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flow-bin@^0.94.0: - version "0.94.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.94.0.tgz#b5d58fe7559705b73a18229f97edfc3ab6ffffcb" - integrity sha512-DYF7r9CJ/AksfmmB4+q+TyLMoeQPRnqtF1Pk7KY3zgfkB/nVuA3nXyzqgsIPIvnMSiFEXQcFK4z+iPxSLckZhQ== +flow-bin@^0.101.0: + version "0.101.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.101.0.tgz#c56fa0afb9c151eeba7954136e9066d408691063" + integrity sha512-2xriPEOSrGQklAArNw1ixoIUiLTWhIquYV26WqnxEu7IcXWgoZUcfJXufG9kIvrNbdwCNd5RBjTwbB0p6L6XaA== + +flow-typed@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.5.1.tgz#0ff565cc94d2af8c557744ba364b6f14726a6b9f" + integrity sha1-D/VlzJTSr4xVd0S6NktvFHJqa58= + dependencies: + "@octokit/rest" "^15.2.6" + babel-polyfill "^6.26.0" + colors "^1.1.2" + fs-extra "^5.0.0" + glob "^7.1.2" + got "^7.1.0" + md5 "^2.1.0" + mkdirp "^0.5.1" + rimraf "^2.6.2" + semver "^5.5.0" + table "^4.0.2" + through "^2.3.8" + unzipper "^0.8.11" + which "^1.3.0" + yargs "^4.2.0" flush-write-stream@^1.0.0: version "1.0.3" @@ -3568,23 +4191,20 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" @@ -3593,6 +4213,7 @@ form-data@~2.3.2: fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" @@ -3616,7 +4237,16 @@ fs-extra@^1.0.0: jsonfile "^2.1.0" klaw "^1.0.0" -fs-extra@^7.0.0: +fs-extra@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -3631,15 +4261,6 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.2.1" -fs-vacuum@^1.2.10: - version "1.2.10" - resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" - integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= - dependencies: - graceful-fs "^4.1.2" - path-is-inside "^1.0.1" - rimraf "^2.5.2" - fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -3653,15 +4274,17 @@ fs-write-stream-atomic@^1.0.8: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" +fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" -fstream@^1.0.0, fstream@^1.0.2: +fstream@~1.0.10: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= @@ -3671,9 +4294,10 @@ fstream@^1.0.0, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.1.0, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: version "1.0.1" @@ -3697,23 +4321,10 @@ genfun@^5.0.0: resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== -gentle-fs@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.0.1.tgz#585cfd612bfc5cd52471fdb42537f016a5ce3687" - integrity sha512-cEng5+3fuARewXktTEGbwsktcldA+YsnUEaXZwcK/3pjSE1X9ObnTs+/8rYf8s+RnIcQm2D5x3rwpN7Zom8Bew== - dependencies: - aproba "^1.1.2" - fs-vacuum "^1.2.10" - graceful-fs "^4.1.11" - iferr "^0.1.5" - mkdirp "^0.5.1" - path-is-inside "^1.0.2" - read-cmd-shim "^1.0.1" - slide "^1.1.6" - get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-pkg-repo@^1.0.0: version "1.4.0" @@ -3736,14 +4347,10 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - get-stream@^3.0.0: version "3.0.0" - resolved "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" @@ -3754,10 +4361,12 @@ get-stream@^4.0.0, get-stream@^4.1.0: get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" @@ -3788,6 +4397,21 @@ git-semver-tags@^2.0.2: meow "^4.0.0" semver "^5.5.0" +git-up@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/git-up/-/git-up-4.0.1.tgz#cb2ef086653640e721d2042fe3104857d89007c0" + integrity sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw== + dependencies: + is-ssh "^1.3.0" + parse-url "^5.0.0" + +git-url-parse@^11.1.2: + version "11.1.2" + resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.1.2.tgz#aff1a897c36cc93699270587bea3dbcbbb95de67" + integrity sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ== + dependencies: + git-up "^4.0.0" + gitconfiglocal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" @@ -3795,19 +4419,6 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -3839,7 +4450,12 @@ global@^4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^11.1.0, globals@^11.7.0: +globals@^11.1.0: + version "11.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" + integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== + +globals@^11.7.0: version "11.8.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.8.0.tgz#c1ef45ee9bed6badf0663c5cb90e8d1adec1321d" @@ -3867,6 +4483,26 @@ globby@^8.0.1: pify "^3.0.0" slash "^1.0.0" +got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -3874,12 +4510,14 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3 growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -handlebars@^4.0.11, handlebars@^4.0.2: - version "4.0.12" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" +handlebars@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.1.tgz#6e4e41c18ebe7719ae4d38e5aca3d32fa3dd23d3" + integrity sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA== dependencies: - async "^2.5.0" + neo-async "^2.6.0" optimist "^0.6.1" source-map "^0.6.1" optionalDependencies: @@ -3888,12 +4526,14 @@ handlebars@^4.0.11, handlebars@^4.0.2: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== dependencies: - ajv "^5.3.0" + ajv "^6.5.5" har-schema "^2.0.0" has-ansi@^2.0.0: @@ -3905,10 +4545,24 @@ has-ansi@^2.0.0: has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" @@ -3917,6 +4571,7 @@ has-unicode@^2.0.0, has-unicode@^2.0.1: has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -3925,6 +4580,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -3933,10 +4589,12 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -3947,6 +4605,11 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" +home-or-tmp@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-3.0.0.tgz#57a8fe24cf33cdd524860a15821ddc25c86671fb" + integrity sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs= + hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -3954,6 +4617,7 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: html-encoding-sniffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== dependencies: whatwg-encoding "^1.0.1" @@ -3982,12 +4646,13 @@ http-proxy-agent@^2.1.0: http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^2.2.1: +https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== @@ -4032,6 +4697,11 @@ ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" +ignore@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.5.tgz#c663c548d6ce186fb33616a8ccb5d46e56bdbbf9" + integrity sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA== + image-size@^0.6.0: version "0.6.3" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2" @@ -4055,6 +4725,7 @@ import-local@^1.0.0: import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== dependencies: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" @@ -4062,6 +4733,7 @@ import-local@^2.0.0: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= indent-string@^2.1.0: version "2.1.0" @@ -4078,15 +4750,16 @@ indent-string@^3.0.0: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -4173,6 +4846,7 @@ invert-kv@^1.0.0: invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== ip@^1.1.5: version "1.1.5" @@ -4182,32 +4856,37 @@ ip@^1.1.5: is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-buffer@^1.1.5: +is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" - resolved "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-callable@^1.1.3, is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== is-ci@^1.0.10: version "1.2.1" @@ -4226,22 +4905,26 @@ is-ci@^2.0.0: is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -4250,6 +4933,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -4259,30 +4943,18 @@ is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -4298,23 +4970,19 @@ is-finite@^1.0.0: is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-generator-fn@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.0.0.tgz#038c31b774709641bda678b1f06a4e3227c10b3e" - integrity sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g== - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-glob@^3.1.0: version "3.1.0" @@ -4330,27 +4998,23 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -4375,17 +5039,10 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -4393,10 +5050,23 @@ is-promise@^2.1.0: is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" -is-stream@^1.0.1, is-stream@^1.1.0: +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= + +is-ssh@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.1.tgz#f349a8cadd24e65298037a522cf7520f2e81a0f3" + integrity sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg== + dependencies: + protocols "^1.1.0" + +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4408,6 +5078,7 @@ is-subset@^0.1.1: is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== dependencies: has-symbols "^1.0.0" @@ -4421,6 +5092,7 @@ is-text-path@^1.0.0: is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-utf8@^0.2.0: version "0.2.1" @@ -4430,24 +5102,34 @@ is-utf8@^0.2.0: is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isomorphic-fetch@^2.1.1: version "2.2.1" @@ -4460,446 +5142,441 @@ isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -istanbul-api@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.0.8.tgz#5621503c5595e5adbbacd5ce257090417c7f55da" - integrity sha512-ITCccemErW+BhZotmyQ/ktlYTAp9r7oWfz1oxxMpgKQVTUw0NAYRbKLbOSNaInipecIKul7U7O5BfCQBBRZa3w== +istanbul-api@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.1.tgz#194b773f6d9cbc99a9258446848b0f988951c4d0" + integrity sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw== dependencies: async "^2.6.1" compare-versions "^3.2.1" fileset "^2.0.3" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-hook "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.3" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.0.3" + istanbul-lib-coverage "^2.0.3" + istanbul-lib-hook "^2.0.3" + istanbul-lib-instrument "^3.1.0" + istanbul-lib-report "^2.0.4" + istanbul-lib-source-maps "^3.0.2" + istanbul-reports "^2.1.1" js-yaml "^3.12.0" make-dir "^1.3.0" + minimatch "^3.0.4" once "^1.4.0" -istanbul-lib-coverage@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#2aee0e073ad8c5f6a0b00e0dfbf52b4667472eda" - integrity sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA== - -istanbul-lib-coverage@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#d5db9a7a4bb8fdbd62ec746226385987b73a8f43" - integrity sha512-4CsY730KHy12ya/YNKubrMlb7EZZVsEPhXntyRY/Cbs7HN5HdznLbI4UbvIGHgocxHx3VkGe7l6IN1lipetuGg== +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba" + integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw== -istanbul-lib-hook@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.2.tgz#9ddd28aeac10f3bb6a4d02325e72b35044d17d3a" - integrity sha512-m0MwviQ0Av6qBNDkvKdLBxxuK6ffXo8761gE2bfT+/b+dhg8LUyQhp1nFh795LO12DpiSocuCPIRwILCsN1//Q== +istanbul-lib-hook@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz#e0e581e461c611be5d0e5ef31c5f0109759916fb" + integrity sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA== dependencies: append-transform "^1.0.0" -istanbul-lib-instrument@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz#b5f066b2a161f75788be17a9d556f40a0cf2afc9" - integrity sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ== - dependencies: - "@babel/generator" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - istanbul-lib-coverage "^2.0.1" - semver "^5.5.0" - -istanbul-lib-instrument@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.1.tgz#dd631e117dd9891e8bf1de7bb400cb8e491363af" - integrity sha512-/LTPhh1YKXjJlb5uggsiZjJHuViIljcIsB1zqmZegIw2yQ4l8LRksRGebJrZUFVEE28ZtKzmmT50W5tpAucfJg== +istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz#a2b5484a7d445f1f311e93190813fa56dfb62971" + integrity sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA== dependencies: "@babel/generator" "^7.0.0" "@babel/parser" "^7.0.0" "@babel/template" "^7.0.0" "@babel/traverse" "^7.0.0" "@babel/types" "^7.0.0" - istanbul-lib-coverage "^2.0.2" + istanbul-lib-coverage "^2.0.3" semver "^5.5.0" -istanbul-lib-report@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.3.tgz#8e22534766e9cc8e20ae96283331b4405da9dce9" - integrity sha512-25gX27Mbd3MjM41hwGl5lWcQEqaPaMP79YDFS20xuTUujItNmHgTBS3WRZvzyzLE0IAKaL+JpLrryou2WlZNMw== +istanbul-lib-report@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4" + integrity sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA== dependencies: - istanbul-lib-coverage "^2.0.2" + istanbul-lib-coverage "^2.0.3" make-dir "^1.3.0" - supports-color "^5.4.0" + supports-color "^6.0.0" -istanbul-lib-source-maps@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.1.tgz#002936e1106c4fa49714a946e6c63c1098b52e11" - integrity sha512-DBsZMpCwCPewRCmyd0FETHtzarQK/kKejQkDPBqKPwLYQmhs2p6a7yytfVDqib7PgXGSJZNTc1b6B3jl9G8FqA== +istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz#f1e817229a9146e8424a28e5d69ba220fda34156" + integrity sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ== dependencies: - debug "^3.1.0" - istanbul-lib-coverage "^2.0.2" + debug "^4.1.1" + istanbul-lib-coverage "^2.0.3" make-dir "^1.3.0" rimraf "^2.6.2" source-map "^0.6.1" -istanbul-reports@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.0.3.tgz#332eda684c9ee891f199dfba305c3e776f55fc16" - integrity sha512-qpQ5ZWBkOatTxmTelS+HV5ybPSq7EeXmwXrPbGv7ebP+9DJOtveUcv6hCncZE4IxSAEkdmLEh3xo31SCttbApQ== +istanbul-reports@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.1.1.tgz#72ef16b4ecb9a4a7bd0e2001e00f95d1eec8afa9" + integrity sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw== + dependencies: + handlebars "^4.1.0" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== dependencies: - handlebars "^4.0.11" + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" -jest-changed-files@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.0.0.tgz#c02c09a8cc9ca93f513166bc773741bd39898ff7" - integrity sha512-nnuU510R9U+UX0WNb5XFEcsrMqriSiRLeO9KWDFgPrpToaQm60prfQYpxsXigdClpvNot5bekDY440x9dNGnsQ== +jest-changed-files@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.7.0.tgz#39d723a11b16ed7b373ac83adc76a69464b0c4fa" + integrity sha512-33BgewurnwSfJrW7T5/ZAXGE44o7swLslwh8aUckzq2e17/2Os1V0QU506ZNik3hjs8MgnEMKNkcud442NCDTw== dependencies: + "@jest/types" "^24.7.0" execa "^1.0.0" throat "^4.0.0" -jest-cli@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.0.0.tgz#691fd4f7bce2574c1865db6844a43b56e60ce2a4" - integrity sha512-mElnFipLaGxo1SiQ1CLvuaz3eX07MJc4HcyKrApSJf8xSdY1/EwaHurKwu1g2cDiwIgY8uHj7UcF5OYbtiBOWg== +jest-cli@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.7.1.tgz#6093a539073b6f4953145abeeb9709cd621044f1" + integrity sha512-32OBoSCVPzcTslGFl6yVCMzB2SqX3IrWwZCY5mZYkb0D2WsogmU3eV2o8z7+gRQa4o4sZPX/k7GU+II7CxM6WQ== dependencies: - ansi-escapes "^3.0.0" + "@jest/core" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" chalk "^2.0.1" exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.1.15" import-local "^2.0.0" is-ci "^2.0.0" - istanbul-api "^2.0.8" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-source-maps "^3.0.1" - jest-changed-files "^24.0.0" - jest-config "^24.0.0" - jest-environment-jsdom "^24.0.0" - jest-get-type "^24.0.0" - jest-haste-map "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" - jest-resolve-dependencies "^24.0.0" - jest-runner "^24.0.0" - jest-runtime "^24.0.0" - jest-snapshot "^24.0.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" - jest-watcher "^24.0.0" - jest-worker "^24.0.0" - micromatch "^3.1.10" - node-notifier "^5.2.1" - p-each-series "^1.0.0" - pirates "^4.0.0" + jest-config "^24.7.1" + jest-util "^24.7.1" + jest-validate "^24.7.0" prompts "^2.0.1" - realpath-native "^1.0.0" - rimraf "^2.5.4" - slash "^2.0.0" - string-length "^2.0.0" - strip-ansi "^5.0.0" - which "^1.2.12" + realpath-native "^1.1.0" yargs "^12.0.2" -jest-config@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.0.0.tgz#878abe03c060c74a0ec30d3cd5dd1897873e030e" - integrity sha512-9/soqWL5YSq1ZJtgVJ5YYPCL1f9Mi2lVCp5+OXuYBOaN8DHSFRCSWip0rQ6N+mPTOEIAlCvcUH8zaPOwK4hePg== +jest-config@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.7.1.tgz#6c1dd4db82a89710a3cf66bdba97827c9a1cf052" + integrity sha512-8FlJNLI+X+MU37j7j8RE4DnJkvAghXmBWdArVzypW6WxfGuxiL/CCkzBg0gHtXhD2rxla3IMOSUAHylSKYJ83g== dependencies: "@babel/core" "^7.1.0" - babel-jest "^24.0.0" + "@jest/test-sequencer" "^24.7.1" + "@jest/types" "^24.7.0" + babel-jest "^24.7.1" chalk "^2.0.1" glob "^7.1.1" - jest-environment-jsdom "^24.0.0" - jest-environment-node "^24.0.0" - jest-get-type "^24.0.0" - jest-jasmine2 "^24.0.0" - jest-regex-util "^24.0.0" - jest-resolve "^24.0.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" + jest-environment-jsdom "^24.7.1" + jest-environment-node "^24.7.1" + jest-get-type "^24.3.0" + jest-jasmine2 "^24.7.1" + jest-regex-util "^24.3.0" + jest-resolve "^24.7.1" + jest-util "^24.7.1" + jest-validate "^24.7.0" micromatch "^3.1.10" - pretty-format "^24.0.0" - realpath-native "^1.0.2" - uuid "^3.3.2" + pretty-format "^24.7.0" + realpath-native "^1.1.0" -jest-diff@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.0.0.tgz#a3e5f573dbac482f7d9513ac9cfa21644d3d6b34" - integrity sha512-XY5wMpRaTsuMoU+1/B2zQSKQ9RdE9gsLkGydx3nvApeyPijLA8GtEvIcPwISRCer+VDf9W1mStTYYq6fPt8ryA== +jest-diff@^24.0.0, jest-diff@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.7.0.tgz#5d862899be46249754806f66e5729c07fcb3580f" + integrity sha512-ULQZ5B1lWpH70O4xsANC4tf4Ko6RrpwhE3PtG6ERjMg1TiYTC2Wp4IntJVGro6a8HG9luYHhhmF4grF0Pltckg== dependencies: chalk "^2.0.1" - diff-sequences "^24.0.0" - jest-get-type "^24.0.0" - pretty-format "^24.0.0" + diff-sequences "^24.3.0" + jest-get-type "^24.3.0" + pretty-format "^24.7.0" + +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + integrity sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw== -jest-docblock@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.0.0.tgz#54d77a188743e37f62181a91a01eb9222289f94e" - integrity sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA== +jest-docblock@^24.3.0: + version "24.3.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.3.0.tgz#b9c32dac70f72e4464520d2ba4aec02ab14db5dd" + integrity sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg== dependencies: detect-newline "^2.1.0" -jest-each@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.0.0.tgz#10987a06b21c7ffbfb7706c89d24c52ed864be55" - integrity sha512-gFcbY4Cu55yxExXMkjrnLXov3bWO3dbPAW7HXb31h/DNWdNc/6X8MtxGff8nh3/MjkF9DpVqnj0KsPKuPK0cpA== +jest-each@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.7.1.tgz#fcc7dda4147c28430ad9fb6dc7211cd17ab54e74" + integrity sha512-4fsS8fEfLa3lfnI1Jw6NxjhyRTgfpuOVTeUZZFyVYqeTa4hPhr2YkToUhouuLTrL2eMGOfpbdMyRx0GQ/VooKA== dependencies: + "@jest/types" "^24.7.0" chalk "^2.0.1" - jest-get-type "^24.0.0" - jest-util "^24.0.0" - pretty-format "^24.0.0" - -jest-environment-jsdom@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz#5affa0654d6e44cd798003daa1a8701dbd6e4d11" - integrity sha512-1YNp7xtxajTRaxbylDc2pWvFnfDTH5BJJGyVzyGAKNt/lEULohwEV9zFqTgG4bXRcq7xzdd+sGFws+LxThXXOw== - dependencies: - jest-mock "^24.0.0" - jest-util "^24.0.0" + jest-get-type "^24.3.0" + jest-util "^24.7.1" + pretty-format "^24.7.0" + +jest-environment-jsdom@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.7.1.tgz#a40e004b4458ebeb8a98082df135fd501b9fbbd6" + integrity sha512-Gnhb+RqE2JuQGb3kJsLF8vfqjt3PHKSstq4Xc8ic+ax7QKo4Z0RWGucU3YV+DwKR3T9SYc+3YCUQEJs8r7+Jxg== + dependencies: + "@jest/environment" "^24.7.1" + "@jest/fake-timers" "^24.7.1" + "@jest/types" "^24.7.0" + jest-mock "^24.7.0" + jest-util "^24.7.1" jsdom "^11.5.1" -jest-environment-node@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.0.0.tgz#330948980656ed8773ce2e04eb597ed91e3c7190" - integrity sha512-62fOFcaEdU0VLaq8JL90TqwI7hLn0cOKOl8vY2n477vRkCJRojiRRtJVRzzCcgFvs6gqU97DNqX5R0BrBP6Rxg== +jest-environment-node@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.7.1.tgz#fa2c047a31522a48038d26ee4f7c8fd9c1ecfe12" + integrity sha512-GJJQt1p9/C6aj6yNZMvovZuxTUd+BEJprETdvTKSb4kHcw4mFj8777USQV0FJoJ4V3djpOwA5eWyPwfq//PFBA== dependencies: - jest-mock "^24.0.0" - jest-util "^24.0.0" + "@jest/environment" "^24.7.1" + "@jest/fake-timers" "^24.7.1" + "@jest/types" "^24.7.0" + jest-mock "^24.7.0" + jest-util "^24.7.1" -jest-get-type@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.0.0.tgz#36e72930b78e33da59a4f63d44d332188278940b" - integrity sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w== +jest-get-type@^24.3.0: + version "24.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.3.0.tgz#582cfd1a4f91b5cdad1d43d2932f816d543c65da" + integrity sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow== -jest-haste-map@24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0-alpha.6.tgz#fb2c785080f391b923db51846b86840d0d773076" - integrity sha512-+NO2HMbjvrG8BC39ieLukdpFrcPhhjCJGhpbHodHNZygH1Tt06WrlNYGpZtWKx/zpf533tCtMQXO/q59JenjNw== - dependencies: - fb-watchman "^2.0.0" - graceful-fs "^4.1.11" - invariant "^2.2.4" - jest-serializer "^24.0.0-alpha.6" - jest-worker "^24.0.0-alpha.6" - micromatch "^2.3.11" - sane "^3.0.0" - -jest-haste-map@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" - integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== +jest-haste-map@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.7.1.tgz#772e215cd84080d4bbcb759cfb668ad649a21471" + integrity sha512-g0tWkzjpHD2qa03mTKhlydbmmYiA2KdcJe762SbfFo/7NIMgBWAA0XqQlApPwkWOF7Cxoi/gUqL0i6DIoLpMBw== dependencies: + "@jest/types" "^24.7.0" + anymatch "^2.0.0" fb-watchman "^2.0.0" graceful-fs "^4.1.15" invariant "^2.2.4" - jest-serializer "^24.0.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" + jest-serializer "^24.4.0" + jest-util "^24.7.1" + jest-worker "^24.6.0" micromatch "^3.1.10" - sane "^3.0.0" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^1.2.7" -jest-jasmine2@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.0.0.tgz#7d87be9d8b32d34ac5980ad646b7ae7f99e33a19" - integrity sha512-q1xEV9KHM0bgfBj3yrkrjRF5kxpNDkWPCwVfSPN1DC+pD6J5wrM9/u2BgzhKhALXiaZUUhJ+f/OcEC0Gwpw90A== +jest-jasmine2@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.7.1.tgz#01398686dabe46553716303993f3be62e5d9d818" + integrity sha512-Y/9AOJDV1XS44wNwCaThq4Pw3gBPiOv/s6NcbOAkVRRUEPu+36L2xoPsqQXsDrxoBerqeyslpn2TpCI8Zr6J2w== dependencies: "@babel/traverse" "^7.1.0" + "@jest/environment" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" chalk "^2.0.1" co "^4.6.0" - expect "^24.0.0" + expect "^24.7.1" is-generator-fn "^2.0.0" - jest-each "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-snapshot "^24.0.0" - jest-util "^24.0.0" - pretty-format "^24.0.0" + jest-each "^24.7.1" + jest-matcher-utils "^24.7.0" + jest-message-util "^24.7.1" + jest-runtime "^24.7.1" + jest-snapshot "^24.7.1" + jest-util "^24.7.1" + pretty-format "^24.7.0" + throat "^4.0.0" -jest-leak-detector@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.0.0.tgz#78280119fd05ee98317daee62cddb3aa537a31c6" - integrity sha512-ZYHJYFeibxfsDSKowjDP332pStuiFT2xfc5R67Rjm/l+HFJWJgNIOCOlQGeXLCtyUn3A23+VVDdiCcnB6dTTrg== +jest-leak-detector@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.7.0.tgz#323ff93ed69be12e898f5b040952f08a94288ff9" + integrity sha512-zV0qHKZGXtmPVVzT99CVEcHE9XDf+8LwiE0Ob7jjezERiGVljmqKFWpV2IkG+rkFIEUHFEkMiICu7wnoPM/RoQ== dependencies: - pretty-format "^24.0.0" + pretty-format "^24.7.0" -jest-matcher-utils@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.0.0.tgz#fc9c41cfc49b2c3ec14e576f53d519c37729d579" - integrity sha512-LQTDmO+aWRz1Tf9HJg+HlPHhDh1E1c65kVwRFo5mwCVp5aQDzlkz4+vCvXhOKFjitV2f0kMdHxnODrXVoi+rlA== +jest-matcher-utils@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.7.0.tgz#bbee1ff37bc8b2e4afcaabc91617c1526af4bcd4" + integrity sha512-158ieSgk3LNXeUhbVJYRXyTPSCqNgVXOp/GT7O94mYd3pk/8+odKTyR1JLtNOQSPzNi8NFYVONtvSWA/e1RDXg== dependencies: chalk "^2.0.1" - jest-diff "^24.0.0" - jest-get-type "^24.0.0" - pretty-format "^24.0.0" + jest-diff "^24.7.0" + jest-get-type "^24.3.0" + pretty-format "^24.7.0" -jest-message-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.0.0.tgz#a07a141433b2c992dbaec68d4cbfe470ba289619" - integrity sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q== +jest-message-util@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.7.1.tgz#f1dc3a6c195647096a99d0f1dadbc447ae547018" + integrity sha512-dk0gqVtyqezCHbcbk60CdIf+8UHgD+lmRHifeH3JRcnAqh4nEyPytSc9/L1+cQyxC+ceaeP696N4ATe7L+omcg== dependencies: "@babel/code-frame" "^7.0.0" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" + "@types/stack-utils" "^1.0.1" chalk "^2.0.1" micromatch "^3.1.10" slash "^2.0.0" stack-utils "^1.0.1" -jest-mock@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.0.0.tgz#9a4b53e01d66a0e780f7d857462d063e024c617d" - integrity sha512-sQp0Hu5fcf5NZEh1U9eIW2qD0BwJZjb63Yqd98PQJFvf/zzUTBoUAwv/Dc/HFeNHIw1f3hl/48vNn+j3STaI7A== +jest-mock@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.7.0.tgz#e49ce7262c12d7f5897b0d8af77f6db8e538023b" + integrity sha512-6taW4B4WUcEiT2V9BbOmwyGuwuAFT2G8yghF7nyNW1/2gq5+6aTqSPcS9lS6ArvEkX55vbPAS/Jarx5LSm4Fng== + dependencies: + "@jest/types" "^24.7.0" -jest-regex-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.0.0.tgz#4feee8ec4a358f5bee0a654e94eb26163cb9089a" - integrity sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q== +jest-pnp-resolver@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" + integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== -jest-resolve-dependencies@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.0.0.tgz#86540611d660bdcaab8b87d069247d3832811d94" - integrity sha512-CJGS5ME2g5wL16o3Y22ga9p5ntNT5CUYX40/0lYj9ic9jB5YHm/qMKTgbFt9kowEBiMOFpXy15dWtBTEU54+zg== +jest-regex-util@^24.3.0: + version "24.3.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36" + integrity sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg== + +jest-resolve-dependencies@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.7.1.tgz#cf93bbef26999488a96a2b2012f9fe7375aa378f" + integrity sha512-2Eyh5LJB2liNzfk4eo7bD1ZyBbqEJIyyrFtZG555cSWW9xVHxII2NuOkSl1yUYTAYCAmM2f2aIT5A7HzNmubyg== dependencies: - jest-regex-util "^24.0.0" - jest-snapshot "^24.0.0" + "@jest/types" "^24.7.0" + jest-regex-util "^24.3.0" + jest-snapshot "^24.7.1" -jest-resolve@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.0.0.tgz#0206cfe842324f8796b01f706f4075309bf7b405" - integrity sha512-uKDGyJqNaBQKox1DJzm27CJobADsIMNgZGusXhtYzl98LKu/fKuokkRsd7EBVgoDA80HKHc3LOPKuYLryMu1vw== +jest-resolve@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.7.1.tgz#e4150198299298380a75a9fd55043fa3b9b17fde" + integrity sha512-Bgrc+/UUZpGJ4323sQyj85hV9d+ANyPNu6XfRDUcyFNX1QrZpSoM0kE4Mb2vZMAYTJZsBFzYe8X1UaOkOELSbw== dependencies: + "@jest/types" "^24.7.0" browser-resolve "^1.11.3" chalk "^2.0.1" - realpath-native "^1.0.0" - -jest-runner@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.0.0.tgz#00b280d52d23286111a8ed0362ed958283f7f0e3" - integrity sha512-XefXm2XimKtwdfi2am4364GfCmLD1tOjiRtDexY65diCXt4Rw23rxj2wiW7p9s8Nh9dzJQNmrheqZ5rzvn762g== - dependencies: + jest-pnp-resolver "^1.2.1" + realpath-native "^1.1.0" + +jest-runner@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.7.1.tgz#41c8a02a06aa23ea82d8bffd69d7fa98d32f85bf" + integrity sha512-aNFc9liWU/xt+G9pobdKZ4qTeG/wnJrJna3VqunziDNsWT3EBpmxXZRBMKCsNMyfy+A/XHiV+tsMLufdsNdgCw== + dependencies: + "@jest/console" "^24.7.1" + "@jest/environment" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" + chalk "^2.4.2" exit "^0.1.2" graceful-fs "^4.1.15" - jest-config "^24.0.0" - jest-docblock "^24.0.0" - jest-haste-map "^24.0.0" - jest-jasmine2 "^24.0.0" - jest-leak-detector "^24.0.0" - jest-message-util "^24.0.0" - jest-runtime "^24.0.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" + jest-config "^24.7.1" + jest-docblock "^24.3.0" + jest-haste-map "^24.7.1" + jest-jasmine2 "^24.7.1" + jest-leak-detector "^24.7.0" + jest-message-util "^24.7.1" + jest-resolve "^24.7.1" + jest-runtime "^24.7.1" + jest-util "^24.7.1" + jest-worker "^24.6.0" source-map-support "^0.5.6" throat "^4.0.0" -jest-runtime@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.0.0.tgz#bc80756f5458c2c8e4db86f44b687ff692026c13" - integrity sha512-UeVoTGiij8upcqfyBlJvImws7IGY+ZWtgVpt1h4VmVbyei39tVGia/20VoP3yvodS6FdjTwBj+JzVNuoh/9UTw== - dependencies: - "@babel/core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" +jest-runtime@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.7.1.tgz#2ffd70b22dd03a5988c0ab9465c85cdf5d25c597" + integrity sha512-0VAbyBy7tll3R+82IPJpf6QZkokzXPIS71aDeqh+WzPRXRCNz6StQ45otFariPdJ4FmXpDiArdhZrzNAC3sj6A== + dependencies: + "@jest/console" "^24.7.1" + "@jest/environment" "^24.7.1" + "@jest/source-map" "^24.3.0" + "@jest/transform" "^24.7.1" + "@jest/types" "^24.7.0" + "@types/yargs" "^12.0.2" chalk "^2.0.1" - convert-source-map "^1.4.0" exit "^0.1.2" - fast-json-stable-stringify "^2.0.0" glob "^7.1.3" graceful-fs "^4.1.15" - jest-config "^24.0.0" - jest-haste-map "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" - jest-resolve "^24.0.0" - jest-snapshot "^24.0.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" - micromatch "^3.1.10" - realpath-native "^1.0.0" + jest-config "^24.7.1" + jest-haste-map "^24.7.1" + jest-message-util "^24.7.1" + jest-mock "^24.7.0" + jest-regex-util "^24.3.0" + jest-resolve "^24.7.1" + jest-snapshot "^24.7.1" + jest-util "^24.7.1" + jest-validate "^24.7.0" + realpath-native "^1.1.0" slash "^2.0.0" - strip-bom "3.0.0" - write-file-atomic "^2.4.2" + strip-bom "^3.0.0" yargs "^12.0.2" -jest-serializer@24.0.0-alpha.6, jest-serializer@^24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0-alpha.6.tgz#27d2fee4b1a85698717a30c3ec2ab80767312597" - integrity sha512-IPA5T6/GhlE6dedSk7Cd7YfuORnYjN0VD5iJVFn1Q81RJjpj++Hen5kJbKcg547vXsQ1TddV15qOA/zeIfOCLw== - -jest-serializer@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" - integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== +jest-serializer@^24.4.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3" + integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q== -jest-snapshot@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.0.0.tgz#fb447a753a3271660b3d89d068698014eb14c414" - integrity sha512-7OcrckVnfzVYxSGPYl2Sn+HyT30VpDv+FMBFbQxSQ6DV2K9Js6vYT6d4SBPKp6DfDiEL2txNssJBxtlvF+Dymw== +jest-snapshot@^24.0.0, jest-snapshot@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.7.1.tgz#bd5a35f74aedff070975e9e9c90024f082099568" + integrity sha512-8Xk5O4p+JsZZn4RCNUS3pxA+ORKpEKepE+a5ejIKrId9CwrVN0NY+vkqEkXqlstA5NMBkNahXkR/4qEBy0t5yA== dependencies: "@babel/types" "^7.0.0" + "@jest/types" "^24.7.0" chalk "^2.0.1" - jest-diff "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-resolve "^24.0.0" + expect "^24.7.1" + jest-diff "^24.7.0" + jest-matcher-utils "^24.7.0" + jest-message-util "^24.7.1" + jest-resolve "^24.7.1" mkdirp "^0.5.1" natural-compare "^1.4.0" - pretty-format "^24.0.0" + pretty-format "^24.7.0" semver "^5.5.0" -jest-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.0.0.tgz#fd38fcafd6dedbd0af2944d7a227c0d91b68f7d6" - integrity sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ== +jest-util@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.7.1.tgz#b4043df57b32a23be27c75a2763d8faf242038ff" + integrity sha512-/KilOue2n2rZ5AnEBYoxOXkeTu6vi7cjgQ8MXEkih0oeAXT6JkS3fr7/j8+engCjciOU1Nq5loMSKe0A1oeX0A== dependencies: + "@jest/console" "^24.7.1" + "@jest/fake-timers" "^24.7.1" + "@jest/source-map" "^24.3.0" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" callsites "^3.0.0" chalk "^2.0.1" graceful-fs "^4.1.15" is-ci "^2.0.0" - jest-message-util "^24.0.0" mkdirp "^0.5.1" slash "^2.0.0" source-map "^0.6.0" -jest-validate@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.0.0.tgz#aa8571a46983a6538328fef20406b4a496b6c020" - integrity sha512-vMrKrTOP4BBFIeOWsjpsDgVXATxCspC9S1gqvbJ3Tnn/b9ACsJmteYeVx9830UMV28Cob1RX55x96Qq3Tfad4g== +jest-validate@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.7.0.tgz#70007076f338528ee1b1c8a8258b1b0bb982508d" + integrity sha512-cgai/gts9B2chz1rqVdmLhzYxQbgQurh1PEQSvSgPZ8KGa1AqXsqC45W5wKEwzxKrWqypuQrQxnF4+G9VejJJA== dependencies: + "@jest/types" "^24.7.0" camelcase "^5.0.0" chalk "^2.0.1" - jest-get-type "^24.0.0" + jest-get-type "^24.3.0" leven "^2.1.0" - pretty-format "^24.0.0" + pretty-format "^24.7.0" -jest-watcher@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.0.0.tgz#20d44244d10b0b7312410aefd256c1c1eef68890" - integrity sha512-GxkW2QrZ4YxmW1GUWER05McjVDunBlKMFfExu+VsGmXJmpej1saTEKvONdx5RJBlVdpPI5x6E3+EDQSIGgl53g== +jest-watcher@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.7.1.tgz#e161363d7f3f4e1ef3d389b7b3a0aad247b673f5" + integrity sha512-Wd6TepHLRHVKLNPacEsBwlp9raeBIO+01xrN24Dek4ggTS8HHnOzYSFnvp+6MtkkJ3KfMzy220KTi95e2rRkrw== dependencies: + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" + "@types/yargs" "^12.0.9" ansi-escapes "^3.0.0" chalk "^2.0.1" - jest-util "^24.0.0" + jest-util "^24.7.1" string-length "^2.0.0" -jest-worker@24.0.0-alpha.6, jest-worker@^24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0-alpha.6.tgz#463681b92c117c57107135c14b9b9d6cd51d80ce" - integrity sha512-iXtH7MR9bjWlNnlnRBcrBRrb4cSVxML96La5vsnmBvDI+mJnkP5uEt6Fgpo5Y8f3z9y2Rd7wuPnKRxqQsiU/dA== - dependencies: - merge-stream "^1.0.1" - -jest-worker@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" - integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== +jest-worker@^24.6.0: + version "24.6.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" + integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ== dependencies: merge-stream "^1.0.1" supports-color "^6.1.0" -jest@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.0.0.tgz#b8e2c8e6274e1092c7f56e57762a1fdc7800201e" - integrity sha512-1Z2EblP4BnERbWZGtipGb9zjHDq7nCHgCY7V57F5SYaFRJV4DE1HKoOz+CRC5OrAThN9OVhRlUhTzsTFArg2iQ== +jest@^24.6.0: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-24.7.1.tgz#0d94331cf510c75893ee32f87d7321d5bf8f2501" + integrity sha512-AbvRar5r++izmqo5gdbAjTeA6uNRGoNRuj5vHB0OnDXo2DXWZJVuaObiGgtlvhKb+cWy2oYbQSfxv7Q7GjnAtA== dependencies: import-local "^2.0.0" - jest-cli "^24.0.0" + jest-cli "^24.7.1" js-levenshtein@^1.1.3: version "1.1.4" @@ -4908,10 +5585,20 @@ js-levenshtein@^1.1.3: "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.12.0: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" -js-yaml@^3.12.0, js-yaml@^3.9.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" +js-yaml@^3.13.0, js-yaml@^3.9.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" + integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -4919,10 +5606,12 @@ js-yaml@^3.12.0, js-yaml@^3.9.0: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsdom@^11.5.1: version "11.12.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== dependencies: abab "^2.0.0" acorn "^5.5.3" @@ -4952,8 +5641,9 @@ jsdom@^11.5.1: xml-name-validator "^3.0.0" jsesc@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" @@ -4963,10 +5653,6 @@ json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -4974,6 +5660,7 @@ json-schema-traverse@^0.4.1: json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" @@ -4989,10 +5676,17 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json5@^0.5.0: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + json5@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" @@ -5025,6 +5719,7 @@ jsonparse@^1.2.0: jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" @@ -5041,22 +5736,26 @@ jsx-ast-utils@^2.0.1: kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== klaw@^1.0.0: version "1.3.1" @@ -5064,10 +5763,10 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -kleur@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" - integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== +kleur@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== lcid@^1.0.0: version "1.0.0" @@ -5078,39 +5777,42 @@ lcid@^1.0.0: lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== dependencies: invert-kv "^2.0.0" left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - -lerna@^3.10.6: - version "3.10.6" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.10.6.tgz#d4d0566a0ef78855e22ec85c7120137f6a583040" - integrity sha512-qdoyEpozHKQQnrpaDWbhiFG85/CBAyz2rkcj78JQVl2g400n9FFqS2Zweol5wusRnUzmpQKxFFll4P9DzIzSIA== - dependencies: - "@lerna/add" "3.10.6" - "@lerna/bootstrap" "3.10.6" - "@lerna/changed" "3.10.6" - "@lerna/clean" "3.10.6" - "@lerna/cli" "3.10.6" - "@lerna/create" "3.10.6" - "@lerna/diff" "3.10.6" - "@lerna/exec" "3.10.6" - "@lerna/import" "3.10.6" - "@lerna/init" "3.10.6" - "@lerna/link" "3.10.6" - "@lerna/list" "3.10.6" - "@lerna/publish" "3.10.6" - "@lerna/run" "3.10.6" - "@lerna/version" "3.10.6" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + +lerna@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.14.0.tgz#b5485fa1614f6d25d8bf48926639f4ae9f5aa5b0" + integrity sha512-AJobp8D/ovN6CC+nmkaTQ2KgbFH4bU2bNRaGp+30iqVoK9q0DVyAtnB7/hcql4kAE22iL/jpbKd5aSDls8oH3w== + dependencies: + "@lerna/add" "3.14.0" + "@lerna/bootstrap" "3.14.0" + "@lerna/changed" "3.14.0" + "@lerna/clean" "3.14.0" + "@lerna/cli" "3.13.0" + "@lerna/create" "3.14.0" + "@lerna/diff" "3.14.0" + "@lerna/exec" "3.14.0" + "@lerna/import" "3.14.0" + "@lerna/init" "3.14.0" + "@lerna/link" "3.14.0" + "@lerna/list" "3.14.0" + "@lerna/publish" "3.14.0" + "@lerna/run" "3.14.0" + "@lerna/version" "3.14.0" import-local "^1.0.0" - libnpm "^2.0.1" + npmlog "^4.1.2" leven@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= levn@^0.3.0, levn@~0.3.0: version "0.3.0" @@ -5119,32 +5821,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libnpm@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/libnpm/-/libnpm-2.0.1.tgz#a48fcdee3c25e13c77eb7c60a0efe561d7fb0d8f" - integrity sha512-qTKoxyJvpBxHZQB6k0AhSLajyXq9ZE/lUsZzuHAplr2Bpv9G+k4YuYlExYdUCeVRRGqcJt8hvkPh4tBwKoV98w== - dependencies: - bin-links "^1.1.2" - bluebird "^3.5.3" - find-npm-prefix "^1.0.2" - libnpmaccess "^3.0.1" - libnpmconfig "^1.2.1" - libnpmhook "^5.0.2" - libnpmorg "^1.0.0" - libnpmpublish "^1.1.0" - libnpmsearch "^2.0.0" - libnpmteam "^1.0.1" - lock-verify "^2.0.2" - npm-lifecycle "^2.1.0" - npm-logical-tree "^1.2.1" - npm-package-arg "^6.1.0" - npm-profile "^4.0.1" - npm-registry-fetch "^3.8.0" - npmlog "^4.1.2" - pacote "^9.2.3" - read-package-json "^2.0.13" - stringify-package "^1.0.0" - libnpmaccess@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8" @@ -5155,39 +5831,10 @@ libnpmaccess@^3.0.1: npm-package-arg "^6.1.0" npm-registry-fetch "^3.8.0" -libnpmconfig@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0" - integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA== - dependencies: - figgy-pudding "^3.5.1" - find-up "^3.0.0" - ini "^1.3.5" - -libnpmhook@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-5.0.2.tgz#d12817b0fb893f36f1d5be20017f2aea25825d94" - integrity sha512-vLenmdFWhRfnnZiNFPNMog6CK7Ujofy2TWiM2CrpZUjBRIhHkJeDaAbJdYCT6W4lcHtyrJR8yXW8KFyq6UAp1g== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^3.8.0" - -libnpmorg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232" - integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^3.8.0" - -libnpmpublish@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-1.1.0.tgz#773bd6fc9ed247e4a41a68ebd69fdc096ea630a3" - integrity sha512-mQ3LT2EWlpJ6Q8mgHTNqarQVCgcY32l6xadPVPMcjWLtVLz7II4WlWkzlbYg1nHGAf+xyABDwS+3aNUiRLkyaA== +libnpmpublish@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-1.1.1.tgz#ff0c6bb0b4ad2bda2ad1f5fba6760a4af37125f0" + integrity sha512-nefbvJd/wY38zdt+b9SHL6171vqBrMtZ56Gsgfd0duEKb/pB8rDT4/ObUQLrHz1tOfht1flt2zM+UGaemzAG5g== dependencies: aproba "^2.0.0" figgy-pudding "^3.5.1" @@ -5199,24 +5846,10 @@ libnpmpublish@^1.1.0: semver "^5.5.1" ssri "^6.0.1" -libnpmsearch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.0.tgz#de05af47ada81554a5f64276a69599070d4a5685" - integrity sha512-vd+JWbTGzOSfiOc+72MU6y7WqmBXn49egCCrIXp27iE/88bX8EpG64ST1blWQI1bSMUr9l1AKPMVsqa2tS5KWA== - dependencies: - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - npm-registry-fetch "^3.8.0" - -libnpmteam@^1.0.1: +listenercount@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213" - integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^3.8.0" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= load-json-file@^1.0.0: version "1.1.0" @@ -5258,31 +5891,40 @@ locate-path@^2.0.0: locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" path-exists "^3.0.0" -lock-verify@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.0.2.tgz#148e4f85974915c9e3c34d694b7de9ecb18ee7a8" - integrity sha512-QNVwK0EGZBS4R3YQ7F1Ox8p41Po9VGl2QG/2GsuvTbkJZYSsPeWHKMbbH6iZMCHWSMww5nrJroZYnGzI4cePuw== - dependencies: - npm-package-arg "^5.1.2 || 6" - semver "^5.4.1" - lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.assign@^4.0.3, lodash.assign@^4.0.6: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= lodash.template@^4.0.2: version "4.4.0" @@ -5303,11 +5945,36 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" -loose-envify@^1.0.0, loose-envify@^1.3.1: +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +logkitty@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.5.0.tgz#5a348c2049551aa02da69543c3b5c44e28c7c24f" + integrity sha512-UA06TmPaSPiHxMBlo5uxL3ZvjJ2Gx/rEECrqowHsIsNoAoSB8aBSP553Fr2FJhOp3it2ulLsd520DZWS1IaYOw== + dependencies: + ansi-fragments "^0.2.1" + yargs "^12.0.5" + +loose-envify@^1.0.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: @@ -5321,6 +5988,11 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" @@ -5343,6 +6015,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +macos-release@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.1.0.tgz#c87935891fbeb0dba7537913fc66f469fee9d662" + integrity sha512-8TCbwvN1mfNxbBv0yBtfyIFMo3m1QsNbKHv7PYIp/abRBKVQBXN7ecu3aeGGgT18VC/Tf397LBDGZF9KBGJFFw== + make-dir@^1.0.0, make-dir@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -5369,18 +6046,21 @@ make-fetch-happen@^4.0.1: makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-age-cleaner@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74" + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== dependencies: p-defer "^1.0.0" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" @@ -5395,12 +6075,18 @@ map-obj@^2.0.0: map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" -math-random@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" +md5@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" mem@^1.1.0: version "1.1.0" @@ -5409,12 +6095,13 @@ mem@^1.1.0: mimic-fn "^1.0.0" mem@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== dependencies: map-age-cleaner "^0.1.1" - mimic-fn "^1.0.0" - p-is-promise "^1.1.0" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" meow@^3.3.0: version "3.7.0" @@ -5450,6 +6137,7 @@ meow@^4.0.0: merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= dependencies: readable-stream "^2.0.1" @@ -5458,126 +6146,97 @@ merge2@^1.2.3: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== -merge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - -metro-babel-transformer@0.51.0: - version "0.51.0" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.51.0.tgz#9ee5199163ac46b2057527b3f8cbd8b089ffc03e" - integrity sha512-M7KEY/hjD3E8tJEliWgI0VOSaJtqaznC0ItM6FiMrhoGDqqa1BvGofl+EPcKqjBSOV1UgExua/T1VOIWbjwQsw== +metro-babel-register@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.54.1.tgz#7d2bfe444b1ccef8de99aedc7d9330891d806076" + integrity sha512-j3VydgncUG8HP6AZala6GTIt3V01nptodnnOke3JMYLqgk8EJ1LOVOdotK9pXi80o7EmmNKFs/LyyH8z+uAJzQ== dependencies: "@babel/core" "^7.0.0" + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/register" "^7.0.0" + core-js "^2.2.2" + escape-string-regexp "^1.0.5" -metro-babel-transformer@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.51.1.tgz#97be9e2b96c78aa202b52ae05fb86f71327aef72" - integrity sha512-+tOnZZzOzufB86ASdfimUEGB1jBKsdsVpPdjNJZkueTFyvYlGqWDQKHM1w9bwKMeM/czPQ48Y6m8Bou6le0X4w== +metro-babel-transformer@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.54.1.tgz#371ffa2d1118b22cc9e40b3c3ea6738c49dae9dc" + integrity sha512-2aiAnuYBdcLV1VINb8ENAA4keIaJIepHgR9+iRvIde+9GSjKnexqx4nNmJN392285gRDp1fVZ7uY0uQawK/A5g== dependencies: "@babel/core" "^7.0.0" -metro-babel7-plugin-react-transform@0.51.0: - version "0.51.0" - resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.51.0.tgz#af27dd81666b91f05d2b371b0d6d283c585e38b6" - integrity sha512-dZ95kXcE2FJMoRsYhxr7YLCbOlHWKwe0bOpihRhfImDTgFfuKIzU4ROQwMUbE0NCbzB+ATFsa2FZ3pHDJ5GI0w== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - -metro-babel7-plugin-react-transform@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.51.1.tgz#9cce2c340cc4006fc82aa6dfab27af22d592607e" - integrity sha512-wzn4X9KgmAMZ7Bi6v9KxA7dw+AHGL0RODPxU5NDJ3A6d0yERvzfZ3qkzWhz8jbFkVBK12cu5DTho3HBazKQDOw== +metro-babel7-plugin-react-transform@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.54.1.tgz#5335b810284789724886dc483d5bde9c149a1996" + integrity sha512-jWm5myuMoZAOhoPsa8ItfDxdTcOzKhTTzzhFlbZnRamE7i9qybeMdrZt8KHQpF7i2p/mKzE9Yhf4ouOz5K/jHg== dependencies: "@babel/helper-module-imports" "^7.0.0" -metro-cache@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.51.1.tgz#d0b296eab8e009214413bba87e4eac3d9b44cd04" - integrity sha512-0m1+aicsw77LVAehNuTxDpE1c/7Xv/ajRD+UL/lFCWUxnrjSbxVtIKr8l5DxEY11082c1axVRuaV9e436W+eXg== +metro-cache@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.54.1.tgz#2e9017cbd11106837b8c385c9eb8c8175469a8c1" + integrity sha512-RxCFoNcANHXZYi4MIQNnqh68gUnC3bMpzCFJY5pBoqqdrkkn8ibYglBweA0/DW7hx1OZTJWelwS1Dp8xxmE2CA== dependencies: - jest-serializer "24.0.0-alpha.6" - metro-core "0.51.1" + jest-serializer "^24.4.0" + metro-core "0.54.1" mkdirp "^0.5.1" rimraf "^2.5.4" -metro-config@0.51.1, metro-config@^0.51.0: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.51.1.tgz#8f1a241ce2c0b521cd492c39bc5c6c69e3397b82" - integrity sha512-WCNd0tTI9gb/ubgTqK1+ljZL4b3hsXVinsOAtep4nHiVb6DSDdbO2yXDD2rpYx3NE6hDRMFS9HHg6G0139pAqQ== +metro-config@0.54.1, metro-config@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.54.1.tgz#808b4e17625d9f4e9afa34232778fdf8e63cc8dd" + integrity sha512-FpxrA+63rGkPGvGI653dvuSreJzU+eOTILItVnnhmqwn2SAK5V00N/qGTOIJe2YIuWEFXwCzw9lXmANrXbwuGg== dependencies: cosmiconfig "^5.0.5" - metro "0.51.1" - metro-cache "0.51.1" - metro-core "0.51.1" - pretty-format "24.0.0-alpha.6" - -metro-core@0.51.1, metro-core@^0.51.0: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.51.1.tgz#e7227fb1dd1bb3f953272fad9876e6201140b038" - integrity sha512-sG1yACjdFqmIzZN50HqLTKUMp1oy0AehHhmIuYeIllo1DjX6Y2o3UAT3rGP8U+SAqJGXf/OWzl6VNyRPGDENfA== - dependencies: - jest-haste-map "24.0.0-alpha.6" + jest-validate "^24.7.0" + metro "0.54.1" + metro-cache "0.54.1" + metro-core "0.54.1" + pretty-format "^24.7.0" + +metro-core@0.54.1, metro-core@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.54.1.tgz#17f6ecc167918da8819d4af5726349e55714954b" + integrity sha512-8oz3Ck7QFBzW9dG9tKFhrXHKPu2Ajx3R7eatf61Gl6Jf/tF7PNouv3wHxPsJW3oXDFiwKLszd89+OgleTGkB5g== + dependencies: + jest-haste-map "^24.7.1" lodash.throttle "^4.1.1" - metro-resolver "0.51.1" + metro-resolver "0.54.1" wordwrap "^1.0.0" -metro-memory-fs@^0.51.0: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-memory-fs/-/metro-memory-fs-0.51.1.tgz#624291f5956b0fd11532d80b1b85d550926f96c9" - integrity sha512-dXVUpLPLwfQcYHd1HlqHGVzBsiwvUdT92TDSbdc10152TP+iynHBqLDWbxt0MAtd6c/QXwOuGZZ1IcX3+lv5iw== - -metro-minify-uglify@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.51.1.tgz#60cd8fe4d3e82d6670c717b8ddb52ae63199c0e4" - integrity sha512-HAqd/rFrQ6mnbqVAszDXIKTg2rqHlY9Fm8DReakgbkAeyMbF2mH3kEgtesPmTrhajdFk81UZcNSm6wxj1JMgVg== +metro-inspector-proxy@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.54.1.tgz#0ef48ee3feb11c6da47aa100151a9bf2a7c358ee" + integrity sha512-sf6kNu7PgFW6U+hU7YGZfbAUKAPVvCJhY8YVu/A1RMKH9nNULrCo+jlWh0gWgmFfWRQiAPCElevROg+5somk8A== dependencies: - uglify-es "^3.1.9" + connect "^3.6.5" + debug "^2.2.0" + rxjs "^5.4.3" + ws "^1.1.5" + yargs "^9.0.0" -metro-react-native-babel-preset@0.51.0: - version "0.51.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.51.0.tgz#978d960acf2d214bbbe43e59145878d663bd07de" - integrity sha512-Y/aPeLl4RzY8IEAneOyDcpdjto/8yjIuX9eUWRngjSqdHYhGQtqiSBpfTpo0BvXpwNRLwCLHyXo58gNpckTJFw== +metro-memory-fs@^0.53.1: + version "0.53.1" + resolved "https://registry.yarnpkg.com/metro-memory-fs/-/metro-memory-fs-0.53.1.tgz#d8975317122b8a9a90f649337d58da85e4ae2559" + integrity sha512-Xb6/TnMOjquTIRyKpaGx/jYM01+ajtQEjGpGS/N1TtnQeW0P7HMZnD+e/FpMgXmdqsf2IiQMK7l8WONU2L3Evw== + +metro-minify-uglify@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.54.1.tgz#54ed1cb349245ce82dba8cc662bbf69fbca142c3" + integrity sha512-z+pOPna/8IxD4OhjW6Xo1mV2EszgqqQHqBm1FdmtdF6IpWkQp33qpDBNEi9NGZTOr7pp2bvcxZnvNJdC2lrK9Q== dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-assign" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - metro-babel7-plugin-react-transform "0.51.0" - react-transform-hmr "^1.0.4" + uglify-es "^3.1.9" -metro-react-native-babel-preset@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.51.1.tgz#44aeeedfea37f7c2ab8f6f273fa71b90fe65f089" - integrity sha512-e9tsYDFhU70gar0jQWcZXRPJVCv4k7tEs6Pm74wXO2OO/T1MEumbvniDIGwGG8bG8RUnYdHhjcaiub2Vc5BRWw== +metro-react-native-babel-preset@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.54.1.tgz#b8f03865c381841d7f8912e7ba46804ea3a928b8" + integrity sha512-Hfr32+u5yYl3qhYQJU8NQ26g4kQlc3yFMg7keVR/3H8rwBIbFqXgsKt8oe0dOrv7WvrMqBHhDtVdU9ls3sSq8g== dependencies: "@babel/plugin-proposal-class-properties" "^7.0.0" "@babel/plugin-proposal-export-default-from" "^7.0.0" @@ -5587,6 +6246,7 @@ metro-react-native-babel-preset@0.51.1: "@babel/plugin-proposal-optional-chaining" "^7.0.0" "@babel/plugin-syntax-dynamic-import" "^7.0.0" "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.0.0" "@babel/plugin-transform-block-scoping" "^7.0.0" "@babel/plugin-transform-classes" "^7.0.0" @@ -5612,37 +6272,39 @@ metro-react-native-babel-preset@0.51.1: "@babel/plugin-transform-typescript" "^7.0.0" "@babel/plugin-transform-unicode-regex" "^7.0.0" "@babel/template" "^7.0.0" - metro-babel7-plugin-react-transform "0.51.1" + metro-babel7-plugin-react-transform "0.54.1" react-transform-hmr "^1.0.4" -metro-react-native-babel-transformer@^0.51.0: - version "0.51.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.51.0.tgz#57a695e97a19d95de63c9633f9d0dc024ee8e99a" - integrity sha512-VFnqtE0qrVmU1HV9B04o53+NZHvDwR+CWCoEx4+7vCqJ9Tvas741biqCjah9xtifoKdElQELk6x0soOAWCDFJA== +metro-react-native-babel-transformer@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.54.1.tgz#45b56db004421134e10e739f69e8de50775fef17" + integrity sha512-ECw7xG91t8dk/PHdiyoC5SP1s9OQzfmJzG5m0YOZaKtHMe534qTDbncxaKfTI3CP99yti2maXFBRVj+xyvph/g== dependencies: "@babel/core" "^7.0.0" - babel-preset-fbjs "^3.0.1" - metro-babel-transformer "0.51.0" - metro-react-native-babel-preset "0.51.0" + babel-preset-fbjs "^3.1.2" + metro-babel-transformer "0.54.1" + metro-react-native-babel-preset "0.54.1" -metro-resolver@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.51.1.tgz#4c26f0baee47d30250187adca3d34c902e627611" - integrity sha512-zmWbD/287NDA/jLPuPV0hne/YMMSG0dljzu21TYMg2lXRLur/zROJHHhyepZvuBHgInXBi4Vhr2wvuSnY39SuA== +metro-resolver@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.54.1.tgz#0295b38624b678b88b16bf11d47288845132b087" + integrity sha512-Byv1LIawYAASy9CFRwzrncYnqaFGLe8vpw178EtzStqP05Hu6hXSqkNTrfoXa+3V9bPFGCrVzFx2NY3gFp2btg== dependencies: absolute-path "^0.0.0" -metro-source-map@0.51.1: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.51.1.tgz#1a8da138e98e184304d5558b4f92a5c2141822d0" - integrity sha512-JyrE+RV4YumrboHPHTGsUUGERjQ681ImRLrSYDGcmNv4tfpk9nvAK26UAas4IvBYFCC9oW90m0udt3kaQGv59Q== +metro-source-map@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.54.1.tgz#e17bad53c11978197d3c05c9168d799c2e04dcc5" + integrity sha512-E9iSYMSUSq5qYi1R2hTQtxH4Mxjzfgr/jaSmQIWi7h3fG2P1qOZNNSzeaeUeTK+s2N/ksVlkcL5kMikol8CDrQ== dependencies: + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" source-map "^0.5.6" -metro@0.51.1, metro@^0.51.0: - version "0.51.1" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.51.1.tgz#b0aad4731593b9f244261bad1abb2a006d1c8969" - integrity sha512-nM0dqn8LQlMjhChl2fzTUq2EWiUebZM7nkesD9vQe47W10bj/tbRLPiIIAxht6SRDbPd/hRA+t39PxLhPSKEKg== +metro@0.54.1, metro@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.54.1.tgz#a629be00abee5a450a25a8f71c24745f70cc9b44" + integrity sha512-6ODPT4mEo4FCpbExRNnQAcZmf1VeNvYOTMj2Na03FjGqhNODHhI2U/wF/Ul5gqTyJ2dVdkXeyvKW3gl/LrnJRg== dependencies: "@babel/core" "^7.0.0" "@babel/generator" "^7.0.0" @@ -5653,7 +6315,7 @@ metro@0.51.1, metro@^0.51.0: "@babel/types" "^7.0.0" absolute-path "^0.0.0" async "^2.4.0" - babel-preset-fbjs "^3.0.1" + babel-preset-fbjs "^3.1.2" buffer-crc32 "^0.2.13" chalk "^2.4.1" concat-stream "^1.6.0" @@ -5666,19 +6328,21 @@ metro@0.51.1, metro@^0.51.0: graceful-fs "^4.1.3" image-size "^0.6.0" invariant "^2.2.4" - jest-haste-map "24.0.0-alpha.6" - jest-worker "24.0.0-alpha.6" + jest-haste-map "^24.7.1" + jest-worker "^24.6.0" json-stable-stringify "^1.0.1" lodash.throttle "^4.1.1" merge-stream "^1.0.1" - metro-babel-transformer "0.51.1" - metro-cache "0.51.1" - metro-config "0.51.1" - metro-core "0.51.1" - metro-minify-uglify "0.51.1" - metro-react-native-babel-preset "0.51.1" - metro-resolver "0.51.1" - metro-source-map "0.51.1" + metro-babel-register "0.54.1" + metro-babel-transformer "0.54.1" + metro-cache "0.54.1" + metro-config "0.54.1" + metro-core "0.54.1" + metro-inspector-proxy "0.54.1" + metro-minify-uglify "0.54.1" + metro-react-native-babel-preset "0.54.1" + metro-resolver "0.54.1" + metro-source-map "0.54.1" mime-types "2.1.11" mkdirp "^0.5.1" node-fetch "^2.2.0" @@ -5696,24 +6360,6 @@ metro@0.51.1, metro@^0.51.0: xpipe "^1.0.5" yargs "^9.0.0" -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -5740,13 +6386,25 @@ mime-db@~1.23.0: version "1.23.0" resolved "http://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz#a31b4070adaea27d732ea333740a64d0ec9a6659" +mime-db@~1.38.0: + version "1.38.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" + integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== + mime-types@2.1.11: version "2.1.11" resolved "http://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz#c259c471bda808a85d6cd193b430a5fae4473b3c" dependencies: mime-db "~1.23.0" -mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.22" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" + integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== + dependencies: + mime-db "~1.38.0" + +mime-types@~2.1.18: version "2.1.21" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" dependencies: @@ -5756,13 +6414,25 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +mime@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.1.tgz#19eb7357bebbda37df585b14038347721558c715" + integrity sha512-VRUfmQO0rCd3hKwBymAn3kxYzBHr3I/wdVMywgG3HhXOwrCQgN84ZagpdTm2tZ4TNtwsSmyJWYO88mb5XvzGqQ== mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== min-document@^2.19.0: version "2.19.0" @@ -5794,7 +6464,8 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: minimist@~0.0.1: version "0.0.10" - resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: version "2.3.5" @@ -5828,6 +6499,7 @@ mississippi@^3.0.0: mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -5869,6 +6541,7 @@ move-concurrently@^1.0.1: ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.0.0, ms@^2.1.1: version "2.1.1" @@ -5895,6 +6568,7 @@ nan@^2.9.2: nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -5911,6 +6585,7 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= ncp@0.4.x: version "0.4.2" @@ -5928,9 +6603,15 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +neo-async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== node-fetch-npm@^2.0.2: version "2.0.2" @@ -5948,16 +6629,25 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-fetch@^2.1.1, node-fetch@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" + integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== + node-fetch@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.2.1.tgz#1fe551e0ded6c45b3b3b937d0fb46f76df718d1e" -node-gyp@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" - integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== +node-fetch@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.5.0.tgz#8028c49fc1191bba56a07adc6e2a954644a48501" + integrity sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw== + +node-gyp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-4.0.0.tgz#972654af4e5dd0cd2a19081b4b46fe0442ba6f45" + integrity sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA== dependencies: - fstream "^1.0.0" glob "^7.0.3" graceful-fs "^4.1.2" mkdirp "^0.5.0" @@ -5967,22 +6657,26 @@ node-gyp@^3.8.0: request "^2.87.0" rimraf "2" semver "~5.3.0" - tar "^2.0.0" + tar "^4.4.8" which "1" node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^5.2.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.3.0.tgz#c77a4a7b84038733d5fb351aafd8a268bfe19a01" + version "5.4.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.0.tgz#7b455fdce9f7de0c63538297354f3db468426e6a" + integrity sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ== dependencies: growly "^1.3.0" + is-wsl "^1.1.0" semver "^5.5.0" shellwords "^0.1.1" which "^1.3.0" @@ -6023,7 +6717,7 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -6032,36 +6726,47 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" +normalize-url@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" -npm-lifecycle@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.1.0.tgz#1eda2eedb82db929e3a0c50341ab0aad140ed569" - integrity sha512-QbBfLlGBKsktwBZLj6AviHC6Q9Y3R/AY4a2PYSIRhSKSS0/CxRyD/PfxEX6tPeOCXQgMSNdwGeECacstgptc+g== +npm-lifecycle@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.1.1.tgz#0027c09646f0fd346c5c93377bdaba59c6748fdf" + integrity sha512-+Vg6I60Z75V/09pdcH5iUo/99Q/vop35PaI99elvxk56azSVVsdsSsS/sXqKDNwbRRNN1qSxkcO45ZOu0yOWew== dependencies: byline "^5.0.0" - graceful-fs "^4.1.11" - node-gyp "^3.8.0" + graceful-fs "^4.1.15" + node-gyp "^4.0.0" resolve-from "^4.0.0" slide "^1.1.6" uid-number "0.0.6" umask "^1.1.0" which "^1.3.1" -npm-logical-tree@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" - integrity sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg== - -"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", "npm-package-arg@^5.1.2 || 6", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: +"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== @@ -6086,6 +6791,14 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" +npm-packlist@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-pick-manifest@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" @@ -6095,15 +6808,6 @@ npm-pick-manifest@^2.2.3: npm-package-arg "^6.0.0" semver "^5.4.1" -npm-profile@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa" - integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA== - dependencies: - aproba "^1.1.2 || 2" - figgy-pudding "^3.4.1" - npm-registry-fetch "^3.8.0" - npm-registry-fetch@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz#aa7d9a7c92aff94f48dba0984bdef4bd131c88cc" @@ -6116,9 +6820,22 @@ npm-registry-fetch@^3.8.0: make-fetch-happen "^4.0.1" npm-package-arg "^6.1.0" +npm-registry-fetch@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856" + integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" @@ -6138,14 +6855,17 @@ nullthrows@^1.1.0: number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= nwsapi@^2.0.7: - version "2.0.9" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.9.tgz#77ac0cdfdcad52b6a1151a84e73254edc33ed016" + version "2.1.3" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.1.3.tgz#25f3a5cec26c654f7376df6659cdf84b99df9558" + integrity sha512-RowAaJGEgYXEZfQ7tvvdtAQUKPyTR6T6wNu0fwlNsGQYr/h3yQc6oI8WnVZh3Y/Sylwc+dtAlvPqfFZjhTyk3A== oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" @@ -6154,61 +6874,54 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" -object-keys@^1.0.11, object-keys@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" +object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== +object.fromentries@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" + integrity sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA== dependencies: define-properties "^1.1.2" + es-abstract "^1.11.0" function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.entries@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" - integrity sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.6.1" - function-bind "^1.1.0" has "^1.0.1" object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= dependencies: define-properties "^1.1.2" es-abstract "^1.5.1" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" +octokit-pagination-methods@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" + integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -6231,15 +6944,17 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -opn@^3.0.2: - version "3.0.3" - resolved "http://registry.npmjs.org/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a" +open@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/open/-/open-6.2.0.tgz#7cf92cb961b5d8498b071e64098bf5e27f57230c" + integrity sha512-Vxf6HJkwrqmvh9UAID3MnMYXntbTxKLOSfOnO7LJdzPf3NE3KQYFNV0/Lcz2VAndbRFil58XVCyh8tiX11fiYw== dependencies: - object-assign "^4.0.1" + is-wsl "^1.1.0" optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -6259,10 +6974,29 @@ options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" +ora@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" + integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== + dependencies: + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-spinners "^2.0.0" + log-symbols "^2.2.0" + strip-ansi "^5.2.0" + wcwidth "^1.0.1" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" @@ -6272,13 +7006,22 @@ os-locale@^2.0.0: mem "^1.1.0" os-locale@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620" + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== dependencies: - execa "^0.10.0" + execa "^1.0.0" lcid "^2.0.0" mem "^4.0.0" +os-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.0.0.tgz#e1434dbfddb8e74b44c98b56797d951b7648a5d9" + integrity sha512-7c74tib2FsdFbQ3W+qj8Tyd1R3Z6tuVRNNxXjJcZ4NgjIEQU9N/prVMqcW29XZPXGACqaXN3jq58/6hoaoXH6g== + dependencies: + macos-release "^2.0.0" + windows-release "^3.1.0" + os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -6290,9 +7033,15 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= p-each-series@^1.0.0: version "1.0.0" @@ -6304,10 +7053,12 @@ p-each-series@^1.0.0: p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-is-promise@^1.1.0: - version "1.1.0" - resolved "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== p-limit@^1.1.0: version "1.3.0" @@ -6316,8 +7067,9 @@ p-limit@^1.1.0: p-try "^1.0.0" p-limit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== dependencies: p-try "^2.0.0" @@ -6330,6 +7082,7 @@ p-locate@^2.0.0: p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" @@ -6350,18 +7103,33 @@ p-pipe@^1.2.0: resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= +p-queue@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-4.0.0.tgz#ed0eee8798927ed6f2c2f5f5b77fdb2061a5d346" + integrity sha512-3cRXXn3/O0o3+eVmUroJPSj/esxoEFIm0ZOno/T+NzG/VZgPOqQ8WKmlNqubSEpZmCIngEy34unkHGg83ZIBmg== + dependencies: + eventemitter3 "^3.1.0" + p-reduce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" p-try@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== p-waterfall@^1.0.0: version "1.0.0" @@ -6370,10 +7138,10 @@ p-waterfall@^1.0.0: dependencies: p-reduce "^1.0.0" -pacote@^9.2.3: - version "9.4.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807" - integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w== +pacote@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.0.tgz#85f3013a3f6dd51c108b0ccabd3de8102ddfaeda" + integrity sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg== dependencies: bluebird "^3.5.3" cacache "^11.3.2" @@ -6417,15 +7185,6 @@ parse-github-repo-url@^1.3.0: resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -6435,13 +7194,33 @@ parse-json@^2.2.0: parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= dependencies: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.1.tgz#0ec769704949778cb3b8eda5e994c32073a1adff" + integrity sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA== + dependencies: + is-ssh "^1.3.0" + protocols "^1.4.0" + +parse-url@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-5.0.1.tgz#99c4084fc11be14141efa41b3d117a96fcb9527f" + integrity sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg== + dependencies: + is-ssh "^1.3.0" + normalize-url "^3.3.0" + parse-path "^4.0.0" + protocols "^1.4.0" + parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== parseurl@~1.3.2: version "1.3.2" @@ -6450,6 +7229,7 @@ parseurl@~1.3.2: pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-dirname@^1.0.0: version "1.0.2" @@ -6465,10 +7245,12 @@ path-exists@^2.0.0: path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" @@ -6477,6 +7259,7 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2: path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" @@ -6507,6 +7290,7 @@ path-type@^3.0.0: performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0, pify@^2.3.0: version "2.3.0" @@ -6515,6 +7299,7 @@ pify@^2.0.0, pify@^2.3.0: pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pinkie-promise@^2.0.0: version "2.0.1" @@ -6532,12 +7317,12 @@ pirates@^4.0.0: dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: - find-up "^1.0.0" + node-modules-regexp "^1.0.0" pkg-dir@^2.0.0: version "2.0.0" @@ -6548,9 +7333,17 @@ pkg-dir@^2.0.0: pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== dependencies: find-up "^3.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + pkginfo@0.3.x: version "0.3.1" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" @@ -6574,59 +7367,51 @@ pluralize@^7.0.0: pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^1.14.2: - version "1.15.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a" - integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg== - -prettier@^1.16.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.0.tgz#104dd25f5ee3d0c9d0a6ce4bb40ced8481d51219" - integrity sha512-MCBCYeAuZfejUPdEpkleLWvpRBwLii/Sp5jQs0eb8Ul/drGIDjkL6tAU24tk6yCGf0KPV5rhPPPlczfBmN2pWQ== +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -pretty-format@24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz#25ad2fa46b342d6278bf241c5d2114d4376fbac1" - integrity sha512-zG2m6YJeuzwBFqb5EIdmwYVf30sap+iMRuYNPytOccEXZMAJbPIFGKVJ/U0WjQegmnQbRo9CI7j6j3HtDaifiA== - dependencies: - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" +prettier@1.16.4: + version "1.16.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" + integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g== -pretty-format@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" - integrity sha512-LszZaKG665djUcqg5ZQq+XzezHLKrxsA86ZABTozp+oNhkdqa+tG2dX4qa6ERl5c/sRDrAa3lHmwnvKoP+OG/g== +pretty-format@^24.0.0, pretty-format@^24.7.0: + version "24.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.7.0.tgz#d23106bc2edcd776079c2daa5da02bcb12ed0c10" + integrity sha512-apen5cjf/U4dj7tHetpC7UEFCvtAgnNZnBDkfPv3fokzIqyOJckAG9OlAPC1BlFALnqT/lGB2tl9EJjlK6eCsA== dependencies: + "@jest/types" "^24.7.0" ansi-regex "^4.0.0" ansi-styles "^3.2.0" + react-is "^16.8.4" private@^0.1.6: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= + process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== process@~0.5.1: version "0.5.2" @@ -6666,11 +7451,11 @@ prompt@^0.2.14: winston "0.8.x" prompts@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.1.tgz#201b3718b4276fb407f037db48c0029d6465245c" - integrity sha512-8lnEOSIGQbgbnO47+13S+H204L8ISogGulyi0/NNEFAQ9D1VMNTrJ9SBX2Ra03V4iPn/zt36HQMndRYkaPoWiQ== + version "2.0.4" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.4.tgz#179f9d4db3128b9933aa35f93a800d8fce76a682" + integrity sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA== dependencies: - kleur "^3.0.0" + kleur "^3.0.2" sisteransi "^1.0.0" promzard@^0.3.0: @@ -6681,18 +7466,24 @@ promzard@^0.3.0: read "1" prop-types@^15.6.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" - integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== dependencies: - loose-envify "^1.3.1" + loose-envify "^1.4.0" object-assign "^4.1.1" + react-is "^16.8.1" proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= +protocols@^1.1.0, protocols@^1.4.0: + version "1.4.7" + resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32" + integrity sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg== + protoduck@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" @@ -6704,9 +7495,10 @@ pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -psl@^1.1.24: - version "1.1.29" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" +psl@^1.1.24, psl@^1.1.28: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== pump@^2.0.0: version "2.0.1" @@ -6735,8 +7527,9 @@ pumpify@^1.3.3: punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -6748,20 +7541,13 @@ q@^1.5.1: qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== quick-lru@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -6779,6 +7565,16 @@ react-deep-force-update@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.2.tgz#3d2ae45c2c9040cbb1772be52f8ea1ade6ca2ee1" +react-is@^16.8.1: + version "16.8.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.3.tgz#4ad8b029c2a718fc0cfc746c8d4e1b7221e5387d" + integrity sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA== + +react-is@^16.8.4: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" + integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== + react-proxy@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a" @@ -6886,7 +7682,7 @@ read@1, read@1.0.x, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@~2.3.6: version "2.3.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -6898,6 +7694,19 @@ read@1, read@1.0.x, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + integrity sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA= + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" @@ -6908,9 +7717,10 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -realpath-native@^1.0.0, realpath-native@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.2.tgz#cd51ce089b513b45cf9b1516c82989b51ccc6560" +realpath-native@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== dependencies: util.promisify "^1.0.0" @@ -6940,21 +7750,26 @@ regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + regenerator-transform@^0.13.3: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" dependencies: private "^0.1.6" -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -6987,14 +7802,17 @@ regjsparser@^0.3.0: remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.5.2, repeat-string@^1.6.1: +repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" @@ -7003,23 +7821,26 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" +request-promise-core@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346" + integrity sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag== dependencies: - lodash "^4.13.1" + lodash "^4.17.11" request-promise-native@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + version "1.0.7" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.7.tgz#a49868a624bdea5069f1251d0a836e0d89aa2c59" + integrity sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w== dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.3" + request-promise-core "1.1.2" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -7045,10 +7866,12 @@ request@^2.87.0: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= require-uncached@^1.0.3: version "1.0.3" @@ -7057,9 +7880,20 @@ require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" +requireindex@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" + integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== + +reselect@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" + integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= dependencies: resolve-from "^3.0.0" @@ -7070,6 +7904,7 @@ resolve-from@^1.0.0: resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= resolve-from@^4.0.0: version "4.0.0" @@ -7079,24 +7914,26 @@ resolve-from@^4.0.0: resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + +resolve@^1.10.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== + dependencies: + path-parse "^1.0.6" -resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1: +resolve@^1.5.0, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: path-parse "^1.0.5" -resolve@^1.6.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" - integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== - dependencies: - path-parse "^1.0.6" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -7107,6 +7944,7 @@ restore-cursor@^2.0.0: ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== retry@^0.10.0: version "0.10.1" @@ -7117,14 +7955,14 @@ revalidator@0.1.x: version "0.1.8" resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" -rimraf@2, rimraf@^2.5.2, rimraf@^2.6.2: +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" -rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -7134,9 +7972,10 @@ rimraf@~2.2.6: version "2.2.8" resolved "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" -rsvp@^3.3.3: - version "3.6.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" +rsvp@^4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" + integrity sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA== run-async@^2.2.0: version "2.3.0" @@ -7161,6 +8000,13 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +rxjs@^5.4.3: + version "5.5.12" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" + integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== + dependencies: + symbol-observable "1.0.1" + rxjs@^6.1.0: version "6.3.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" @@ -7173,42 +8019,54 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, s safe-regex@^1.1.0: version "1.1.0" - resolved "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: + "@cnakazawa/watch" "^1.0.3" anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" execa "^1.0.0" fb-watchman "^2.0.0" micromatch "^3.1.4" minimist "^1.1.1" walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== sax@~1.1.1: version "1.1.6" resolved "http://registry.npmjs.org/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +"semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" +semver@5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -7252,6 +8110,7 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -7261,13 +8120,14 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.5: +setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -7278,12 +8138,14 @@ setprototypeof@1.1.0: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shell-quote@1.6.1: version "1.6.1" @@ -7297,10 +8159,12 @@ shell-quote@1.6.1: shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= simple-plist@^1.0.0: version "1.0.0" @@ -7314,6 +8178,7 @@ simple-plist@^1.0.0: sisteransi@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" + integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== slash@^1.0.0: version "1.0.0" @@ -7331,6 +8196,15 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +slice-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + slide@^1.1.5, slide@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -7343,6 +8217,7 @@ smart-buffer@^4.0.1: snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -7351,12 +8226,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -7368,9 +8245,9 @@ snapdragon@^0.8.1: use "^3.1.0" snapshot-diff@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/snapshot-diff/-/snapshot-diff-0.5.0.tgz#f67f4441f0fed806ad759f937112cda8ba78ff2b" - integrity sha512-mDCiZCCPQb4JP8iD8+WRNo5snbcveQqmcm0uRiKedPn+8aIKhp1gvu8BQ3KE28XFT9fI0FChkMIr5zuQdYHlRw== + version "0.5.1" + resolved "https://registry.yarnpkg.com/snapshot-diff/-/snapshot-diff-0.5.1.tgz#8a74d11a4f89662d3f934dcbeccc4f773a817010" + integrity sha512-XBj1NE3oJiqdH/EcNzLSqSeCEnU458T57ZnbptrQ2/mKw+Z2Txu06vPMWG+morlbQp7nY6kkY7zPnHi1dgy6qg== dependencies: jest-diff "^24.0.0" jest-snapshot "^24.0.0" @@ -7403,6 +8280,7 @@ sort-keys@^2.0.0: source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -7411,8 +8289,17 @@ source-map-resolve@^0.5.0: urix "^0.1.0" source-map-support@^0.5.6: - version "0.5.9" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.9: + version "0.5.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" + integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -7420,18 +8307,22 @@ source-map-support@^0.5.6: source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== spdx-correct@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.2.tgz#19bb409e91b47b1ad54159243f7312a858db3c2e" + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -7439,21 +8330,25 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz#a59efc09784c2a5bada13cfeaf5c75dd214044d2" + version "3.0.4" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" + integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" @@ -7474,10 +8369,12 @@ split@^1.0.0: sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629" + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -7501,12 +8398,14 @@ stack-trace@0.0.x: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" stack-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" + version "1.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -7523,9 +8422,10 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" -stealthy-require@^1.1.0: +stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= stream-buffers@~2.2.0: version "2.2.0" @@ -7555,6 +8455,7 @@ string-length@^2.0.0: string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -7567,38 +8468,38 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -stringify-package@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b" - integrity sha512-JIQqiWmLiEozOC0b0BtxZ/AOUtdUZHCBPgqIZ2kSJJqGwgb9neo44XdTHUC4HZSGqi03hOeB7W/E8rAlKnGe9g== - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" +strip-ansi@^5.0.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: - ansi-regex "^4.0.0" - -strip-bom@3.0.0, strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + ansi-regex "^4.1.0" strip-bom@^2.0.0: version "2.0.0" @@ -7607,9 +8508,15 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + strip-eof@^1.0.0: version "1.0.0" - resolved "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-indent@^1.0.1: version "1.0.1" @@ -7640,22 +8547,41 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^5.3.0, supports-color@^5.4.0: +supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: +supports-color@^6.0.0, supports-color@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== dependencies: has-flag "^3.0.0" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= + symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= + +table@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" + integrity sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg== + dependencies: + ajv "^6.0.1" + ajv-keywords "^3.0.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" table@^5.0.2: version "5.1.0" @@ -7666,15 +8592,6 @@ table@^5.0.2: slice-ansi "1.0.0" string-width "^2.1.1" -tar@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - tar@^4: version "4.4.7" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.7.tgz#14df45023ffdcd0c233befa2fc01ebb76ee39e7c" @@ -7725,9 +8642,9 @@ temp@0.8.3: rimraf "~2.2.6" test-exclude@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.0.0.tgz#cdce7cece785e0e829cd5c2b27baf18bc583cfb7" - integrity sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw== + version "5.1.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.1.0.tgz#6ba6b25179d2d38724824661323b73e03c0c1de1" + integrity sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA== dependencies: arrify "^1.0.1" minimatch "^3.0.4" @@ -7754,10 +8671,15 @@ through2@^2.0.0, through2@^2.0.2: readable-stream "~2.3.6" xtend "~4.0.1" -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: +through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -7767,20 +8689,24 @@ tmp@^0.0.33: tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -7788,15 +8714,25 @@ to-regex-range@^2.1.0: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@>=2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.4.3: +tough-cookie@^2.3.3, tough-cookie@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" @@ -7804,9 +8740,15 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.4.3: tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= dependencies: punycode "^2.1.0" +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -7825,24 +8767,46 @@ trim-off-newlines@^1.0.0: trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +tsconfig-paths@^3.6.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.8.0.tgz#4e34202d5b41958f269cf56b01ed95b853d59f72" + integrity sha512-zZEYFo4sjORK8W58ENkRn9s+HmQFkkwydDG7My5s/fnfr2YYCaiyXe/HBUcIgU8epEKOXwiahOO+KZYjiXlWyQ== + dependencies: + "@types/json5" "^0.0.29" + deepmerge "^2.0.1" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" +tsutils@^3.7.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.10.0.tgz#6f1c95c94606e098592b0dff06590cf9659227d6" + integrity sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" @@ -7850,6 +8814,11 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript@^3.4.5: + version "3.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" + integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== + ua-parser-js@^0.7.18: version "0.7.19" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b" @@ -7862,10 +8831,11 @@ uglify-es@^3.1.9: source-map "~0.6.1" uglify-js@^3.1.4: - version "3.4.9" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + version "3.5.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.3.tgz#d490bb5347f23025f0c1bc0dee901d98e4d6b063" + integrity sha512-rIQPT2UMDnk4jRX+w4WO84/pebU2jiLsjgIyrCktYgSvx28enOE3iYQMr+BD1rHiitWnDmpu0cY/LfIEpKcjcw== dependencies: - commander "~2.17.1" + commander "~2.19.0" source-map "~0.6.1" uid-number@0.0.6: @@ -7904,6 +8874,7 @@ unicode-property-aliases-ecmascript@^1.0.4: union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -7924,6 +8895,13 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +universal-user-agent@^2.0.0, universal-user-agent@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.3.tgz#9f6f09f9cc33de867bb720d84c08069b14937c6c" + integrity sha512-eRHEHhChCBHrZsA4WEhdgiOKgdvgrMIHwnwnqD0r5C6AO8kwKcG7qSku3iXdhvHL3YvsS9ZkSGN8h/hIpoFC8g== + dependencies: + os-name "^3.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -7936,10 +8914,26 @@ unpipe@~1.0.0: unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" +unzipper@^0.8.11: + version "0.8.14" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.8.14.tgz#ade0524cd2fc14d11b8de258be22f9d247d3f79b" + integrity sha512-8rFtE7EP5ssOwGpN2dt1Q4njl0N1hUXJ7sSPz0leU2hRdq6+pra57z4YPBlVqm40vcgv6ooKZEAx48fMTv9x4w== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "~1.0.10" + listenercount "~1.0.1" + readable-stream "~2.1.5" + setimmediate "~1.0.4" + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -7949,18 +8943,39 @@ uri-js@^4.2.2: urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util.promisify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== dependencies: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" @@ -8005,6 +9020,7 @@ vary@~1.1.2: verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -8013,23 +9029,18 @@ verror@1.10.0: w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= dependencies: browser-process-hrtime "^0.1.2" -walker@~1.0.5: +walker@^1.0.7, walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" -watch@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - -wcwidth@^1.0.0: +wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= @@ -8039,10 +9050,12 @@ wcwidth@^1.0.0: webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" @@ -8051,12 +9064,14 @@ whatwg-fetch@>=0.10.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz#a3d58ef10b76009b042d03e25591ece89b88d171" + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== whatwg-url@^6.4.1: version "6.5.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== dependencies: lodash.sortby "^4.7.0" tr46 "^1.0.1" @@ -8065,16 +9080,23 @@ whatwg-url@^6.4.1: whatwg-url@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" + integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== dependencies: lodash.sortby "^4.7.0" tr46 "^1.0.1" webidl-conversions "^4.0.2" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1, which@^1.2.12, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: @@ -8086,6 +9108,18 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= + +windows-release@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.1.0.tgz#8d4a7e266cbf5a233f6c717dac19ce00af36e12e" + integrity sha512-hBb7m7acFgQPQc222uEQTmdcGLeBmQLNLFIh0rDk3CwFOBrfjefLzEfEfmpMq8Af/n/GnFf3eYf203FY1PmudA== + dependencies: + execa "^0.10.0" + winston@0.8.x: version "0.8.3" resolved "http://registry.npmjs.org/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" @@ -8105,10 +9139,12 @@ wordwrap@^1.0.0, wordwrap@~1.0.0: wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wrap-ansi@^2.0.0: version "2.1.0" - resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -8116,6 +9152,16 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" + integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" write-file-atomic@^1.2.0: version "1.3.4" @@ -8133,15 +9179,6 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.3.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" - integrity sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - write-json-file@^2.2.0, write-json-file@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.3.0.tgz#2b64c8a33004d54b8698c76d585a77ceb61da32f" @@ -8178,6 +9215,7 @@ ws@^1.1.0, ws@^1.1.5: ws@^5.2.0: version "5.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== dependencies: async-limiter "~1.0.0" @@ -8192,6 +9230,7 @@ xcode@^2.0.0: xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== xmlbuilder@^9.0.7: version "9.0.7" @@ -8211,10 +9250,6 @@ xpipe@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" -xregexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" - xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -8235,12 +9270,6 @@ yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" -yargs-parser@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - dependencies: - camelcase "^4.1.0" - yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" @@ -8249,13 +9278,21 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + integrity sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" dependencies: camelcase "^4.1.0" -yargs@^12.0.1: +yargs@^12.0.1, yargs@^12.0.2, yargs@^12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== @@ -8273,22 +9310,25 @@ yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" -yargs@^12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" +yargs@^4.2.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + integrity sha1-wMQpJMpKqmsObaFznfshZDn53cA= dependencies: - cliui "^4.0.0" - decamelize "^2.0.0" - find-up "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" get-caller-file "^1.0.1" - os-locale "^3.0.0" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^10.1.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" yargs@^9.0.0: version "9.0.1"