├── .babelrc ├── .editorconfig ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierrc ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SUMMARY.md ├── bin └── flow-mono ├── docs ├── README.md ├── cli │ ├── README.md │ ├── align-versions.md │ ├── create-stubs.md │ ├── create-symlinks.md │ └── install-types.md └── introduction │ ├── Configuration.md │ ├── MonoRepoStructure.md │ ├── Motivation.md │ └── README.md ├── examples ├── .flowconfig ├── .gitignore ├── .yarnrc ├── README.md ├── build │ └── .flowconfig ├── package.json ├── packages │ ├── package-1 │ │ ├── index.js │ │ └── package.json │ ├── package-2 │ │ ├── index.js │ │ └── package.json │ └── package-3 │ │ ├── index.js │ │ └── package.json ├── run.sh └── yarn.lock ├── package.json ├── renovate.json ├── src ├── commands │ ├── __snapshots__ │ │ ├── align-versions.spec.js.snap │ │ ├── create-stubs.spec.js.snap │ │ ├── create-symlinks.spec.js.snap │ │ └── install-types.spec.js.snap │ ├── align-versions.js │ ├── align-versions.spec.js │ ├── create-stubs.js │ ├── create-stubs.spec.js │ ├── create-symlinks.js │ ├── create-symlinks.spec.js │ ├── install-types.js │ └── install-types.spec.js └── lib │ ├── __snapshots__ │ ├── config.spec.js.snap │ └── dependency.spec.js.snap │ ├── async.js │ ├── async.spec.js │ ├── config.js │ ├── config.spec.js │ ├── dependency.js │ ├── dependency.spec.js │ ├── exec.js │ ├── exec.spec.js │ ├── file.js │ ├── file.spec.js │ ├── flowTyped.js │ ├── flowTyped.spec.js │ ├── logger.js │ ├── logger.spec.js │ ├── paths.js │ ├── paths.spec.js │ ├── updateVersion.js │ └── updateVersion.spec.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-flow" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 120 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | [COMMIT_EDITMSG] 18 | max_line_length = 0 19 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@immowelt/eslint-config-immowelt-base", 3 | "rules": { 4 | "compat/compat": 0, 5 | "no-await-in-loop": 0, 6 | "no-continue": 0, 7 | "no-console": 0, 8 | "no-restricted-syntax": 0 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | # 2 | # By default we ignore all `node_modules`, except for modules which ship typings, since this increases the startup time of Flow drastically 3 | # @see https://github.com/facebook/flow/issues/869 4 | # 5 | [ignore] 6 | .*\/node_modules\/(?!(@immowelt|log-fancy|find-config-up)\/).* 7 | .*\/node_modules/npmconf/.* 8 | .*\/node_modules/config-chain/.* 9 | .*/examples/.* 10 | .*.spec.js 11 | 12 | [include] 13 | 14 | [libs] 15 | 16 | [options] 17 | suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe 18 | 19 | # 20 | # Supress errors in case we require() something based on a variable (E.g. used in the getComponent function of hypernova). 21 | # 22 | module.ignore_non_literal_requires=true 23 | 24 | [lints] 25 | # all=off by default 26 | all=warn 27 | untyped-type-import=error 28 | sketchy-null-bool=off 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules/ 5 | 6 | # third party typings 7 | /flow-typed/ 8 | 9 | # compiled assets 10 | /dist/ 11 | 12 | # test results 13 | /coverage/ 14 | 15 | # IDEs 16 | /.idea/ 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # third party typings 5 | flow-typed/npm 6 | 7 | # test results 8 | coverage 9 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.22.1 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "bracketSpacing": false, 4 | "singleQuote": true, 5 | "semi": true, 6 | "overrides": [{ 7 | "files": "*.js", 8 | "options": { 9 | "parser": "flow" 10 | } 11 | }] 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "12.13.1" 5 | notifications: 6 | email: false 7 | before_install: 8 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.19.2 9 | - export PATH="$HOME/.yarn/bin:$PATH" 10 | install: 11 | - yarn 12 | script: 13 | - yarn lint 14 | - yarn test --coverage 15 | - yarn build 16 | - yarn integTest 17 | after_success: 18 | - yarn release 19 | branches: 20 | except: 21 | - /^v\d+\.\d+\.\d+$/ 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We are open and grateful for any contributions made by you! 4 | 5 | ## Reporting issues 6 | 7 | Before opening an issue, please make sure that your issue hasn't been already reported by using the search functionality of the [issue tracker](https://github.com/ImmoweltGroup/flow-mono-cli/issues). 8 | 9 | ## Development 10 | 11 | Visit the [issue tracker](https://github.com/ImmoweltGroup/flow-mono-cli/issues) to find a list of open issues that are easy to pick up or need some love. 12 | 13 | ### New features 14 | 15 | Please open an issue with a proposal for a new feature or refactoring before starting on the work. We don't want you to waste your efforts on a pull request that we won't want to accept. 16 | 17 | ## Commit guideline 18 | 19 | Our repositories make great use of [semantic-release](https://github.com/semantic-release/semantic-release). This tool automatically creates releases once the code is pushed to our `master` branch and the commits signal a release-worthy CI run. 20 | 21 | All commits must contain a prefix of one of the following values, e.g. 22 | 23 | | Prefix | Description | Release type | 24 | | ------------- | --------------- | ------------- | 25 | | `BREAKING` | Breaking change | Major | 26 | | `FEATURE` | Feature | Minor | 27 | | `BUGFIX` | Bugfix | Patch | 28 | | `SECURITY` | Dependencies | Patch | 29 | 30 | ## Submitting Changes 31 | 32 | * Open a new issue in the [issue tracker](https://github.com/ImmoweltGroup/flow-mono-cli/issues). 33 | * Fork the repo. 34 | * Create a new feature branch based off the `master` branch. 35 | * Make sure all tests pass and there are no linting errors. 36 | * Make sure to commit your changes with the guidelines written above. 37 | * Submit a pull request, referencing any issues it addresses. 38 | 39 | Please try to keep your pull request focused in scope and avoid including unrelated commits. 40 | 41 | After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements. 42 | 43 | Thank you for contributing! :-) :heart: 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Immowelt Hamburg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | flow-mono-cli 2 | 3 | # flow-mono-cli 4 | 5 | [![Powered by Immowelt](https://img.shields.io/badge/powered%20by-immowelt-yellow.svg?colorB=ffb200)](https://stackshare.io/immowelt-group/) 6 | [![Build Status](https://travis-ci.org/ImmoweltGroup/flow-mono-cli.svg?branch=master)](https://travis-ci.org/ImmoweltGroup/flow-mono-cli) 7 | [![Dependency Status](https://david-dm.org/ImmoweltGroup/flow-mono-cli.svg)](https://david-dm.org/ImmoweltGroup/flow-mono-cli) 8 | [![devDependency Status](https://david-dm.org/ImmoweltGroup/flow-mono-cli/dev-status.svg)](https://david-dm.org/ImmoweltGroup/flow-mono-cli#info=devDependencies&view=table) 9 | [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovateapp.com/) 10 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 11 | 12 | `flow-mono-cli` is a command line interface that aims to [solve](https://github.com/facebook/flow/issues/4738) [a](https://github.com/facebook/flow/issues/5107) [few](https://github.com/flowtype/flow-typed/issues/1391) [issues](https://github.com/lerna/lerna/issues/891) [while](https://github.com/facebook/flow/issues/869) working with flow typed codebases in a mono-repo. 13 | 14 | It provides a set of commands that we found to be very useful *if you want your mono-repo packages to have their own flow instances*. We do not intend to replace existing packages and furthermore we find it to be of importance that these issues are getting fixed at their respective packages but in the meantime a separate CLI was the fastest and best option we found. 15 | 16 | ## Features 17 | 18 | * Creates symlinks for flow to be able to resolve dependencies which were installed/hoisted into the root `node_modules` of your mono-repo into each packages `node_modules`. 19 | * Smart resolve mechanism of mono-repo packages with a dependency to `flow-bin`, based on the `workspaces` config in your root `package.json`. 20 | * Keeps your `flow-bin` and `flow-typed` versions in sync across your mono-repo packages. 21 | * Maintains a single or fallback `.flowconfig` across all packages. 22 | * Creates flow-typed stubs for in-direct dependencies (dependencies of dependencies). 23 | * Configurable via a `.flowmonorc` or `flow-mono` property in your mono-repo's root `package.json`. 24 | 25 | ## Installation 26 | ```sh 27 | $ npm install flow-mono-cli --save-dev 28 | ``` 29 | 30 | or 31 | 32 | ```sh 33 | $ yarn add flow-mono-cli --dev 34 | ``` 35 | 36 | afterwards make sure that you've got your workspaces configured in the root `package.json`, e.g. 37 | 38 | ```json 39 | { 40 | "workspaces": [ 41 | "packages/*" 42 | ] 43 | } 44 | ``` 45 | 46 | ## Commands and Documentation 47 | 48 | * [Introduction](/docs/introduction/README.md) 49 | * [`flow-mono create-symlinks`](/docs/cli/create-symlinks.md) 50 | * [`flow-mono install-types`](/docs/cli/install-types.md) 51 | * [`flow-mono create-stubs`](/docs/cli/create-stubs.md) 52 | * [`flow-mono align-versions`](/docs/cli/align-versions.md) 53 | 54 | ## Contributing 55 | See the `CONTRIBUTING.md` file at the root of the repository. 56 | 57 | ## Licensing 58 | See the `LICENSE` file at the root of the repository. 59 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [README](README.md) 4 | * [1. Introduction](docs/introduction/README.md) 5 | * [1.1 Motivation](docs/introduction/Motivation.md) 6 | * [1.2 Mono-Repo Structure](docs/introduction/MonoRepoStructure.md) 7 | * [1.3 CLI Configuration](docs/introduction/Configuration.md) 8 | * [2. CLI](docs/cli/README.md) 9 | * [2.1 create-symlinks](docs/cli/create-symlinks.md) 10 | * [2.2 install-types](docs/cli/install-types.md) 11 | * [2.3 create-stubs](docs/cli/create-stubs.md) 12 | * [2.4 align-versions](docs/cli/align-versions.md) 13 | -------------------------------------------------------------------------------- /bin/flow-mono: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const asyncUtils = require('./../dist/lib/async.js'); 4 | const alignFlowVersions = require('./../dist/commands/align-versions.js'); 5 | const createDependencyFlowTypeStubs = require('./../dist/commands/create-stubs.js'); 6 | const createFlowTypeSymlinks = require('./../dist/commands/create-symlinks.js'); 7 | const installFlowTypes = require('./../dist/commands/install-types.js'); 8 | 9 | const _ = require('yargs') 10 | // Always English 11 | .detectLocale(false) 12 | .usage('$0 [args]', 'A command line interface that aims to solve a few issues while working with flow typed codebases in a mono-repo') 13 | .command('align-versions', 'Aligns all versions of `flow-bin` and `flow-typed` to the version specified in the mono-repo `package.json`', () => {}, () => { 14 | asyncUtils.exec(alignFlowVersions); 15 | }) 16 | .command('create-stubs', 'Creates stubs for nested dependencies to avoid the all to common `Required module not found` error', yargs => { 17 | yargs.option('use-root', { 18 | alias: 'u', 19 | type: 'boolean', 20 | default: false, 21 | describe: 'If passed the stubs will be created in the root of the mono-repository' 22 | }) 23 | }, argv => { 24 | asyncUtils.exec(createDependencyFlowTypeStubs, { 25 | useRoot: argv.useRoot 26 | }); 27 | }) 28 | .command('create-symlinks [path]', 'Creates symlinks for all mono-repo package dependencies and the `.flowconfig` if a path was provided', yargs => { 29 | yargs.positional('path', { 30 | type: 'string', 31 | describe: 'The relative path to the `.flowconfig` for which symlinks will be created in all packages with a `flow-bin` dependency' 32 | }) 33 | yargs.option('relative', { 34 | alias: 'r', 35 | type: 'boolean', 36 | default: false, 37 | describe: 'If passed the symlinks will be relative paths instead of absolute' 38 | }) 39 | }, argv => { 40 | asyncUtils.exec(createFlowTypeSymlinks, { 41 | flowConfigPath: argv.path, 42 | relative: argv.relative 43 | }); 44 | }) 45 | .command('install-types', 'Installs flow-typed typings for all mono-repo package dependencies', () => {}, () => { 46 | asyncUtils.exec(installFlowTypes); 47 | }) 48 | .help() 49 | .argv; 50 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [README](/README.md) 4 | * [Introduction](/docs/introduction/README.md) 5 | * [Motivation](/docs/introduction/Motivation.md) 6 | * [CLI Reference](/docs/cli/README.md) 7 | * [`flow-mono create-symlinks`](/docs/cli/create-symlinks.md) 8 | * [`flow-mono install-types`](/docs/cli/install-types.md) 9 | * [`flow-mono create-stubs`](/docs/cli/create-stubs.md) 10 | * [`flow-mono align-versions`](/docs/cli/align-versions.md) 11 | -------------------------------------------------------------------------------- /docs/cli/README.md: -------------------------------------------------------------------------------- 1 | # CLI Reference 2 | 3 | This CLI is built as a set of separate and independent commands, see each file for detailed informations regarding options, configurations and examples. 4 | 5 | ### Commands 6 | 7 | * [`$ flow-mono create-symlinks`](create-symlinks.md) 8 | * [`$ flow-mono install-types`](install-types.md) 9 | * [`$ flow-mono create-stubs`](create-stubs.md) 10 | * [`$ flow-mono align-versions`](align-versions.md) 11 | 12 | ### Execution 13 | 14 | ```sh 15 | $ flow-mono [command] [...options] 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/cli/align-versions.md: -------------------------------------------------------------------------------- 1 | # `flow-mono align-versions` 2 | 3 | Compares all mono-repo packages with a dependency to `flow-bin` or `flow-typed` and prompts a automatic update that you can accept or decline on a per-dependency and package basis. 4 | 5 | #### Features 6 | 7 | * Makes maintaining the same `flow-bin` and `flow-typed` version across your mono-repo packages a bit easier. 8 | 9 | #### Example 10 | 11 | ```sh 12 | $ flow-mono align-versions 13 | ``` 14 | 15 | #### Options and Arguments 16 | 17 | _This command does not have any arguments or options as of now_ 18 | 19 | #### Configuration 20 | 21 | _This command does not support configuration as of now_ 22 | -------------------------------------------------------------------------------- /docs/cli/create-stubs.md: -------------------------------------------------------------------------------- 1 | # `flow-mono create-stubs` 2 | 3 | Creates stubs for so called "in-direct" dependencies, this is useful if a package provides it's own typings out of the box and you don't want to suppress any errors from in-direct dependencies or even `Required module not found` errors. 4 | 5 | #### Features 6 | 7 | * Resolves packages of your mono-repo that have a dependency to `flow-typed` as well as a dependency to one of the whitelisted packages in your configuration. 8 | * Resolves the in-direct dependencies of the iterated dependency and creates stubs for them. 9 | 10 | #### Example 11 | 12 | ```sh 13 | $ flow-mono create-stubs 14 | ``` 15 | 16 | #### Options and Arguments 17 | 18 | ##### `-u, --use-root` \(Optional\) 19 | 20 | Installs all stubs in the root of your mono-repo. 21 | 22 | #### Configuration 23 | 24 | By default this command will not do anything since automatically stubbing all 2nd level dependencies is to error prone. Instead you need to whitelist the dependencies for which we should create stubs of it's in-direct dependencies. To do so just create a `.flowmonorc` or a `flow-mono` section in your repositories root `package.json`, paste in the example and adjust as you like! 25 | 26 | ```json 27 | { 28 | "create-stubs": { 29 | "dependencies": ["immutable-js"] 30 | } 31 | } 32 | ``` 33 | 34 | This will resolve all mono-repo packages that have `immutable-js` as a dependency, resolve `immutable-js` own dependencies and create stubs for them. 35 | 36 | This command also respects the `flowTypedCommandExecRetries` configuration option, which might be useful if you encounter problems due to network errors while flow-typed is running, .e.g. 37 | 38 | ```json 39 | { 40 | "flowTypedCommandExecRetries": 3 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/cli/create-symlinks.md: -------------------------------------------------------------------------------- 1 | # `flow-mono create-symlinks [flowconfig-path]` 2 | 3 | Ever had errors like `Required module not found` for dependencies which where located in the root `node_modules` of your mono-repo? Ever wanted to maintain a fallback or even a singleton `.flowconfig` in your mono-repo? This command is your new best friend! 4 | 5 | #### Features 6 | 7 | * Resolves packages of your mono-repo that have a dependency to `flow-bin`. 8 | * Creates symlinks for all dependencies into the root `node_modules` of your mono-repo. 9 | * Creates symlinks to the provided `.flowconfig` path if a package does not hold it's own `.flowconfig` file. 10 | 11 | #### Example 12 | 13 | ```sh 14 | $ flow-mono create-symlinks ./build/.flowconfig 15 | ``` 16 | 17 | #### Options and Arguments 18 | 19 | ##### `[flowconfig-path]` 20 | 21 | The relative path to the fallback / singleton `.flowconfig`. 22 | 23 | ##### `-r, --relative` \(Optional\) 24 | 25 | Create relative symlinks (e.g. ../../../build/.flowconfig) instead of absolute symlinks (e.g. /path/to/build/.flowconfig) 26 | 27 | #### Configuration 28 | 29 | Additionally you can specify a blacklist of packages that should be ignored entirely from being symlinked. To do so just create a `.flowmonorc` or a `flow-mono` section in your repositories root `package.json`, paste in the example and adjust as you like! 30 | 31 | ```json 32 | { 33 | "create-symlinks": { 34 | "ignore": ["eslint", "jest"] 35 | } 36 | } 37 | ``` 38 | 39 | This will ignore all dependencies that include either `jest` or `eslint` in their package names. 40 | -------------------------------------------------------------------------------- /docs/cli/install-types.md: -------------------------------------------------------------------------------- 1 | # `flow-mono install-types [...flow-typed install options]` 2 | 3 | Updates your local `flow-typed` cache and does a parallel `flow-typed install` in all of your packages. 4 | 5 | #### Features 6 | 7 | * Resolves packages of your mono-repo that have a dependency to `flow-typed`. 8 | * Updates your `flow-typed` cache. 9 | * Installs typings from the `flow-typed` repository into your mono-repo packages. 10 | * Supports argument propagation to the `flow-typed install` commands. 11 | 12 | #### Example 13 | 14 | ```sh 15 | $ flow-mono install-types --ignoreDeps=peer --overwrite 16 | ``` 17 | 18 | #### Options and Arguments 19 | 20 | All given options are being propagated to each `flow-typed intall` child process in the packages. 21 | 22 | #### Configuration 23 | 24 | This command respects the `flowTypedCommandExecRetries` configuration option, which might be useful if you encounter problems due to network errors while flow-typed is running, .e.g. 25 | 26 | ```json 27 | { 28 | "flowTypedCommandExecRetries": 3 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/introduction/Configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | Most commands of this CLI can be configured by either adding a `.flowmonorc` file into the root of your mono-repository, or by adding a `flow-mono` property into the root `package.json`. 4 | 5 | #### Example configuration via `.flowmonorc` 6 | ```json 7 | { 8 | "create-symlinks": { 9 | "ignore": ["eslint", "jest"] 10 | } 11 | } 12 | ``` 13 | 14 | #### Example configuration via `package.json` 15 | ```json 16 | { 17 | "name": "my-mono-repo", 18 | "workspaces": ["packages/*"], 19 | 20 | "flow-mono": { 21 | "create-symlinks": { 22 | "ignore": ["eslint", "jest"] 23 | } 24 | } 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/introduction/MonoRepoStructure.md: -------------------------------------------------------------------------------- 1 | # Mono-Repository Structure 2 | 3 | The CLI does almost no assumptions about the structure of your mono-repo, it uses `yarn`'s workspace configuration in your root `package.json` so you can place your packages where ever you want them to be. 4 | 5 | In case you already use `yarn` workspaces, you can skip this part, otherwise just add this property to your root `package.json` and you are good to go. 6 | 7 | ```json 8 | { 9 | "workspaces": ["packages/*"] 10 | } 11 | ``` 12 | 13 | We strongly recommend having a flow instance per package, since this decreases startup time due to multi-threading. Another benefit is that it reduces the coupling of the packages to your mono-repository and the effort once you want to extract a package from your mono-repository. But don't worry, this CLI will provide you with a couple of commands to help you maintain all the single instances more easily. 14 | 15 | This is how an example mono-repository could look like 16 | ``` 17 | . 18 | ├── build 19 | | └── .flowconfig // A fallback / default / singleton `.flowconfig` that will be symlinked (for all packages that do not hold their own `.flowconfig`). 20 | ├── flow-typed // Patched typings or global stubs. 21 | ├── node_modules // Hoisted or root dependencies of the mono-repository. 22 | ├── packages 23 | | ├── package-a 24 | | | ├── flow-typed // Flow-typed stubs / typings for this package. 25 | | | ├── node_modules // dependencies of this package. 26 | | | ├── package.json // If the package has a dependency to `flow-bin` it will be recognized by the CLI. 27 | | | └── .flowconfig // Packages could also hold it's own `.flowconfig` if necessary. 28 | | └── package-b 29 | | | ├── flow-typed 30 | | | ├── node_modules 31 | | | └── package.json 32 | ├── .flowmonorc // Configuration of the CLI. 33 | └── package.json // The `flow-mono-cli` would need to be added to the `devDependencies` in the root `package.json` 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/introduction/Motivation.md: -------------------------------------------------------------------------------- 1 | # Motivation 2 | 3 | As of now maintaining a mono-repository with flow is hard, there are a few issues within flow itself that you will stumble upon when adding flow to your mono-repository such as the all to common `Required module not found` error which pops up when using Lernas `--hoist` or even yarn workspaces feature. 4 | 5 | Here is a list of issues that we try to solve, if you find yourself in one of these, you may want to try out this CLI and see if it helps to solve your problems. 6 | 7 | * [Having nested .flowconfig files in different folders](https://github.com/facebook/flow/issues/4738) 8 | * [Finding types from external dependencies when using Yarn workspaces](https://github.com/facebook/flow/issues/5107) 9 | * [Don't typecheck or load files under node_modules/ unless they're imported by flow-typed files](https://github.com/facebook/flow/issues/869) 10 | * [How to apply flow type checking in lerna managed project?](https://github.com/lerna/lerna/issues/891) 11 | 12 | We do not intend to replace existing packages and furthermore we find it to be of importance that these issues are getting fixed at their respective packages but in the meantime a separate CLI was the fastest and best option we found. This CLI does only target mono-repository specific problems and we might introduce more commands in the future which are not only bug/issue related, but more developer-experience oriented! :-) 13 | -------------------------------------------------------------------------------- /docs/introduction/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | * [Motivation](Motivation.md) 4 | * [Mono-Repo Structure](MonoRepoStructure.md) 5 | * [Configuration](Configuration.md) 6 | -------------------------------------------------------------------------------- /examples/.flowconfig: -------------------------------------------------------------------------------- 1 | # Intermediate .flowconfig file created by `flow-mono-cli -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | packages/*/.flowconfig 6 | 7 | # third party typings 8 | flow-typed/npm 9 | packages/*/flow-typed/npm 10 | -------------------------------------------------------------------------------- /examples/.yarnrc: -------------------------------------------------------------------------------- 1 | workspaces-experimental true 2 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Example / Integration test suite for the CLI 2 | 3 | This folder holds an example setup of a yarn workspace with multiple packages that have dependencies between each other, as well as a dependency to `log-fancy` which in-direct dependencies need to be stubbed to work correctly. 4 | -------------------------------------------------------------------------------- /examples/build/.flowconfig: -------------------------------------------------------------------------------- 1 | # 2 | # This file will be symlinked into all packages of the mono-repo, 3 | # therefore are paths like `./../../` just a reference to the root of the mono-repo. 4 | # 5 | # By default we ignore all `node_modules`, except for modules which ship typings. 6 | # This ignore pattern increases the startup time of Flow drastically. 7 | # 8 | # @see https://github.com/facebook/flow/issues/869 9 | # 10 | [ignore] 11 | .*\/node_modules\/(?!(@immowelt|log-fancy)\/).* 12 | 13 | [include] 14 | 15 | [libs] 16 | # 17 | # Include patched typings or stubs from the root of the mono-repo. 18 | # 19 | ./../../flow-typed/npm 20 | 21 | [options] 22 | module.ignore_non_literal_requires=true 23 | 24 | [lints] 25 | all=warn 26 | untyped-type-import=error 27 | sketchy-null-bool=off 28 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flow-mono-cli-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "bootstrap": "yarn create-symlinks && yarn install-types && yarn create-stubs", 7 | "create-symlinks": "node ./../bin/flow-mono create-symlinks build/.flowconfig", 8 | "install-types": "node ./../bin/flow-mono install-types --ignoreDeps=peer", 9 | "create-stubs": "node ./../bin/flow-mono create-stubs --use-root", 10 | "test": "yarn flow", 11 | "flow": "wsrun -a --collect-logs flow", 12 | "flow:stop": "wsrun -a --collect-logs 'flow stop'" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "private": true, 18 | "workspaces": [ 19 | "packages/*" 20 | ], 21 | "flow-mono": { 22 | "create-symlinks": { 23 | "ignore": [ 24 | "eslint", 25 | "jest" 26 | ] 27 | }, 28 | "create-stubs": { 29 | "dependencies": [ 30 | "log-fancy" 31 | ] 32 | } 33 | }, 34 | "devDependencies": { 35 | "wsrun": "5.2.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/packages/package-1/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const api = require('flow-mono-cli-example-package-2'); 4 | 5 | api.doSomething(); 6 | -------------------------------------------------------------------------------- /examples/packages/package-1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flow-mono-cli-example-package-1", 3 | "version": "0.0.0-development", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "flow": "flow" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "private": true, 13 | "workspaces": ["packages/*"], 14 | "dependencies": { 15 | "flow-mono-cli-example-package-2": "0.0.0-development" 16 | }, 17 | "devDependencies": { 18 | "flow-bin": "0.117.0", 19 | "flow-typed": "2.6.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/packages/package-2/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const logger = require('flow-mono-cli-example-package-3'); 4 | 5 | module.exports = { 6 | doSomething() { 7 | logger.info('Foo'); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /examples/packages/package-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flow-mono-cli-example-package-2", 3 | "version": "0.0.0-development", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "flow": "flow" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "private": true, 13 | "workspaces": ["packages/*"], 14 | "dependencies": { 15 | "flow-mono-cli-example-package-3": "0.0.0-development" 16 | }, 17 | "devDependencies": { 18 | "flow-bin": "0.117.0", 19 | "flow-typed": "2.6.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/packages/package-3/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // 4 | // The package `log-fancy` gets served with it's own typings. 5 | // 6 | // The typings also include references to other packages, which we create stubs for since we don't want symlinks for 7 | // in-direct dependencies on a per package basis. 8 | // 9 | const createLogger = require('log-fancy'); 10 | const logger = createLogger('@immowelt/search-ui'); 11 | 12 | module.exports = logger; 13 | -------------------------------------------------------------------------------- /examples/packages/package-3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flow-mono-cli-example-package-3", 3 | "version": "0.0.0-development", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "flow": "flow" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "private": true, 13 | "workspaces": ["packages/*"], 14 | "dependencies": { 15 | "log-fancy": "1.3.2" 16 | }, 17 | "devDependencies": { 18 | "flow-bin": "0.117.0", 19 | "flow-typed": "2.6.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # break on all failures 3 | set -e 4 | 5 | cd examples 6 | 7 | ## install dependencies and run flow commands 8 | yarn 9 | yarn bootstrap 10 | yarn flow 11 | 12 | cd - 13 | -------------------------------------------------------------------------------- /examples/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.5.5" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" 8 | integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== 9 | dependencies: 10 | "@babel/highlight" "^7.0.0" 11 | 12 | "@babel/highlight@^7.0.0": 13 | version "7.5.0" 14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" 15 | integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== 16 | dependencies: 17 | chalk "^2.0.0" 18 | esutils "^2.0.2" 19 | js-tokens "^4.0.0" 20 | 21 | "@babel/polyfill@^7.0.0": 22 | version "7.7.0" 23 | resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.7.0.tgz#e1066e251e17606ec7908b05617f9b7f8180d8f3" 24 | integrity sha512-/TS23MVvo34dFmf8mwCisCbWGrfhbiWZSwBo6HkADTBhUa2Q/jWltyY/tpofz/b6/RIhqaqQcquptCirqIhOaQ== 25 | dependencies: 26 | core-js "^2.6.5" 27 | regenerator-runtime "^0.13.2" 28 | 29 | "@jest/types@^24.9.0": 30 | version "24.9.0" 31 | resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" 32 | integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== 33 | dependencies: 34 | "@types/istanbul-lib-coverage" "^2.0.0" 35 | "@types/istanbul-reports" "^1.1.1" 36 | "@types/yargs" "^13.0.0" 37 | 38 | "@octokit/endpoint@^5.5.0": 39 | version "5.5.1" 40 | resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.1.tgz#2eea81e110ca754ff2de11c79154ccab4ae16b3f" 41 | integrity sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg== 42 | dependencies: 43 | "@octokit/types" "^2.0.0" 44 | is-plain-object "^3.0.0" 45 | universal-user-agent "^4.0.0" 46 | 47 | "@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": 48 | version "1.2.0" 49 | resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.0.tgz#a64d2a9d7a13555570cd79722de4a4d76371baaa" 50 | integrity sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg== 51 | dependencies: 52 | "@octokit/types" "^2.0.0" 53 | deprecation "^2.0.0" 54 | once "^1.4.0" 55 | 56 | "@octokit/request@^5.2.0": 57 | version "5.3.1" 58 | resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.1.tgz#3a1ace45e6f88b1be4749c5da963b3a3b4a2f120" 59 | integrity sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg== 60 | dependencies: 61 | "@octokit/endpoint" "^5.5.0" 62 | "@octokit/request-error" "^1.0.1" 63 | "@octokit/types" "^2.0.0" 64 | deprecation "^2.0.0" 65 | is-plain-object "^3.0.0" 66 | node-fetch "^2.3.0" 67 | once "^1.4.0" 68 | universal-user-agent "^4.0.0" 69 | 70 | "@octokit/rest@^16.33.1": 71 | version "16.35.0" 72 | resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.35.0.tgz#7ccc1f802f407d5b8eb21768c6deca44e7b4c0d8" 73 | integrity sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w== 74 | dependencies: 75 | "@octokit/request" "^5.2.0" 76 | "@octokit/request-error" "^1.0.2" 77 | atob-lite "^2.0.0" 78 | before-after-hook "^2.0.0" 79 | btoa-lite "^1.0.0" 80 | deprecation "^2.0.0" 81 | lodash.get "^4.4.2" 82 | lodash.set "^4.3.2" 83 | lodash.uniq "^4.5.0" 84 | octokit-pagination-methods "^1.1.0" 85 | once "^1.4.0" 86 | universal-user-agent "^4.0.0" 87 | 88 | "@octokit/types@^2.0.0": 89 | version "2.0.2" 90 | resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.0.2.tgz#0888497f5a664e28b0449731d5e88e19b2a74f90" 91 | integrity sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ== 92 | dependencies: 93 | "@types/node" ">= 8" 94 | 95 | "@sindresorhus/is@^0.7.0": 96 | version "0.7.0" 97 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" 98 | integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== 99 | 100 | "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": 101 | version "2.0.1" 102 | resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" 103 | integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== 104 | 105 | "@types/istanbul-lib-report@*": 106 | version "1.1.1" 107 | resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c" 108 | integrity sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg== 109 | dependencies: 110 | "@types/istanbul-lib-coverage" "*" 111 | 112 | "@types/istanbul-reports@^1.1.1": 113 | version "1.1.1" 114 | resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" 115 | integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== 116 | dependencies: 117 | "@types/istanbul-lib-coverage" "*" 118 | "@types/istanbul-lib-report" "*" 119 | 120 | "@types/node@>= 8": 121 | version "12.12.14" 122 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2" 123 | integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA== 124 | 125 | "@types/yargs-parser@*": 126 | version "13.1.0" 127 | resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" 128 | integrity sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg== 129 | 130 | "@types/yargs@^13.0.0": 131 | version "13.0.3" 132 | resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.3.tgz#76482af3981d4412d65371a318f992d33464a380" 133 | integrity sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ== 134 | dependencies: 135 | "@types/yargs-parser" "*" 136 | 137 | ajv@^6.10.2: 138 | version "6.10.2" 139 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" 140 | integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== 141 | dependencies: 142 | fast-deep-equal "^2.0.1" 143 | fast-json-stable-stringify "^2.0.0" 144 | json-schema-traverse "^0.4.1" 145 | uri-js "^4.2.2" 146 | 147 | ansi-regex@^2.0.0: 148 | version "2.1.1" 149 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 150 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 151 | 152 | ansi-regex@^3.0.0: 153 | version "3.0.0" 154 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 155 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 156 | 157 | ansi-regex@^4.1.0: 158 | version "4.1.0" 159 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 160 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 161 | 162 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 163 | version "3.2.1" 164 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 165 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 166 | dependencies: 167 | color-convert "^1.9.0" 168 | 169 | astral-regex@^1.0.0: 170 | version "1.0.0" 171 | resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" 172 | integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== 173 | 174 | atob-lite@^2.0.0: 175 | version "2.0.0" 176 | resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" 177 | integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= 178 | 179 | balanced-match@^1.0.0: 180 | version "1.0.0" 181 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 182 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 183 | 184 | before-after-hook@^2.0.0: 185 | version "2.1.0" 186 | resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" 187 | integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== 188 | 189 | big-integer@^1.6.17: 190 | version "1.6.48" 191 | resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" 192 | integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== 193 | 194 | binary@~0.3.0: 195 | version "0.3.0" 196 | resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" 197 | integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= 198 | dependencies: 199 | buffers "~0.1.1" 200 | chainsaw "~0.1.0" 201 | 202 | bluebird@^3.5.1: 203 | version "3.7.2" 204 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" 205 | integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== 206 | 207 | bluebird@~3.4.1: 208 | version "3.4.7" 209 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" 210 | integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= 211 | 212 | brace-expansion@^1.1.7: 213 | version "1.1.11" 214 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 215 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 216 | dependencies: 217 | balanced-match "^1.0.0" 218 | concat-map "0.0.1" 219 | 220 | btoa-lite@^1.0.0: 221 | version "1.0.0" 222 | resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" 223 | integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= 224 | 225 | buffer-indexof-polyfill@~1.0.0: 226 | version "1.0.1" 227 | resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz#a9fb806ce8145d5428510ce72f278bb363a638bf" 228 | integrity sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8= 229 | 230 | buffers@~0.1.1: 231 | version "0.1.1" 232 | resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" 233 | integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= 234 | 235 | cacheable-request@^2.1.1: 236 | version "2.1.4" 237 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" 238 | integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= 239 | dependencies: 240 | clone-response "1.0.2" 241 | get-stream "3.0.0" 242 | http-cache-semantics "3.8.1" 243 | keyv "3.0.0" 244 | lowercase-keys "1.0.0" 245 | normalize-url "2.0.1" 246 | responselike "1.0.2" 247 | 248 | camelcase@^5.0.0: 249 | version "5.3.1" 250 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 251 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 252 | 253 | chainsaw@~0.1.0: 254 | version "0.1.0" 255 | resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" 256 | integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= 257 | dependencies: 258 | traverse ">=0.3.0 <0.4" 259 | 260 | chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0: 261 | version "2.4.2" 262 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 263 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 264 | dependencies: 265 | ansi-styles "^3.2.1" 266 | escape-string-regexp "^1.0.5" 267 | supports-color "^5.3.0" 268 | 269 | charenc@~0.0.1: 270 | version "0.0.2" 271 | resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" 272 | integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= 273 | 274 | cliui@^4.0.0: 275 | version "4.1.0" 276 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" 277 | integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== 278 | dependencies: 279 | string-width "^2.1.1" 280 | strip-ansi "^4.0.0" 281 | wrap-ansi "^2.0.0" 282 | 283 | cliui@^5.0.0: 284 | version "5.0.0" 285 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 286 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 287 | dependencies: 288 | string-width "^3.1.0" 289 | strip-ansi "^5.2.0" 290 | wrap-ansi "^5.1.0" 291 | 292 | clone-response@1.0.2: 293 | version "1.0.2" 294 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 295 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 296 | dependencies: 297 | mimic-response "^1.0.0" 298 | 299 | code-point-at@^1.0.0: 300 | version "1.1.0" 301 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 302 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 303 | 304 | color-convert@^1.9.0: 305 | version "1.9.3" 306 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 307 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 308 | dependencies: 309 | color-name "1.1.3" 310 | 311 | color-name@1.1.3: 312 | version "1.1.3" 313 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 314 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 315 | 316 | colors@^1.3.2: 317 | version "1.4.0" 318 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" 319 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== 320 | 321 | commander@^2.11.0: 322 | version "2.20.3" 323 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 324 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 325 | 326 | concat-map@0.0.1: 327 | version "0.0.1" 328 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 329 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 330 | 331 | core-js@^2.6.5: 332 | version "2.6.10" 333 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" 334 | integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== 335 | 336 | core-util-is@~1.0.0: 337 | version "1.0.2" 338 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 339 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 340 | 341 | cross-spawn@^6.0.0: 342 | version "6.0.5" 343 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 344 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 345 | dependencies: 346 | nice-try "^1.0.4" 347 | path-key "^2.0.1" 348 | semver "^5.5.0" 349 | shebang-command "^1.2.0" 350 | which "^1.2.9" 351 | 352 | crypt@~0.0.1: 353 | version "0.0.2" 354 | resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" 355 | integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= 356 | 357 | debug@^3.0.0: 358 | version "3.2.6" 359 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 360 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 361 | dependencies: 362 | ms "^2.1.1" 363 | 364 | decamelize@^1.2.0: 365 | version "1.2.0" 366 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 367 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 368 | 369 | decode-uri-component@^0.2.0: 370 | version "0.2.0" 371 | resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" 372 | integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= 373 | 374 | decompress-response@^3.3.0: 375 | version "3.3.0" 376 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 377 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= 378 | dependencies: 379 | mimic-response "^1.0.0" 380 | 381 | deprecation@^2.0.0: 382 | version "2.3.1" 383 | resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" 384 | integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== 385 | 386 | duplexer2@~0.1.4: 387 | version "0.1.4" 388 | resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" 389 | integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= 390 | dependencies: 391 | readable-stream "^2.0.2" 392 | 393 | duplexer3@^0.1.4: 394 | version "0.1.4" 395 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 396 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 397 | 398 | emoji-regex@^7.0.1: 399 | version "7.0.3" 400 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 401 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 402 | 403 | end-of-stream@^1.1.0: 404 | version "1.4.4" 405 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 406 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 407 | dependencies: 408 | once "^1.4.0" 409 | 410 | escape-string-regexp@^1.0.5: 411 | version "1.0.5" 412 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 413 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 414 | 415 | esutils@^2.0.2: 416 | version "2.0.3" 417 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 418 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 419 | 420 | execa@^1.0.0: 421 | version "1.0.0" 422 | resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" 423 | integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== 424 | dependencies: 425 | cross-spawn "^6.0.0" 426 | get-stream "^4.0.0" 427 | is-stream "^1.1.0" 428 | npm-run-path "^2.0.0" 429 | p-finally "^1.0.0" 430 | signal-exit "^3.0.0" 431 | strip-eof "^1.0.0" 432 | 433 | fast-deep-equal@^2.0.1: 434 | version "2.0.1" 435 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 436 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 437 | 438 | fast-json-stable-stringify@^2.0.0: 439 | version "2.0.0" 440 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 441 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 442 | 443 | find-up@^3.0.0: 444 | version "3.0.0" 445 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 446 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 447 | dependencies: 448 | locate-path "^3.0.0" 449 | 450 | flow-bin@0.117.0: 451 | version "0.117.0" 452 | resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.117.0.tgz#2fd331f476dac31f7dae6ac9b557581ebc84e8ad" 453 | integrity sha512-LwDdiApyQsO26ubieaLBcW//K8QNcFR50FSUUDo5roy+2nsvkfRdJa0Qse2De6/2fwBElLDDrc3rrSzvC3hy2Q== 454 | 455 | flow-typed@2.6.2: 456 | version "2.6.2" 457 | resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.6.2.tgz#6d324a96c4df300e0f823c13ca879c824bef40ce" 458 | integrity sha512-brTh8SukLidVpR1u8hSR3OcZSvLtptpwLEGgEhK/qBhWCB7zxPZmnmChYi40JQH6vB448ck380+qbkDo3fJ6qA== 459 | dependencies: 460 | "@babel/polyfill" "^7.0.0" 461 | "@octokit/rest" "^16.33.1" 462 | colors "^1.3.2" 463 | flowgen "^1.9.0" 464 | fs-extra "^7.0.0" 465 | glob "^7.1.3" 466 | got "^8.3.2" 467 | md5 "^2.2.1" 468 | mkdirp "^0.5.1" 469 | prettier "^1.18.2" 470 | rimraf "^2.6.2" 471 | semver "^5.5.1" 472 | table "^5.0.2" 473 | through "^2.3.8" 474 | unzipper "^0.9.3" 475 | which "^1.3.1" 476 | yargs "^12.0.2" 477 | 478 | flowgen@^1.9.0: 479 | version "1.10.0" 480 | resolved "https://registry.yarnpkg.com/flowgen/-/flowgen-1.10.0.tgz#a041ae31d543d22166e7ba7c296b8445deb3c2e4" 481 | integrity sha512-3lsoaa1vxGXhnkHuoE4mLPJi/klvpR3ID8R9CFJ/GBNi+cxJXecWQaUPrWMdNI5tGs8Y+7wrIZaCVFKFLQiGOg== 482 | dependencies: 483 | "@babel/code-frame" "^7.0.0" 484 | "@babel/highlight" "^7.0.0" 485 | commander "^2.11.0" 486 | lodash "^4.17.4" 487 | paralleljs "^0.2.1" 488 | prettier "^1.16.4" 489 | shelljs "^0.8.3" 490 | typescript "^3.4" 491 | typescript-compiler "^1.4.1-2" 492 | 493 | from2@^2.1.1: 494 | version "2.3.0" 495 | resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" 496 | integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= 497 | dependencies: 498 | inherits "^2.0.1" 499 | readable-stream "^2.0.0" 500 | 501 | fs-extra@^7.0.0: 502 | version "7.0.1" 503 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" 504 | integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== 505 | dependencies: 506 | graceful-fs "^4.1.2" 507 | jsonfile "^4.0.0" 508 | universalify "^0.1.0" 509 | 510 | fs.realpath@^1.0.0: 511 | version "1.0.0" 512 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 513 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 514 | 515 | fstream@^1.0.12: 516 | version "1.0.12" 517 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" 518 | integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== 519 | dependencies: 520 | graceful-fs "^4.1.2" 521 | inherits "~2.0.0" 522 | mkdirp ">=0.5 0" 523 | rimraf "2" 524 | 525 | get-caller-file@^1.0.1: 526 | version "1.0.3" 527 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" 528 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== 529 | 530 | get-caller-file@^2.0.1: 531 | version "2.0.5" 532 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 533 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 534 | 535 | get-stream@3.0.0, get-stream@^3.0.0: 536 | version "3.0.0" 537 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" 538 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= 539 | 540 | get-stream@^4.0.0: 541 | version "4.1.0" 542 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 543 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 544 | dependencies: 545 | pump "^3.0.0" 546 | 547 | glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: 548 | version "7.1.6" 549 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 550 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 551 | dependencies: 552 | fs.realpath "^1.0.0" 553 | inflight "^1.0.4" 554 | inherits "2" 555 | minimatch "^3.0.4" 556 | once "^1.3.0" 557 | path-is-absolute "^1.0.0" 558 | 559 | got@^8.3.2: 560 | version "8.3.2" 561 | resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" 562 | integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== 563 | dependencies: 564 | "@sindresorhus/is" "^0.7.0" 565 | cacheable-request "^2.1.1" 566 | decompress-response "^3.3.0" 567 | duplexer3 "^0.1.4" 568 | get-stream "^3.0.0" 569 | into-stream "^3.1.0" 570 | is-retry-allowed "^1.1.0" 571 | isurl "^1.0.0-alpha5" 572 | lowercase-keys "^1.0.0" 573 | mimic-response "^1.0.0" 574 | p-cancelable "^0.4.0" 575 | p-timeout "^2.0.1" 576 | pify "^3.0.0" 577 | safe-buffer "^5.1.1" 578 | timed-out "^4.0.1" 579 | url-parse-lax "^3.0.0" 580 | url-to-options "^1.0.1" 581 | 582 | graceful-fs@^4.1.2, graceful-fs@^4.1.6: 583 | version "4.2.3" 584 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" 585 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== 586 | 587 | has-flag@^2.0.0: 588 | version "2.0.0" 589 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 590 | integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= 591 | 592 | has-flag@^3.0.0: 593 | version "3.0.0" 594 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 595 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 596 | 597 | has-symbol-support-x@^1.4.1: 598 | version "1.4.2" 599 | resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" 600 | integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== 601 | 602 | has-to-string-tag-x@^1.2.0: 603 | version "1.4.1" 604 | resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" 605 | integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== 606 | dependencies: 607 | has-symbol-support-x "^1.4.1" 608 | 609 | http-cache-semantics@3.8.1: 610 | version "3.8.1" 611 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" 612 | integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== 613 | 614 | inflight@^1.0.4: 615 | version "1.0.6" 616 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 617 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 618 | dependencies: 619 | once "^1.3.0" 620 | wrappy "1" 621 | 622 | inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: 623 | version "2.0.4" 624 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 625 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 626 | 627 | interpret@^1.0.0: 628 | version "1.2.0" 629 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" 630 | integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== 631 | 632 | into-stream@^3.1.0: 633 | version "3.1.0" 634 | resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" 635 | integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= 636 | dependencies: 637 | from2 "^2.1.1" 638 | p-is-promise "^1.1.0" 639 | 640 | invert-kv@^2.0.0: 641 | version "2.0.0" 642 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" 643 | integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== 644 | 645 | is-buffer@~1.1.1: 646 | version "1.1.6" 647 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 648 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 649 | 650 | is-fullwidth-code-point@^1.0.0: 651 | version "1.0.0" 652 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 653 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 654 | dependencies: 655 | number-is-nan "^1.0.0" 656 | 657 | is-fullwidth-code-point@^2.0.0: 658 | version "2.0.0" 659 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 660 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 661 | 662 | is-object@^1.0.1: 663 | version "1.0.1" 664 | resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" 665 | integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= 666 | 667 | is-plain-obj@^1.0.0: 668 | version "1.1.0" 669 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" 670 | integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= 671 | 672 | is-plain-object@^3.0.0: 673 | version "3.0.0" 674 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928" 675 | integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg== 676 | dependencies: 677 | isobject "^4.0.0" 678 | 679 | is-retry-allowed@^1.1.0: 680 | version "1.2.0" 681 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" 682 | integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== 683 | 684 | is-stream@^1.1.0: 685 | version "1.1.0" 686 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 687 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 688 | 689 | isarray@~1.0.0: 690 | version "1.0.0" 691 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 692 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 693 | 694 | isexe@^2.0.0: 695 | version "2.0.0" 696 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 697 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 698 | 699 | isobject@^4.0.0: 700 | version "4.0.0" 701 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" 702 | integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== 703 | 704 | isurl@^1.0.0-alpha5: 705 | version "1.0.0" 706 | resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" 707 | integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== 708 | dependencies: 709 | has-to-string-tag-x "^1.2.0" 710 | is-object "^1.0.1" 711 | 712 | jest-changed-files@^24.9.0: 713 | version "24.9.0" 714 | resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" 715 | integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== 716 | dependencies: 717 | "@jest/types" "^24.9.0" 718 | execa "^1.0.0" 719 | throat "^4.0.0" 720 | 721 | js-tokens@^4.0.0: 722 | version "4.0.0" 723 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 724 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 725 | 726 | json-buffer@3.0.0: 727 | version "3.0.0" 728 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" 729 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= 730 | 731 | json-schema-traverse@^0.4.1: 732 | version "0.4.1" 733 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 734 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 735 | 736 | jsonfile@^4.0.0: 737 | version "4.0.0" 738 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 739 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= 740 | optionalDependencies: 741 | graceful-fs "^4.1.6" 742 | 743 | keyv@3.0.0: 744 | version "3.0.0" 745 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" 746 | integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== 747 | dependencies: 748 | json-buffer "3.0.0" 749 | 750 | lcid@^2.0.0: 751 | version "2.0.0" 752 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" 753 | integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== 754 | dependencies: 755 | invert-kv "^2.0.0" 756 | 757 | listenercount@~1.0.1: 758 | version "1.0.1" 759 | resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" 760 | integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= 761 | 762 | locate-path@^3.0.0: 763 | version "3.0.0" 764 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 765 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 766 | dependencies: 767 | p-locate "^3.0.0" 768 | path-exists "^3.0.0" 769 | 770 | lodash.get@^4.4.2: 771 | version "4.4.2" 772 | resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" 773 | integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= 774 | 775 | lodash.set@^4.3.2: 776 | version "4.3.2" 777 | resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" 778 | integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= 779 | 780 | lodash.uniq@^4.5.0: 781 | version "4.5.0" 782 | resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" 783 | integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= 784 | 785 | lodash@^4.17.14, lodash@^4.17.4: 786 | version "4.17.15" 787 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 788 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 789 | 790 | log-fancy@1.3.2: 791 | version "1.3.2" 792 | resolved "https://registry.yarnpkg.com/log-fancy/-/log-fancy-1.3.2.tgz#0d328bef0e6dca3d8b3758179c8ff35f1cd3860b" 793 | integrity sha512-8lYdFr4RfrB1b9222G9IGuLAqYugBAKuSvXXFFLEL1KrBgp0YeDv5RSTndMzC10t9slEyFvEZ4HvwszvH6A4Lg== 794 | dependencies: 795 | chalk "^2.1.0" 796 | debug "^3.0.0" 797 | log-symbols "^2.0.0" 798 | supports-color "^4.2.1" 799 | 800 | log-symbols@^2.0.0: 801 | version "2.2.0" 802 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" 803 | integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== 804 | dependencies: 805 | chalk "^2.0.1" 806 | 807 | lowercase-keys@1.0.0: 808 | version "1.0.0" 809 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" 810 | integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= 811 | 812 | lowercase-keys@^1.0.0: 813 | version "1.0.1" 814 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 815 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== 816 | 817 | macos-release@^2.2.0: 818 | version "2.3.0" 819 | resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" 820 | integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== 821 | 822 | map-age-cleaner@^0.1.1: 823 | version "0.1.3" 824 | resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" 825 | integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== 826 | dependencies: 827 | p-defer "^1.0.0" 828 | 829 | md5@^2.2.1: 830 | version "2.2.1" 831 | resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" 832 | integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= 833 | dependencies: 834 | charenc "~0.0.1" 835 | crypt "~0.0.1" 836 | is-buffer "~1.1.1" 837 | 838 | mem@^4.0.0: 839 | version "4.3.0" 840 | resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" 841 | integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== 842 | dependencies: 843 | map-age-cleaner "^0.1.1" 844 | mimic-fn "^2.0.0" 845 | p-is-promise "^2.0.0" 846 | 847 | mimic-fn@^2.0.0: 848 | version "2.1.0" 849 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 850 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 851 | 852 | mimic-response@^1.0.0: 853 | version "1.0.1" 854 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 855 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== 856 | 857 | minimatch@^3.0.4: 858 | version "3.0.4" 859 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 860 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 861 | dependencies: 862 | brace-expansion "^1.1.7" 863 | 864 | minimist@0.0.8: 865 | version "0.0.8" 866 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 867 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 868 | 869 | "mkdirp@>=0.5 0", mkdirp@^0.5.1: 870 | version "0.5.1" 871 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 872 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 873 | dependencies: 874 | minimist "0.0.8" 875 | 876 | ms@^2.1.1: 877 | version "2.1.2" 878 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 879 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 880 | 881 | nice-try@^1.0.4: 882 | version "1.0.5" 883 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 884 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 885 | 886 | node-fetch@^2.3.0: 887 | version "2.6.0" 888 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" 889 | integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== 890 | 891 | normalize-url@2.0.1: 892 | version "2.0.1" 893 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" 894 | integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== 895 | dependencies: 896 | prepend-http "^2.0.0" 897 | query-string "^5.0.1" 898 | sort-keys "^2.0.0" 899 | 900 | npm-run-path@^2.0.0: 901 | version "2.0.2" 902 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 903 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= 904 | dependencies: 905 | path-key "^2.0.0" 906 | 907 | number-is-nan@^1.0.0: 908 | version "1.0.1" 909 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 910 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 911 | 912 | object-assign@^4.1.0: 913 | version "4.1.1" 914 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 915 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 916 | 917 | octokit-pagination-methods@^1.1.0: 918 | version "1.1.0" 919 | resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" 920 | integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== 921 | 922 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 923 | version "1.4.0" 924 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 925 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 926 | dependencies: 927 | wrappy "1" 928 | 929 | os-locale@^3.0.0: 930 | version "3.1.0" 931 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" 932 | integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== 933 | dependencies: 934 | execa "^1.0.0" 935 | lcid "^2.0.0" 936 | mem "^4.0.0" 937 | 938 | os-name@^3.1.0: 939 | version "3.1.0" 940 | resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" 941 | integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== 942 | dependencies: 943 | macos-release "^2.2.0" 944 | windows-release "^3.1.0" 945 | 946 | p-cancelable@^0.4.0: 947 | version "0.4.1" 948 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" 949 | integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== 950 | 951 | p-defer@^1.0.0: 952 | version "1.0.0" 953 | resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" 954 | integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= 955 | 956 | p-finally@^1.0.0: 957 | version "1.0.0" 958 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 959 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 960 | 961 | p-is-promise@^1.1.0: 962 | version "1.1.0" 963 | resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" 964 | integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= 965 | 966 | p-is-promise@^2.0.0: 967 | version "2.1.0" 968 | resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" 969 | integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== 970 | 971 | p-limit@^2.0.0: 972 | version "2.2.1" 973 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" 974 | integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== 975 | dependencies: 976 | p-try "^2.0.0" 977 | 978 | p-locate@^3.0.0: 979 | version "3.0.0" 980 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 981 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 982 | dependencies: 983 | p-limit "^2.0.0" 984 | 985 | p-timeout@^2.0.1: 986 | version "2.0.1" 987 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" 988 | integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== 989 | dependencies: 990 | p-finally "^1.0.0" 991 | 992 | p-try@^2.0.0: 993 | version "2.2.0" 994 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 995 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 996 | 997 | paralleljs@^0.2.1: 998 | version "0.2.1" 999 | resolved "https://registry.yarnpkg.com/paralleljs/-/paralleljs-0.2.1.tgz#ebca745d3e09c01e2bebcc14858891ff4510e926" 1000 | integrity sha1-68p0XT4JwB4r68wUhYiR/0UQ6SY= 1001 | 1002 | path-exists@^3.0.0: 1003 | version "3.0.0" 1004 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1005 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 1006 | 1007 | path-is-absolute@^1.0.0: 1008 | version "1.0.1" 1009 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1010 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1011 | 1012 | path-key@^2.0.0, path-key@^2.0.1: 1013 | version "2.0.1" 1014 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 1015 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 1016 | 1017 | path-parse@^1.0.6: 1018 | version "1.0.6" 1019 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 1020 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 1021 | 1022 | pify@^3.0.0: 1023 | version "3.0.0" 1024 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" 1025 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 1026 | 1027 | prepend-http@^2.0.0: 1028 | version "2.0.0" 1029 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 1030 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= 1031 | 1032 | prettier@^1.16.4, prettier@^1.18.2: 1033 | version "1.19.1" 1034 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" 1035 | integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== 1036 | 1037 | process-nextick-args@~2.0.0: 1038 | version "2.0.1" 1039 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1040 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1041 | 1042 | pump@^3.0.0: 1043 | version "3.0.0" 1044 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1045 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1046 | dependencies: 1047 | end-of-stream "^1.1.0" 1048 | once "^1.3.1" 1049 | 1050 | punycode@^2.1.0: 1051 | version "2.1.1" 1052 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1053 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 1054 | 1055 | query-string@^5.0.1: 1056 | version "5.1.1" 1057 | resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" 1058 | integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== 1059 | dependencies: 1060 | decode-uri-component "^0.2.0" 1061 | object-assign "^4.1.0" 1062 | strict-uri-encode "^1.0.0" 1063 | 1064 | readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@~2.3.6: 1065 | version "2.3.6" 1066 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 1067 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== 1068 | dependencies: 1069 | core-util-is "~1.0.0" 1070 | inherits "~2.0.3" 1071 | isarray "~1.0.0" 1072 | process-nextick-args "~2.0.0" 1073 | safe-buffer "~5.1.1" 1074 | string_decoder "~1.1.1" 1075 | util-deprecate "~1.0.1" 1076 | 1077 | rechoir@^0.6.2: 1078 | version "0.6.2" 1079 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 1080 | integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= 1081 | dependencies: 1082 | resolve "^1.1.6" 1083 | 1084 | regenerator-runtime@^0.13.2: 1085 | version "0.13.3" 1086 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" 1087 | integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== 1088 | 1089 | require-directory@^2.1.1: 1090 | version "2.1.1" 1091 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1092 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 1093 | 1094 | require-main-filename@^1.0.1: 1095 | version "1.0.1" 1096 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 1097 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 1098 | 1099 | require-main-filename@^2.0.0: 1100 | version "2.0.0" 1101 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 1102 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 1103 | 1104 | resolve@^1.1.6: 1105 | version "1.13.1" 1106 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" 1107 | integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== 1108 | dependencies: 1109 | path-parse "^1.0.6" 1110 | 1111 | responselike@1.0.2: 1112 | version "1.0.2" 1113 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" 1114 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= 1115 | dependencies: 1116 | lowercase-keys "^1.0.0" 1117 | 1118 | rimraf@2, rimraf@^2.6.2: 1119 | version "2.7.1" 1120 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 1121 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 1122 | dependencies: 1123 | glob "^7.1.3" 1124 | 1125 | safe-buffer@^5.1.1: 1126 | version "5.2.0" 1127 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" 1128 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== 1129 | 1130 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1131 | version "5.1.2" 1132 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1133 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1134 | 1135 | semver@^5.5.0, semver@^5.5.1: 1136 | version "5.7.1" 1137 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1138 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1139 | 1140 | set-blocking@^2.0.0: 1141 | version "2.0.0" 1142 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1143 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1144 | 1145 | setimmediate@~1.0.4: 1146 | version "1.0.5" 1147 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 1148 | integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= 1149 | 1150 | shebang-command@^1.2.0: 1151 | version "1.2.0" 1152 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1153 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1154 | dependencies: 1155 | shebang-regex "^1.0.0" 1156 | 1157 | shebang-regex@^1.0.0: 1158 | version "1.0.0" 1159 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1160 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1161 | 1162 | shelljs@^0.8.3: 1163 | version "0.8.3" 1164 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" 1165 | integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== 1166 | dependencies: 1167 | glob "^7.0.0" 1168 | interpret "^1.0.0" 1169 | rechoir "^0.6.2" 1170 | 1171 | signal-exit@^3.0.0: 1172 | version "3.0.2" 1173 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1174 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 1175 | 1176 | slice-ansi@^2.1.0: 1177 | version "2.1.0" 1178 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" 1179 | integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== 1180 | dependencies: 1181 | ansi-styles "^3.2.0" 1182 | astral-regex "^1.0.0" 1183 | is-fullwidth-code-point "^2.0.0" 1184 | 1185 | sort-keys@^2.0.0: 1186 | version "2.0.0" 1187 | resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" 1188 | integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= 1189 | dependencies: 1190 | is-plain-obj "^1.0.0" 1191 | 1192 | split@^1.0.1: 1193 | version "1.0.1" 1194 | resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" 1195 | integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== 1196 | dependencies: 1197 | through "2" 1198 | 1199 | strict-uri-encode@^1.0.0: 1200 | version "1.1.0" 1201 | resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" 1202 | integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= 1203 | 1204 | string-width@^1.0.1: 1205 | version "1.0.2" 1206 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1207 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 1208 | dependencies: 1209 | code-point-at "^1.0.0" 1210 | is-fullwidth-code-point "^1.0.0" 1211 | strip-ansi "^3.0.0" 1212 | 1213 | string-width@^2.0.0, string-width@^2.1.1: 1214 | version "2.1.1" 1215 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1216 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1217 | dependencies: 1218 | is-fullwidth-code-point "^2.0.0" 1219 | strip-ansi "^4.0.0" 1220 | 1221 | string-width@^3.0.0, string-width@^3.1.0: 1222 | version "3.1.0" 1223 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1224 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 1225 | dependencies: 1226 | emoji-regex "^7.0.1" 1227 | is-fullwidth-code-point "^2.0.0" 1228 | strip-ansi "^5.1.0" 1229 | 1230 | string_decoder@~1.1.1: 1231 | version "1.1.1" 1232 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1233 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1234 | dependencies: 1235 | safe-buffer "~5.1.0" 1236 | 1237 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1238 | version "3.0.1" 1239 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1240 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 1241 | dependencies: 1242 | ansi-regex "^2.0.0" 1243 | 1244 | strip-ansi@^4.0.0: 1245 | version "4.0.0" 1246 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1247 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1248 | dependencies: 1249 | ansi-regex "^3.0.0" 1250 | 1251 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 1252 | version "5.2.0" 1253 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1254 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 1255 | dependencies: 1256 | ansi-regex "^4.1.0" 1257 | 1258 | strip-eof@^1.0.0: 1259 | version "1.0.0" 1260 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 1261 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 1262 | 1263 | supports-color@^4.2.1: 1264 | version "4.5.0" 1265 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" 1266 | integrity sha1-vnoN5ITexcXN34s9WRJQRJEvY1s= 1267 | dependencies: 1268 | has-flag "^2.0.0" 1269 | 1270 | supports-color@^5.3.0: 1271 | version "5.5.0" 1272 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1273 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1274 | dependencies: 1275 | has-flag "^3.0.0" 1276 | 1277 | table@^5.0.2: 1278 | version "5.4.6" 1279 | resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" 1280 | integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== 1281 | dependencies: 1282 | ajv "^6.10.2" 1283 | lodash "^4.17.14" 1284 | slice-ansi "^2.1.0" 1285 | string-width "^3.0.0" 1286 | 1287 | throat@^4.0.0, throat@^4.1.0: 1288 | version "4.1.0" 1289 | resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" 1290 | integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= 1291 | 1292 | through@2, through@^2.3.8: 1293 | version "2.3.8" 1294 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1295 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 1296 | 1297 | timed-out@^4.0.1: 1298 | version "4.0.1" 1299 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" 1300 | integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= 1301 | 1302 | "traverse@>=0.3.0 <0.4": 1303 | version "0.3.9" 1304 | resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" 1305 | integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= 1306 | 1307 | typescript-compiler@^1.4.1-2: 1308 | version "1.4.1-2" 1309 | resolved "https://registry.yarnpkg.com/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz#ba4f7db22d91534a1929d90009dce161eb72fd3f" 1310 | integrity sha1-uk99si2RU0oZKdkACdzhYety/T8= 1311 | 1312 | typescript@^3.4: 1313 | version "3.7.2" 1314 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" 1315 | integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== 1316 | 1317 | universal-user-agent@^4.0.0: 1318 | version "4.0.0" 1319 | resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16" 1320 | integrity sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA== 1321 | dependencies: 1322 | os-name "^3.1.0" 1323 | 1324 | universalify@^0.1.0: 1325 | version "0.1.2" 1326 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 1327 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 1328 | 1329 | unzipper@^0.9.3: 1330 | version "0.9.15" 1331 | resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.9.15.tgz#97d99203dad17698ee39882483c14e4845c7549c" 1332 | integrity sha512-2aaUvO4RAeHDvOCuEtth7jrHFaCKTSXPqUkXwADaLBzGbgZGzUDccoEdJ5lW+3RmfpOZYNx0Rw6F6PUzM6caIA== 1333 | dependencies: 1334 | big-integer "^1.6.17" 1335 | binary "~0.3.0" 1336 | bluebird "~3.4.1" 1337 | buffer-indexof-polyfill "~1.0.0" 1338 | duplexer2 "~0.1.4" 1339 | fstream "^1.0.12" 1340 | listenercount "~1.0.1" 1341 | readable-stream "~2.3.6" 1342 | setimmediate "~1.0.4" 1343 | 1344 | uri-js@^4.2.2: 1345 | version "4.2.2" 1346 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 1347 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 1348 | dependencies: 1349 | punycode "^2.1.0" 1350 | 1351 | url-parse-lax@^3.0.0: 1352 | version "3.0.0" 1353 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" 1354 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= 1355 | dependencies: 1356 | prepend-http "^2.0.0" 1357 | 1358 | url-to-options@^1.0.1: 1359 | version "1.0.1" 1360 | resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" 1361 | integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= 1362 | 1363 | util-deprecate@~1.0.1: 1364 | version "1.0.2" 1365 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1366 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1367 | 1368 | which-module@^2.0.0: 1369 | version "2.0.0" 1370 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 1371 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 1372 | 1373 | which@^1.2.9, which@^1.3.1: 1374 | version "1.3.1" 1375 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1376 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1377 | dependencies: 1378 | isexe "^2.0.0" 1379 | 1380 | windows-release@^3.1.0: 1381 | version "3.2.0" 1382 | resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f" 1383 | integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA== 1384 | dependencies: 1385 | execa "^1.0.0" 1386 | 1387 | wrap-ansi@^2.0.0: 1388 | version "2.1.0" 1389 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 1390 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= 1391 | dependencies: 1392 | string-width "^1.0.1" 1393 | strip-ansi "^3.0.1" 1394 | 1395 | wrap-ansi@^5.1.0: 1396 | version "5.1.0" 1397 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 1398 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 1399 | dependencies: 1400 | ansi-styles "^3.2.0" 1401 | string-width "^3.0.0" 1402 | strip-ansi "^5.0.0" 1403 | 1404 | wrappy@1: 1405 | version "1.0.2" 1406 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1407 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1408 | 1409 | wsrun@5.2.4: 1410 | version "5.2.4" 1411 | resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-5.2.4.tgz#6eb6c3ccd3327721a8df073a5e3578fb0dea494e" 1412 | integrity sha512-akv3WtKBohdHsD/5uqhYRHw6GXeCXe87FsSg28Szq+2cpoqRW2SY4yPfm1D0za1cS6MgNy5hPgzS5SqYJaGUxg== 1413 | dependencies: 1414 | bluebird "^3.5.1" 1415 | chalk "^2.3.0" 1416 | glob "^7.1.2" 1417 | jest-changed-files "^24.9.0" 1418 | lodash "^4.17.4" 1419 | minimatch "^3.0.4" 1420 | split "^1.0.1" 1421 | throat "^4.1.0" 1422 | yargs "^13.0.0" 1423 | 1424 | "y18n@^3.2.1 || ^4.0.0": 1425 | version "4.0.0" 1426 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 1427 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 1428 | 1429 | y18n@^4.0.0: 1430 | version "4.0.1" 1431 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" 1432 | integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== 1433 | 1434 | yargs-parser@^11.1.1: 1435 | version "11.1.1" 1436 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" 1437 | integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== 1438 | dependencies: 1439 | camelcase "^5.0.0" 1440 | decamelize "^1.2.0" 1441 | 1442 | yargs-parser@^13.1.2: 1443 | version "13.1.2" 1444 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 1445 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 1446 | dependencies: 1447 | camelcase "^5.0.0" 1448 | decamelize "^1.2.0" 1449 | 1450 | yargs@^12.0.2: 1451 | version "12.0.5" 1452 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" 1453 | integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== 1454 | dependencies: 1455 | cliui "^4.0.0" 1456 | decamelize "^1.2.0" 1457 | find-up "^3.0.0" 1458 | get-caller-file "^1.0.1" 1459 | os-locale "^3.0.0" 1460 | require-directory "^2.1.1" 1461 | require-main-filename "^1.0.1" 1462 | set-blocking "^2.0.0" 1463 | string-width "^2.0.0" 1464 | which-module "^2.0.0" 1465 | y18n "^3.2.1 || ^4.0.0" 1466 | yargs-parser "^11.1.1" 1467 | 1468 | yargs@^13.0.0: 1469 | version "13.3.2" 1470 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 1471 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 1472 | dependencies: 1473 | cliui "^5.0.0" 1474 | find-up "^3.0.0" 1475 | get-caller-file "^2.0.1" 1476 | require-directory "^2.1.1" 1477 | require-main-filename "^2.0.0" 1478 | set-blocking "^2.0.0" 1479 | string-width "^3.0.0" 1480 | which-module "^2.0.0" 1481 | y18n "^4.0.0" 1482 | yargs-parser "^13.1.2" 1483 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flow-mono-cli", 3 | "version": "0.0.0-development", 4 | "private": false, 5 | "author": "Immonet dev team (https://immonet.de)", 6 | "license": "MIT", 7 | "description": "A command line interface that aims to solve a few issues while working with flow typed codebases in a mono-repo.", 8 | "bin": { 9 | "flow-mono": "./bin/flow-mono" 10 | }, 11 | "engines": { 12 | "node": ">=8.11.4", 13 | "yarn": ">=1.6.0" 14 | }, 15 | "files": [ 16 | "dist", 17 | "bin" 18 | ], 19 | "keywords": [ 20 | "flow", 21 | "mono", 22 | "mono-repo", 23 | "cli", 24 | "stub", 25 | "typing", 26 | "lerna", 27 | "workspaces", 28 | "workspace", 29 | "yarn" 30 | ], 31 | "scripts": { 32 | "test": "jest", 33 | "integTest": "./examples/run.sh", 34 | "clean": "rimraf dist node_modules flow-typed", 35 | "build": "babel src --out-dir dist --ignore spec.js && flow-copy-source -v src dist --ignore='*.spec.js'", 36 | "dev": "nodemon --quiet --watch src --exec 'yarn build'", 37 | "flow": "flow", 38 | "flow-typed": "flow-typed", 39 | "flow-typed-install": "flow-typed install --ignoreDeps=peer --overwrite", 40 | "prepare": "yarn flow-typed-install || true", 41 | "lint": "eslint src", 42 | "prettier": "prettier --write src/**/*.js", 43 | "prepublishOnly": "yarn build", 44 | "release": "semantic-release" 45 | }, 46 | "dependencies": { 47 | "cosmiconfig": "6.0.0", 48 | "debug-logger": "0.4.1", 49 | "execa": "3.4.0", 50 | "find-up": "4.1.0", 51 | "glob": "7.1.7", 52 | "inquirer": "7.3.3", 53 | "jest-worker": "^24.9.0", 54 | "lodash.merge": "4.6.2", 55 | "micromatch": "4.0.4", 56 | "ora": "4.1.1", 57 | "yargs": "15.4.1" 58 | }, 59 | "devDependencies": { 60 | "@babel/cli": "7.14.5", 61 | "@babel/core": "7.14.3", 62 | "@babel/preset-flow": "7.14.5", 63 | "@immowelt/eslint-config-immowelt-base": "1.3.0", 64 | "@immowelt/jest-preset-node": "1.1.1", 65 | "eslint": "6.8.0", 66 | "eslint-plugin-compat": "3.9.0", 67 | "eslint-plugin-flowtype": "4.7.0", 68 | "eslint-plugin-import": "2.22.1", 69 | "flow-bin": "0.117.0", 70 | "flow-copy-source": "2.0.9", 71 | "flow-typed": "2.6.2", 72 | "jest": "24.9.0", 73 | "prettier": "1.19.1", 74 | "rimraf": "3.0.2", 75 | "semantic-release": "15.13.31" 76 | }, 77 | "jest": { 78 | "preset": "@immowelt/jest-preset-node" 79 | }, 80 | "publishConfig": { 81 | "access": "public" 82 | }, 83 | "release": { 84 | "analyzeCommits": { 85 | "releaseRules": [ 86 | { 87 | "type": "BREAKING", 88 | "release": "major" 89 | }, 90 | { 91 | "type": "FEATURE", 92 | "release": "minor" 93 | }, 94 | { 95 | "type": "BUGFIX", 96 | "release": "patch" 97 | } 98 | ] 99 | }, 100 | "branch": "master" 101 | }, 102 | "repository": { 103 | "type": "git", 104 | "url": "https://github.com/ImmoweltGroup/flow-mono-cli.git" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "semanticCommitType": "TASK", 3 | "semanticCommitScope": null, 4 | "semanticCommits": true, 5 | "docker": false, 6 | "automerge": true, 7 | "major": { 8 | "automerge": false 9 | }, 10 | "ignoreDeps": ["semantic-release"] 11 | } 12 | -------------------------------------------------------------------------------- /src/commands/__snapshots__/align-versions.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`align-versions should call the dependency.logVersionMisMatch method for each resolved package path and flow dependencies 1`] = ` 4 | Array [ 5 | Array [ 6 | "/foo/packages/package-a", 7 | "flow-bin", 8 | "1.2.0", 9 | ], 10 | ] 11 | `; 12 | -------------------------------------------------------------------------------- /src/commands/__snapshots__/create-stubs.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`create-stubs should iterate over all dependencies of the resolved packages and create 2nd level stubs for the configured dependency names. 1`] = ` 4 | Array [ 5 | Array [ 6 | "/foo/bar/package-a", 7 | ], 8 | Array [ 9 | "/foo/bar/package-b", 10 | ], 11 | Array [ 12 | "/foo/bar/package-c", 13 | ], 14 | ] 15 | `; 16 | 17 | exports[`create-stubs should iterate over all dependencies of the resolved packages and create 2nd level stubs for the configured dependency names. 2`] = ` 18 | Array [ 19 | Array [ 20 | "/foo/bar/package-a", 21 | "foo-package", 22 | ], 23 | Array [ 24 | "/foo/bar/package-a", 25 | "bar-package", 26 | ], 27 | Array [ 28 | "/foo/bar/package-b", 29 | "foo-package", 30 | ], 31 | ] 32 | `; 33 | -------------------------------------------------------------------------------- /src/commands/__snapshots__/create-symlinks.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`create-symlinks should create symlinks for the .flowconfig for each package as well as symlinks for the dependencies 1`] = ` 4 | Array [ 5 | Array [ 6 | "/usr/app/foo/.flowconfig", 7 | "/foo/baz", 8 | false, 9 | ], 10 | ] 11 | `; 12 | 13 | exports[`create-symlinks should create symlinks for the .flowconfig for each package as well as symlinks for the dependencies 2`] = ` 14 | Array [ 15 | Array [ 16 | "baz-dependency", 17 | "/foo", 18 | "/foo/bar", 19 | false, 20 | ], 21 | Array [ 22 | "baz-dependency", 23 | "/foo", 24 | "/foo/baz", 25 | false, 26 | ], 27 | ] 28 | `; 29 | -------------------------------------------------------------------------------- /src/commands/__snapshots__/install-types.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`install-types should fatally exit the process if something went wrong during the installation 1`] = ` 4 | Array [ 5 | Array [ 6 | "Failed installing \\"flow-typed\\" definitions in package \\"myFooPackageName\\"", 7 | "Foo", 8 | ], 9 | ] 10 | `; 11 | 12 | exports[`install-types should update the flow-typed cache and afterwards install types in all packages 1`] = ` 13 | Array [ 14 | Array [ 15 | "flow-typed", 16 | Array [ 17 | "update-cache", 18 | ], 19 | Object { 20 | "cwd": "/foo", 21 | "localDir": "/foo", 22 | "preferLocal": true, 23 | }, 24 | ], 25 | Array [ 26 | "flow-typed", 27 | Array [ 28 | "install", 29 | "--overwrite", 30 | ], 31 | Object { 32 | "cwd": "/foo/bar", 33 | "localDir": "/foo/bar", 34 | "preferLocal": true, 35 | }, 36 | ], 37 | Array [ 38 | "flow-typed", 39 | Array [ 40 | "install", 41 | "--overwrite", 42 | ], 43 | Object { 44 | "cwd": "/foo/baz", 45 | "localDir": "/foo/baz", 46 | "preferLocal": true, 47 | }, 48 | ], 49 | ] 50 | `; 51 | -------------------------------------------------------------------------------- /src/commands/align-versions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const inquirer = require('inquirer'); 4 | const path = require('./../lib/paths.js'); 5 | const dependency = require('./../lib/dependency.js'); 6 | const {info, success} = require('./../lib/logger.js'); 7 | 8 | async function checkVersionAndPromptUpdate(dependencyKey, packagePath) { 9 | const rootPath = await path.resolveMonoRepoRootPath(); 10 | const relativePackagePath = packagePath.replace(rootPath, ''); 11 | const {hasMisMatch, rootVersion} = await dependency.hasRootVersionMisMatch(dependencyKey, packagePath); 12 | 13 | if (hasMisMatch) { 14 | const answers = await inquirer.prompt({ 15 | type: 'confirm', 16 | name: 'shouldUpdateDependency', 17 | message: `Should we align the version of "${dependencyKey}" in package "${relativePackagePath}"?`, 18 | default: false 19 | }); 20 | 21 | if (answers.shouldUpdateDependency) { 22 | await dependency.updateDependency(packagePath, dependencyKey, rootVersion); 23 | } 24 | } else { 25 | success(`Dependency "${dependencyKey}" in package "${relativePackagePath}" is of the same version`); 26 | } 27 | } 28 | 29 | async function alignFlowVersions() { 30 | const packagePaths = await path.resolveMonoRepoPackagePaths(); 31 | 32 | info(`Aligning dependency versions of "flow-bin" and "flow-typed" in ${packagePaths.length} packages`); 33 | 34 | for (const packagePath of packagePaths) { 35 | await checkVersionAndPromptUpdate('flow-bin', packagePath); 36 | await checkVersionAndPromptUpdate('flow-typed', packagePath); 37 | } 38 | 39 | success('Aligned dependency versions'); 40 | } 41 | 42 | module.exports = alignFlowVersions; 43 | -------------------------------------------------------------------------------- /src/commands/align-versions.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./../lib/paths.js'); 4 | jest.mock('./../lib/dependency.js'); 5 | jest.mock('./../lib/logger.js'); 6 | 7 | const inquirer = require('inquirer'); 8 | const path: any = require('./../lib/paths.js'); 9 | const dependency: any = require('./../lib/dependency.js'); 10 | 11 | const alignFlowVersions = require('./align-versions.js'); 12 | 13 | describe('align-versions', () => { 14 | let prompt; 15 | 16 | beforeEach(() => { 17 | prompt = jest.spyOn(inquirer, 'prompt').mockImplementation(jest.fn()); 18 | }); 19 | 20 | afterEach(() => { 21 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 22 | jest.restoreAllMocks(); 23 | jest.clearAllMocks(); 24 | }); 25 | 26 | it('should export an function', () => { 27 | expect(typeof alignFlowVersions).toBe('function'); 28 | }); 29 | 30 | it('should call the dependency.logVersionMisMatch method for each resolved package path and flow dependencies', async () => { 31 | path.resolveMonoRepoPackagePaths.mockReturnValue([ 32 | '/foo/packages/package-a', 33 | '/foo/packages/package-b', 34 | '/foo/packages/package-c' 35 | ]); 36 | path.resolveMonoRepoRootPath.mockReturnValueOnce('/foo'); 37 | dependency.hasRootVersionMisMatch 38 | .mockReturnValueOnce( 39 | Promise.resolve({ 40 | hasMisMatch: true, 41 | rootVersion: '1.2.0', 42 | packageVersion: '1.0.0' 43 | }) 44 | ) 45 | .mockReturnValueOnce( 46 | Promise.resolve({ 47 | hasMisMatch: true, 48 | rootVersion: '1.3.0', 49 | packageVersion: '1.0.0' 50 | }) 51 | ) 52 | .mockReturnValue( 53 | Promise.resolve({ 54 | hasMisMatch: false, 55 | rootVersion: '1.2.0', 56 | packageVersion: '1.2.0' 57 | }) 58 | ); 59 | prompt.mockReturnValueOnce({shouldUpdateDependency: true}).mockReturnValue({shouldUpdateDependency: false}); 60 | 61 | await alignFlowVersions(); 62 | 63 | expect(dependency.updateDependency.mock.calls).toMatchSnapshot(); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /src/commands/create-stubs.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const mm = require('micromatch'); 4 | const config = require('./../lib/config.js'); 5 | const path = require('./../lib/paths.js'); 6 | const dependency = require('./../lib/dependency.js'); 7 | const flowTyped = require('./../lib/flowTyped.js'); 8 | const {info} = require('./../lib/logger.js'); 9 | 10 | async function createDependencyFlowTypeStubs({useRoot = false}: Object = {}) { 11 | const cliConfig = await config.resolveAndReadConfig(); 12 | const rootPath = await path.resolveMonoRepoRootPath(); 13 | const packagePaths = await path.resolveMonoRepoPackagePaths(); 14 | 15 | for (const cwd of packagePaths) { 16 | const packageJson = await dependency.readPackageJson(cwd); 17 | const dependencyKeys = dependency.mergeDependenciesIntoList(packageJson); 18 | const targetCwd = useRoot ? rootPath : cwd; 19 | const allowedStubDependencyKeys = mm(dependencyKeys, cliConfig['create-stubs'].dependencies); 20 | 21 | if (!allowedStubDependencyKeys.length) { 22 | continue; 23 | } 24 | 25 | info(`Creating in-direct dependency stubs in "${targetCwd}"`); 26 | 27 | for (const key of allowedStubDependencyKeys) { 28 | await flowTyped.createStubsForInDirectDependencies(targetCwd, key); 29 | } 30 | } 31 | } 32 | 33 | module.exports = createDependencyFlowTypeStubs; 34 | -------------------------------------------------------------------------------- /src/commands/create-stubs.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./../lib/config.js'); 4 | jest.mock('./../lib/paths.js'); 5 | jest.mock('./../lib/dependency.js'); 6 | jest.mock('./../lib/flowTyped.js'); 7 | jest.mock('./../lib/logger.js'); 8 | 9 | const config: any = require('./../lib/config.js'); 10 | const path: any = require('./../lib/paths.js'); 11 | const dependency: any = require('./../lib/dependency.js'); 12 | const flowTyped: any = require('./../lib/flowTyped.js'); 13 | 14 | const createDependencyFlowTypeStubs = require('./create-stubs.js'); 15 | 16 | describe('create-stubs', () => { 17 | afterEach(() => { 18 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 19 | jest.restoreAllMocks(); 20 | jest.clearAllMocks(); 21 | }); 22 | 23 | it('should export an function', () => { 24 | expect(typeof createDependencyFlowTypeStubs).toBe('function'); 25 | }); 26 | 27 | it('should iterate over all dependencies of the resolved packages and create 2nd level stubs for the configured dependency names.', async () => { 28 | config.resolveAndReadConfig.mockReturnValue({ 29 | 'create-stubs': {dependencies: ['foo-package', 'bar-package']} 30 | }); 31 | path.resolveMonoRepoPackagePaths.mockReturnValue([ 32 | '/foo/bar/package-a', 33 | '/foo/bar/package-b', 34 | '/foo/bar/package-c' 35 | ]); 36 | 37 | dependency.mergeDependenciesIntoList 38 | .mockReturnValueOnce(['foo-package', 'bar-package', 'baz-package']) 39 | .mockReturnValueOnce(['foo-package']) 40 | .mockReturnValueOnce(['baz-package']); 41 | 42 | await createDependencyFlowTypeStubs(); 43 | 44 | expect(dependency.readPackageJson.mock.calls).toMatchSnapshot(); 45 | expect(flowTyped.createStubsForInDirectDependencies.mock.calls).toMatchSnapshot(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/commands/create-symlinks.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const mm = require('micromatch'); 4 | const {join} = require('path'); 5 | const config = require('./../lib/config.js'); 6 | const path = require('./../lib/paths.js'); 7 | const dependency = require('./../lib/dependency.js'); 8 | const file = require('./../lib/file.js'); 9 | const {info, success} = require('./../lib/logger.js'); 10 | 11 | async function createFlowTypeSymlinks( 12 | {flowConfigPath, relative}: {flowConfigPath: string, relative: boolean}, 13 | cwd?: string = process.cwd() 14 | ) { 15 | const cliConfig = await config.resolveAndReadConfig(); 16 | const absoluteFlowConfigPath = join(cwd, flowConfigPath); 17 | 18 | info('Creating symlinks to the defined ".flowconfig" and dependencies to all packages with a "flow-bin" dependency'); 19 | 20 | const [rootPath, packagePaths] = await Promise.all([ 21 | path.resolveMonoRepoRootPath(), 22 | path.resolveMonoRepoPackagePaths() 23 | ]); 24 | 25 | await Promise.all( 26 | packagePaths.map(async packagePath => { 27 | const existsFlowConfig = await file.existsAsync(join(packagePath, '.flowconfig')); 28 | 29 | if (existsFlowConfig === false) { 30 | await file.createSymlink(absoluteFlowConfigPath, packagePath, relative); 31 | } 32 | 33 | const packageJson = await dependency.readPackageJson(packagePath); 34 | const dependencyKeys = dependency.mergeDependenciesIntoList(packageJson); 35 | const ignoredPackageKeys = mm(dependencyKeys, cliConfig['create-symlinks'].ignore); 36 | 37 | await Promise.all( 38 | dependencyKeys.filter(key => ignoredPackageKeys.includes(key) === false).map(key => dependency.createSymlinkForDependency(key, rootPath, packagePath, relative)) 39 | ); 40 | }) 41 | ); 42 | 43 | success(`Symlinked all direct dependencies of ${packagePaths.length} packages`); 44 | } 45 | 46 | module.exports = createFlowTypeSymlinks; 47 | -------------------------------------------------------------------------------- /src/commands/create-symlinks.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./../lib/config.js'); 4 | jest.mock('./../lib/logger.js'); 5 | jest.mock('./../lib/dependency.js'); 6 | jest.mock('./../lib/paths.js'); 7 | jest.mock('./../lib/file.js'); 8 | 9 | const config: any = require('./../lib/config.js'); 10 | const path: any = require('./../lib/paths.js'); 11 | const dependency: any = require('./../lib/dependency.js'); 12 | const file: any = require('./../lib/file.js'); 13 | 14 | const createFlowTypeSymlinks = require('./create-symlinks.js'); 15 | 16 | describe('create-symlinks', () => { 17 | afterEach(() => { 18 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 19 | jest.restoreAllMocks(); 20 | jest.clearAllMocks(); 21 | }); 22 | 23 | it('should export an function', () => { 24 | expect(typeof createFlowTypeSymlinks).toBe('function'); 25 | }); 26 | 27 | it('should create symlinks for the .flowconfig for each package as well as symlinks for the dependencies', async () => { 28 | config.resolveAndReadConfig.mockReturnValue({ 29 | 'create-symlinks': {ignore: ['foo-dependency', 'bar-dependency']} 30 | }); 31 | path.resolveMonoRepoRootPath.mockReturnValue('/foo'); 32 | path.resolveMonoRepoPackagePaths.mockReturnValue(['/foo/bar', '/foo/baz']); 33 | file.existsAsync.mockReturnValueOnce(true).mockReturnValue(false); 34 | dependency.readPackageJson.mockReturnValue({}); 35 | dependency.mergeDependenciesIntoList.mockReturnValue(['foo-dependency', 'bar-dependency', 'baz-dependency']); 36 | 37 | await createFlowTypeSymlinks({flowConfigPath: '/foo/.flowconfig', relative: false}, '/usr/app'); 38 | 39 | expect(file.createSymlink.mock.calls).toMatchSnapshot(); 40 | expect(dependency.createSymlinkForDependency.mock.calls).toMatchSnapshot(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/commands/install-types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const {default: Workder} = require('jest-worker'); 4 | 5 | const path = require('./../lib/paths.js'); 6 | const dependency = require('./../lib/dependency.js'); 7 | const flowTyped = require('./../lib/flowTyped.js'); 8 | const {info, success, error} = require('./../lib/logger.js'); 9 | 10 | async function installFlowTypes() { 11 | const exec = new Workder(require.resolve('./../lib/exec.js')); 12 | const [rootPath, packagePaths] = await Promise.all([ 13 | path.resolveMonoRepoRootPath(), 14 | path.resolveMonoRepoPackagePaths() 15 | ]); 16 | 17 | // We will update the flow-typed cache first to avoid errors when running the install step in parallel. 18 | info('Updating the global "flow-typed" definitions cache'); 19 | await exec.asyncWithRetries('flow-typed', ['update-cache'], { 20 | preferLocal: true, 21 | localDir: rootPath, 22 | cwd: rootPath 23 | }); 24 | 25 | info(`Installing "flow-typed" definitions for dependencies in ${packagePaths.length} packages`); 26 | await Promise.all( 27 | packagePaths.map(async packagePath => { 28 | try { 29 | const args = flowTyped.parseArgs(); 30 | 31 | await exec.asyncWithRetries('flow-typed', ['install'].concat(args), { 32 | preferLocal: true, 33 | localDir: packagePath, 34 | cwd: packagePath 35 | }); 36 | } catch (e) { 37 | const {name} = await dependency.readPackageJson(packagePath); 38 | 39 | error(`Failed installing "flow-typed" definitions in package "${name}"`, e.message); 40 | console.error(e); 41 | } 42 | }) 43 | ); 44 | 45 | success('Installed "flow-typed" definitions'); 46 | exec.end(); 47 | } 48 | 49 | module.exports = installFlowTypes; 50 | -------------------------------------------------------------------------------- /src/commands/install-types.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('jest-worker'); 4 | 5 | jest.mock('./../lib/paths.js'); 6 | jest.mock('./../lib/logger.js'); 7 | jest.mock('./../lib/dependency.js'); 8 | jest.mock('./../lib/flowTyped.js'); 9 | jest.mock('./../lib/exec.js'); 10 | console.error = jest.fn(); 11 | 12 | const {default: Worker} = require('jest-worker'); 13 | 14 | const path: any = require('./../lib/paths.js'); 15 | const dependency: any = require('./../lib/dependency.js'); 16 | const flowTyped: any = require('./../lib/flowTyped.js'); 17 | const logger: any = require('./../lib/logger.js'); 18 | const exec: any = require('./../lib/exec.js'); 19 | 20 | const installFlowTypes = require('./install-types.js'); 21 | 22 | describe('install-types', () => { 23 | beforeAll(() => { 24 | Worker.mockImplementation(() => ({ 25 | asyncWithRetries: exec.asyncWithRetries, 26 | end: () => {} 27 | })); 28 | }); 29 | 30 | afterEach(() => { 31 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 32 | jest.restoreAllMocks(); 33 | jest.clearAllMocks(); 34 | }); 35 | 36 | it('should export an function', () => { 37 | expect(typeof installFlowTypes).toBe('function'); 38 | }); 39 | 40 | it('should update the flow-typed cache and afterwards install types in all packages', async () => { 41 | path.resolveMonoRepoRootPath.mockReturnValue('/foo'); 42 | path.resolveMonoRepoPackagePaths.mockReturnValue(['/foo/bar', '/foo/baz']); 43 | flowTyped.parseArgs.mockReturnValue(['--overwrite']); 44 | 45 | await installFlowTypes(); 46 | 47 | expect(exec.asyncWithRetries.mock.calls).toMatchSnapshot(); 48 | }); 49 | 50 | it('should fatally exit the process if something went wrong during the installation', async () => { 51 | path.resolveMonoRepoRootPath.mockReturnValue('/foo'); 52 | path.resolveMonoRepoPackagePaths.mockReturnValue(['/foo/bar', '/foo/baz']); 53 | flowTyped.parseArgs.mockReturnValue(['--overwrite']); 54 | dependency.readPackageJson.mockReturnValue({name: 'myFooPackageName'}); 55 | exec.asyncWithRetries.mockReturnValueOnce(null).mockReturnValueOnce(Promise.reject(new Error('Foo'))); 56 | 57 | await installFlowTypes(); 58 | 59 | expect(logger.error.mock.calls).toMatchSnapshot(); 60 | expect(console.error).toHaveBeenCalled(); 61 | expect(console.error.mock.calls[0][0].message).toBe('Foo'); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/lib/__snapshots__/config.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`config.resolveAndReadConfig() should call the "find-config-up" package and return the resolved config 1`] = ` 4 | Object { 5 | "create-stubs": Object { 6 | "dependencies": Array [], 7 | }, 8 | "create-symlinks": Object { 9 | "ignore": Array [], 10 | }, 11 | "flowTypedCommandExecRetries": 1, 12 | "foo": "bar", 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /src/lib/__snapshots__/dependency.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`dependency.updateDependency() should align the given version in all dependency maps and write the new file contents to disk 1`] = ` 4 | Array [ 5 | "/foo/packages/bar/package.json", 6 | "{ 7 | \\"name\\": \\"myPackage\\", 8 | \\"dependencies\\": { 9 | \\"foo\\": \\"1.2.0\\" 10 | }, 11 | \\"devDependencies\\": { 12 | \\"myDependency\\": \\"1.1.0\\" 13 | }, 14 | \\"peerDependencies\\": { 15 | \\"myDependency\\": \\"1.1.0\\" 16 | } 17 | }", 18 | ] 19 | `; 20 | -------------------------------------------------------------------------------- /src/lib/async.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const ora = require('ora'); 4 | const {error} = require('./logger.js'); 5 | 6 | const asyncUtils = { 7 | /** 8 | * Executes a function that returns a Promise with the provided argumens and automatically catches failures. 9 | * 10 | * @param {Function} fn The function to execute. 11 | * @param {Array} args The arguments to propagate to the function. 12 | * @return {Promise} The Promise that resolves once the function has been resolved. 13 | */ 14 | exec(fn: Function, ...args: Array) { 15 | const spinner = ora().start(); 16 | return fn(...args) 17 | .then(() => spinner.stop()) 18 | .catch(e => { 19 | spinner.stop(); 20 | error(e.message); 21 | }); 22 | } 23 | }; 24 | 25 | module.exports = asyncUtils; 26 | -------------------------------------------------------------------------------- /src/lib/async.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./logger.js'); 4 | jest.mock('ora', () => jest.fn(() => ({ 5 | start: jest.fn(() => ({ 6 | stop: jest.fn() 7 | })) 8 | }))); 9 | 10 | const logger = require('./logger.js'); 11 | const asyncUtils = require('./async.js'); 12 | 13 | describe('asyncUtils.exec()', () => { 14 | it('should be a function', () => { 15 | expect(typeof asyncUtils.exec).toBe('function'); 16 | }); 17 | 18 | it('should execute the function with the provided args', async () => { 19 | const fn = jest.fn(() => Promise.resolve()); 20 | const args = ['foo', 'bar']; 21 | 22 | await asyncUtils.exec(fn, ...args); 23 | 24 | expect(fn.mock.calls.length).toBe(1); 25 | expect(fn.mock.calls[0]).toEqual(args); 26 | }); 27 | 28 | it('should safely fail if the function rejects with a call to the logger.error method.', async () => { 29 | const fn = jest.fn(() => Promise.reject(new Error('Foo bar'))); 30 | 31 | await asyncUtils.exec(fn); 32 | 33 | expect(logger.error.mock.calls.length).toBe(1); 34 | expect(logger.error.mock.calls).toEqual([['Foo bar']]); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/lib/config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const {cosmiconfig} = require('cosmiconfig'); 4 | const merge = require('lodash.merge'); 5 | 6 | const utils = { 7 | cosmiconfig 8 | }; 9 | const defaults = { 10 | flowTypedCommandExecRetries: 1, 11 | 'create-symlinks': { 12 | ignore: [] 13 | }, 14 | 'create-stubs': { 15 | dependencies: [] 16 | } 17 | }; 18 | 19 | const config = { 20 | utils, 21 | 22 | async resolveAndReadConfig(): Promise { 23 | const explorer = utils.cosmiconfig('flow-mono', { 24 | searchPlaces: [ 25 | 'package.json', 26 | '.flowmonorc', 27 | '.flowmonorc.json', 28 | '.flowmonorc.yaml', 29 | '.flowmonorc.yml', 30 | '.flowmonorc.js', 31 | 'flowmono.config.js' 32 | ] 33 | }); 34 | const results = await explorer.search(); 35 | 36 | return results && results.config ? merge({}, defaults, results.config) : defaults; 37 | } 38 | }; 39 | 40 | module.exports = config; 41 | -------------------------------------------------------------------------------- /src/lib/config.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const config = require('./config.js'); 4 | 5 | describe('config.resolveAndReadConfig()', () => { 6 | let search; 7 | 8 | beforeEach(() => { 9 | search = jest.fn(); 10 | jest.spyOn(config.utils, 'cosmiconfig').mockImplementation( 11 | jest.fn(() => ({ 12 | search 13 | })) 14 | ); 15 | }); 16 | 17 | afterEach(() => { 18 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 19 | jest.restoreAllMocks(); 20 | jest.clearAllMocks(); 21 | }); 22 | 23 | it('should be a function', () => { 24 | expect(typeof config.resolveAndReadConfig).toBe('function'); 25 | }); 26 | 27 | it('should call the "find-config-up" package and return the resolved config', async () => { 28 | search.mockReturnValue({config: {foo: 'bar'}}); 29 | 30 | const cfg = await config.resolveAndReadConfig(); 31 | 32 | expect(cfg).toMatchSnapshot(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/lib/dependency.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const fs = require('fs'); 4 | const {join} = require('path'); 5 | const path = require('./paths'); 6 | const file = require('./file'); 7 | const update = require('./updateVersion'); 8 | 9 | const dependencyUtils = { 10 | /** 11 | * Merges the contents of a `package.json` into a single dependency map. 12 | * 13 | * @param {Object} json The contents of a `package.json`. 14 | * @return {Object} The map of all dependencies of the given `package.json`. 15 | */ 16 | mergeDependenciesIntoMap(json: Object = {}): {[string]: string} { 17 | return { 18 | ...(json.dependencies || {}), 19 | ...(json.devDependencies || {}), 20 | ...(json.optionalDependencies || {}) 21 | }; 22 | }, 23 | 24 | /** 25 | * Merges the contents of a `package.json` into a list of keys for iterations. 26 | * 27 | * @param {Object} json The contents of a `package.json`. 28 | * @return {Array} The list of dependency keys of the given `package.json`. 29 | */ 30 | mergeDependenciesIntoList(json: Object = {}): Array { 31 | return Object.keys(this.mergeDependenciesIntoMap(json)); 32 | }, 33 | 34 | /** 35 | * Returns the version string of the given dependency name in the contents of a `package.json` file. 36 | * 37 | * @param {String} key The name of the dependency for which the function should return the version. 38 | * @param {Object} json The contents of a `package.json`. 39 | * @return {String} The semantic versioning version string. 40 | */ 41 | getDependencyVersion(key: string, json: Object = {}): string { 42 | const dependencies = this.mergeDependenciesIntoMap(json); 43 | 44 | return dependencies[key]; 45 | }, 46 | 47 | /** 48 | * Reads the contents of a `package.json` and falls back to an empty object if it does not exist. 49 | * 50 | * @param {String} packagePath The full path to the package from which we should require the `package.json`. 51 | * @return {Object} The contents of the `package.json`. 52 | */ 53 | async readPackageJson(packagePath: string): Promise { 54 | const filePath = join(packagePath, 'package.json'); 55 | const existsFile = await file.existsAsync(filePath); 56 | 57 | if (existsFile === false) { 58 | return {}; 59 | } 60 | 61 | return file.readJson(filePath); 62 | }, 63 | 64 | /** 65 | * Updates the given dependency in the given packagePaths package.json. 66 | * 67 | * @param {String} packagePath The full path to the package in which the update should be executed. 68 | * @param {String} dependencyKey The dependency name to update. 69 | * @param {String} version The version to which the dependency should be bumped. 70 | * @return {Promise} The promise that resolves once the update is executed. 71 | */ 72 | async updateDependency(packagePath: string, dependencyKey: string, version: string) { 73 | let json = await this.readPackageJson(packagePath); 74 | 75 | json = update(json, 'dependencies', dependencyKey, version); 76 | json = update(json, 'devDependencies', dependencyKey, version); 77 | json = update(json, 'peerDependencies', dependencyKey, version); 78 | json = update(json, 'optionalDependencies', dependencyKey, version); 79 | 80 | await file.writeFile(join(packagePath, 'package.json'), JSON.stringify(json, null, 2)); 81 | 82 | return json; 83 | }, 84 | 85 | /** 86 | * Checks if a mismatch of the given dependency key is given compared to the one specified in the root package.json. 87 | * 88 | * @param {String} key The key/name of the dependency to validate. 89 | * @param {String} packagePath The package path to validate against the root. 90 | * @return {Promise} The promise that resolves once the validation finished. 91 | */ 92 | async hasRootVersionMisMatch( 93 | key: string, 94 | packagePath: string 95 | ): Promise<{ 96 | hasMisMatch: boolean, 97 | rootVersion: string, 98 | packageVersion: string 99 | }> { 100 | const rootPath = await path.resolveMonoRepoRootPath(); 101 | const [rootPackageJson, packageJson] = await Promise.all([ 102 | this.readPackageJson(rootPath), 103 | this.readPackageJson(packagePath) 104 | ]); 105 | const rootVersion = this.getDependencyVersion(key, rootPackageJson); 106 | const packageVersion = this.getDependencyVersion(key, packageJson); 107 | 108 | return { 109 | hasMisMatch: Boolean(rootVersion && packageVersion && packageVersion !== rootVersion), 110 | rootVersion, 111 | packageVersion 112 | }; 113 | }, 114 | 115 | /** 116 | * Checks if the given package name is a scoped dependency. 117 | * 118 | * @param {String} key The dependency name to validate. 119 | * @return {Boolean} The boolean indicating if the given package name is scoped or not. 120 | */ 121 | isScopedDependency(key: string): boolean { 122 | return key.startsWith('@') && key.includes('/'); 123 | }, 124 | 125 | /** 126 | * Parses the scope identifier of a package name. 127 | * 128 | * @param {String} key The dependency name to parse. 129 | * @return {String} The dependency scope. 130 | */ 131 | getScopeForDependency(key: string): string { 132 | return key.split('/').shift(); 133 | }, 134 | 135 | /** 136 | * Ensures that the directory structure for a dependency exists. We made this method synchronous since non-blocking behavior could lead to false-positives in iterations. 137 | * 138 | * @param {String} key The package name for which we should create the required directory structure. 139 | * @param {String} directoryPath The package path of the mono repo in which we should create the directory structure. 140 | * @return {Promise} A Promise that resolves once the structure is set up. 141 | */ 142 | ensureDependencyScopeExists(key: string, directoryPath: string) { 143 | const isScoped = this.isScopedDependency(key); 144 | 145 | if (isScoped) { 146 | const scope = this.getScopeForDependency(key); 147 | const scopePath = join(directoryPath, 'node_modules', scope); 148 | const existsFile = fs.existsSync(scopePath); 149 | 150 | if (existsFile === false) { 151 | fs.mkdirSync(scopePath); 152 | } 153 | } 154 | }, 155 | 156 | /** 157 | * Creates a symlinks of a dependency from the root into the given package directories `node_modules`. 158 | * @param {String} key The name of the dependency. 159 | * @param {String} rootDir The root directory of the mono repo. 160 | * @param {String} packageDir The package directory in whichs `node_modules` folder we should create the symlink. 161 | * @return {Promise} A Promise that resolves once the symlink was created. 162 | */ 163 | async createSymlinkForDependency(key: string, rootDir: string, packageDir: string, relative: boolean) { 164 | this.ensureDependencyScopeExists(key, packageDir); 165 | 166 | const scope = this.getScopeForDependency(key); 167 | const src = join(rootDir, 'node_modules', key); 168 | const dist = join(packageDir, 'node_modules', key); 169 | const distDir = this.isScopedDependency(key) ? 170 | join(packageDir, 'node_modules', scope) : 171 | join(packageDir, 'node_modules'); 172 | const [existsSrc, existsDist] = await Promise.all([file.existsAsync(src), file.existsAsync(dist)]); 173 | 174 | // Do not create a symlink if the source folder of the dependency does not exist. 175 | if (existsSrc === false) { 176 | return; 177 | } 178 | 179 | // Do not create a symlink if the dependency was already linked. 180 | if (existsDist === true) { 181 | return; 182 | } 183 | 184 | await file.createSymlink(src, distDir, relative); 185 | } 186 | }; 187 | 188 | module.exports = dependencyUtils; 189 | -------------------------------------------------------------------------------- /src/lib/dependency.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./file.js'); 4 | jest.mock('./logger.js'); 5 | jest.mock('./paths.js'); 6 | 7 | const fs = require('fs'); 8 | const file: any = require('./file.js'); 9 | const path: any = require('./paths.js'); 10 | const dependency = require('./dependency.js'); 11 | 12 | describe('dependency.mergeDependenciesIntoMap()', () => { 13 | it('should be a function', () => { 14 | expect(typeof dependency.mergeDependenciesIntoMap).toBe('function'); 15 | }); 16 | 17 | it('should merge the "devDependencies", "dependencies" and "optionalDependencies" into one single map without duplicates', () => { 18 | const result = dependency.mergeDependenciesIntoMap({ 19 | dependencies: { 20 | foo: '1.0.0' 21 | }, 22 | devDependencies: { 23 | bar: '2.1.0', 24 | foo: '1.0.0' 25 | }, 26 | optionalDependencies: { 27 | baz: '3.7.11' 28 | } 29 | }); 30 | 31 | expect(result).toEqual({ 32 | bar: '2.1.0', 33 | foo: '1.0.0', 34 | baz: '3.7.11' 35 | }); 36 | }); 37 | 38 | it('should not throw errors if no argument was provided', () => { 39 | expect(() => dependency.mergeDependenciesIntoMap()).not.toThrow(); 40 | }); 41 | }); 42 | 43 | describe('dependency.mergeDependenciesIntoList()', () => { 44 | it('should be a function', () => { 45 | expect(typeof dependency.mergeDependenciesIntoList).toBe('function'); 46 | }); 47 | 48 | it('should merge the "devDependencies", "dependencies" and "optionalDependencies" into one single list of package names without duplicates', () => { 49 | const result = dependency.mergeDependenciesIntoList({ 50 | dependencies: { 51 | foo: '1.0.0' 52 | }, 53 | devDependencies: { 54 | bar: '2.1.0', 55 | foo: '1.0.0' 56 | }, 57 | optionalDependencies: { 58 | baz: '3.7.11' 59 | } 60 | }); 61 | 62 | expect(result).toEqual(['foo', 'bar', 'baz']); 63 | }); 64 | 65 | it('should not throw errors if no argument was provided', () => { 66 | expect(() => dependency.mergeDependenciesIntoList()).not.toThrow(); 67 | }); 68 | }); 69 | 70 | describe('dependency.getDependencyVersion()', () => { 71 | it('should be a function', () => { 72 | expect(typeof dependency.getDependencyVersion).toBe('function'); 73 | }); 74 | 75 | it('should return the version of the given dependency name within the package json.', () => { 76 | const result = dependency.getDependencyVersion('baz', { 77 | dependencies: { 78 | foo: '1.0.0' 79 | }, 80 | devDependencies: { 81 | bar: '2.1.0', 82 | foo: '1.0.0' 83 | }, 84 | optionalDependencies: { 85 | baz: '3.7.11' 86 | } 87 | }); 88 | 89 | expect(result).toEqual('3.7.11'); 90 | }); 91 | 92 | it('should not throw errors if no argument was provided', () => { 93 | expect(() => dependency.mergeDependenciesIntoList()).not.toThrow(); 94 | }); 95 | }); 96 | 97 | describe('dependency.readPackageJson()', () => { 98 | afterEach(() => { 99 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 100 | jest.restoreAllMocks(); 101 | jest.clearAllMocks(); 102 | }); 103 | 104 | it('should be a function', () => { 105 | expect(typeof dependency.readPackageJson).toBe('function'); 106 | }); 107 | 108 | it('should call the file.readJson function with the given package path and appended package.json filename', async () => { 109 | file.existsAsync.mockReturnValueOnce(true); 110 | file.readJson.mockReturnValueOnce({foo: 'bar'}); 111 | 112 | const contents = await dependency.readPackageJson('/foo/bar'); 113 | 114 | expect(contents).toEqual({foo: 'bar'}); 115 | }); 116 | 117 | it('should fallback to an empty object if the file.existsAsync method returns "false"', async () => { 118 | file.existsAsync.mockReturnValueOnce(false); 119 | 120 | const contents = await dependency.readPackageJson('/foo/bar'); 121 | 122 | expect(contents).toEqual({}); 123 | }); 124 | }); 125 | 126 | describe('dependency.updateDependency()', () => { 127 | let readPackageJson; 128 | let writeFile; 129 | 130 | beforeEach(() => { 131 | readPackageJson = jest.spyOn(dependency, 'readPackageJson').mockImplementation(jest.fn()); 132 | writeFile = jest.spyOn(file, 'writeFile').mockImplementation(jest.fn()); 133 | }); 134 | 135 | afterEach(() => { 136 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 137 | jest.restoreAllMocks(); 138 | jest.clearAllMocks(); 139 | }); 140 | 141 | it('should be a function', () => { 142 | expect(typeof dependency.updateDependency).toBe('function'); 143 | }); 144 | 145 | it('should align the given version in all dependency maps and write the new file contents to disk', async () => { 146 | readPackageJson.mockReturnValue({ 147 | name: 'myPackage', 148 | dependencies: { 149 | foo: '1.2.0' 150 | }, 151 | devDependencies: { 152 | myDependency: '1.0.0' 153 | }, 154 | peerDependencies: { 155 | myDependency: '1.0.0' 156 | } 157 | }); 158 | 159 | await dependency.updateDependency('/foo/packages/bar', 'myDependency', '1.1.0'); 160 | 161 | expect(writeFile.mock.calls[0]).toMatchSnapshot(); 162 | }); 163 | }); 164 | 165 | describe('dependency.hasRootVersionMisMatch()', () => { 166 | let readPackageJson; 167 | 168 | beforeEach(() => { 169 | readPackageJson = jest.spyOn(dependency, 'readPackageJson').mockImplementation(jest.fn()); 170 | }); 171 | 172 | afterEach(() => { 173 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 174 | jest.restoreAllMocks(); 175 | jest.clearAllMocks(); 176 | }); 177 | 178 | it('should be a function', () => { 179 | expect(typeof dependency.hasRootVersionMisMatch).toBe('function'); 180 | }); 181 | 182 | it('should resolve the root and the given packagePaths package.json, compare the given package name version and log out any differences.', async () => { 183 | path.resolveMonoRepoRootPath.mockReturnValueOnce('/foo'); 184 | readPackageJson 185 | .mockReturnValueOnce({dependencies: {foo: '1.2.0', bar: '1.0.0'}}) 186 | .mockReturnValueOnce({dependencies: {foo: '1.3.0', bar: '1.0.0'}}); 187 | 188 | const results = await dependency.hasRootVersionMisMatch('foo', '/foo/bar'); 189 | 190 | expect(results).toEqual({ 191 | hasMisMatch: true, 192 | rootVersion: '1.2.0', 193 | packageVersion: '1.3.0' 194 | }); 195 | }); 196 | }); 197 | 198 | describe('dependency.isScopedDependency()', () => { 199 | it('should be a function', () => { 200 | expect(typeof dependency.isScopedDependency).toBe('function'); 201 | }); 202 | 203 | it('should return a boolean indicating if the packageName is a scoped dependency or not.', async () => { 204 | expect(dependency.isScopedDependency('@foo/bar')).toBe(true); 205 | expect(dependency.isScopedDependency('bar')).toBe(false); 206 | expect(dependency.isScopedDependency('foo/@bar')).toBe(false); 207 | }); 208 | }); 209 | 210 | describe('dependency.getScopeForDependency()', () => { 211 | it('should be a function', () => { 212 | expect(typeof dependency.getScopeForDependency).toBe('function'); 213 | }); 214 | 215 | it('should return the scope of the packageName.', async () => { 216 | expect(dependency.getScopeForDependency('@foo/bar')).toBe('@foo'); 217 | }); 218 | }); 219 | 220 | describe('dependency.ensureDependencyScopeExists()', () => { 221 | let isScopedDependency; 222 | let getScopeForDependency; 223 | let existsSync; 224 | let mkdirSync; 225 | 226 | beforeEach(() => { 227 | isScopedDependency = jest.spyOn(dependency, 'isScopedDependency').mockImplementation(jest.fn(() => false)); 228 | getScopeForDependency = jest.spyOn(dependency, 'getScopeForDependency').mockImplementation(jest.fn(() => '@foo')); 229 | existsSync = jest.spyOn(fs, 'existsSync').mockImplementation(jest.fn()); 230 | mkdirSync = jest.spyOn(fs, 'mkdirSync').mockImplementation(jest.fn()); 231 | }); 232 | 233 | afterEach(() => { 234 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 235 | jest.restoreAllMocks(); 236 | jest.clearAllMocks(); 237 | }); 238 | 239 | it('should be a function', () => { 240 | expect(typeof dependency.ensureDependencyScopeExists).toBe('function'); 241 | }); 242 | 243 | it('should create the dependency scope directory if it was not existing in the given package paths node_modules directory.', () => { 244 | isScopedDependency.mockReturnValue(true); 245 | getScopeForDependency.mockReturnValue('@foo'); 246 | existsSync.mockReturnValueOnce(false); 247 | 248 | dependency.ensureDependencyScopeExists('@foo/bar', '/some/nested/package/path'); 249 | 250 | expect(mkdirSync.mock.calls[0]).toEqual(['/some/nested/package/path/node_modules/@foo']); 251 | }); 252 | 253 | it('should not create the dependency scope directory if the dependency name is not a scoped one.', () => { 254 | isScopedDependency.mockReturnValue(false); 255 | existsSync.mockReturnValueOnce(true); 256 | 257 | dependency.ensureDependencyScopeExists('@foo/bar', '/some/nested/package/path'); 258 | 259 | expect(mkdirSync.mock.calls.length).toEqual(0); 260 | }); 261 | 262 | it('should not create the dependency scope directory if it already exists.', () => { 263 | isScopedDependency.mockReturnValue(false); 264 | getScopeForDependency.mockReturnValue('@foo'); 265 | existsSync.mockReturnValueOnce(true); 266 | 267 | dependency.ensureDependencyScopeExists('@foo/bar', '/some/nested/package/path'); 268 | 269 | expect(mkdirSync.mock.calls.length).toEqual(0); 270 | }); 271 | }); 272 | 273 | describe('dependency.createSymlinkForDependency()', () => { 274 | let ensureDependencyScopeExists; 275 | 276 | beforeEach(() => { 277 | ensureDependencyScopeExists = jest.spyOn(dependency, 'ensureDependencyScopeExists').mockImplementation(jest.fn()); 278 | jest.spyOn(dependency, 'getScopeForDependency').mockImplementation(jest.fn(() => '@foo')); 279 | jest.spyOn(dependency, 'isScopedDependency').mockImplementation(jest.fn(() => false)); 280 | }); 281 | 282 | afterEach(() => { 283 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 284 | jest.restoreAllMocks(); 285 | jest.clearAllMocks(); 286 | }); 287 | 288 | it('should be a function', () => { 289 | expect(typeof dependency.createSymlinkForDependency).toBe('function'); 290 | }); 291 | 292 | it('should call the file.createSymlink method with the source and target path when called.', async () => { 293 | file.existsAsync.mockReturnValueOnce(true).mockReturnValueOnce(false); 294 | 295 | await dependency.createSymlinkForDependency('foo', '/foo', '/foo/bar'); 296 | 297 | expect(file.createSymlink.mock.calls.length).toBe(1); 298 | expect(file.createSymlink.mock.calls[0][0]).toBe('/foo/node_modules/foo'); 299 | expect(file.createSymlink.mock.calls[0][1]).toBe('/foo/bar/node_modules'); 300 | }); 301 | 302 | it('should ensure that the dependencies directory structure exists.', async () => { 303 | file.existsAsync.mockReturnValueOnce(true).mockReturnValueOnce(true); 304 | 305 | await dependency.createSymlinkForDependency('bar', '/foo', '/foo/bar'); 306 | 307 | expect(ensureDependencyScopeExists.mock.calls.length).toBe(1); 308 | expect(ensureDependencyScopeExists.mock.calls[0]).toEqual(['bar', '/foo/bar']); 309 | }); 310 | 311 | it('should not call the file.createSymlink method if the source path does not exist.', async () => { 312 | file.existsAsync.mockReturnValueOnce(false).mockReturnValueOnce(true); 313 | 314 | await dependency.createSymlinkForDependency('baz', '/foo', '/foo/bar'); 315 | 316 | expect(file.createSymlink.mock.calls.length).toBe(0); 317 | }); 318 | 319 | it('should not call the file.createSymlink method if the dist path does already exist.', async () => { 320 | file.existsAsync.mockReturnValueOnce(true).mockReturnValueOnce(true); 321 | 322 | await dependency.createSymlinkForDependency('qux', '/foo', '/foo/bar'); 323 | 324 | expect(file.createSymlink.mock.calls.length).toBe(0); 325 | }); 326 | }); 327 | -------------------------------------------------------------------------------- /src/lib/exec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const exec = require('execa'); 4 | const config = require('./config.js'); 5 | 6 | const execUtils = { 7 | async: exec, 8 | asyncWithRetries: async (...args: Array) => { 9 | const {flowTypedCommandExecRetries} = await config.resolveAndReadConfig(); 10 | let retries = flowTypedCommandExecRetries; 11 | let succeeded = false; 12 | 13 | while (retries-- > 0 && !succeeded) { 14 | try { 15 | await execUtils.async(...args); 16 | succeeded = true; 17 | } catch (e) { 18 | if (retries === 0) { 19 | throw e; 20 | } 21 | } 22 | } 23 | } 24 | }; 25 | 26 | module.exports = execUtils; 27 | -------------------------------------------------------------------------------- /src/lib/exec.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./config.js'); 4 | 5 | const config: any = require('./config.js'); 6 | const exec = require('./exec.js'); 7 | 8 | describe('exec.async()', () => { 9 | it('should be a function', () => { 10 | expect(typeof exec.async).toBe('function'); 11 | }); 12 | }); 13 | 14 | describe('exec.asyncWithRetries()', () => { 15 | let execAsync; 16 | 17 | beforeEach(() => { 18 | execAsync = jest.spyOn(exec, 'async').mockImplementation(jest.fn()); 19 | }); 20 | 21 | afterEach(() => { 22 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 23 | jest.restoreAllMocks(); 24 | jest.clearAllMocks(); 25 | }); 26 | 27 | it('should be a function', () => { 28 | expect(typeof exec.asyncWithRetries).toBe('function'); 29 | }); 30 | 31 | it('should propagate all arguments to the exec.async function', async () => { 32 | config.resolveAndReadConfig.mockReturnValueOnce({ 33 | flowTypedCommandExecRetries: 1 34 | }); 35 | 36 | await exec.asyncWithRetries('foo', 'bar', 'baz'); 37 | 38 | expect(execAsync).toHaveBeenCalledWith('foo', 'bar', 'baz'); 39 | }); 40 | 41 | it('should resolve the retries count from the config and retry the commands execution that many times if it had failed', async () => { 42 | config.resolveAndReadConfig.mockReturnValueOnce({ 43 | flowTypedCommandExecRetries: 2 44 | }); 45 | execAsync.mockImplementationOnce(() => Promise.reject(new Error('first failure'))); 46 | 47 | await exec.asyncWithRetries(); 48 | 49 | expect(execAsync).toHaveBeenCalledTimes(2); 50 | }); 51 | 52 | it('should propagate the error if the command has failed on the last execution', () => { 53 | config.resolveAndReadConfig.mockReturnValueOnce({ 54 | flowTypedCommandExecRetries: 2 55 | }); 56 | execAsync 57 | .mockImplementationOnce(() => Promise.reject('first failure')) // eslint-disable-line prefer-promise-reject-errors 58 | .mockImplementationOnce(() => Promise.reject('second failure')); // eslint-disable-line prefer-promise-reject-errors 59 | 60 | expect(exec.asyncWithRetries()).rejects.toMatch('second failure'); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/lib/file.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const {promisify} = require('util'); 6 | const {error} = require('./logger.js'); 7 | 8 | const utils = { 9 | readFileAsync: promisify(fs.readFile), 10 | writeFileAsync: promisify(fs.writeFile), 11 | accessAsync: promisify(fs.access), 12 | statAsync: promisify(fs.stat), 13 | symlinkAsync: promisify(fs.symlink) 14 | }; 15 | 16 | const fileUtils = { 17 | utils, 18 | 19 | async createSymlink(target: string, distDir: string, relative: boolean) { 20 | const dist = path.join(distDir, path.basename(target)); 21 | const stats = await utils.statAsync(target); 22 | // Use a junction on Windows like Yarn do. 23 | // See: https://github.com/yarnpkg/yarn/blob/fc94a16b7ca90a188d084aef8cea406b60e8c38f/src/util/fs.js#L695-L696 24 | const type = stats.isDirectory() ? 'junction' : 'file'; 25 | 26 | if (relative) { 27 | const targetRelative = path.relative(path.dirname(dist), target); 28 | const currDur = process.cwd(); 29 | process.chdir(distDir); 30 | await utils.symlinkAsync(targetRelative, path.basename(target), type); 31 | process.chdir(currDur); 32 | } else { 33 | await utils.symlinkAsync(target, dist, type); 34 | } 35 | }, 36 | 37 | /** 38 | * Asynchronously checks if a file exists or not. 39 | * 40 | * @param {Array} args Arguments that will be propagated to the fs.stat method. 41 | * @return {Promise} The Promise that resolves with the boolean. 42 | */ 43 | async existsAsync(...args: Array): Promise { 44 | try { 45 | await utils.accessAsync(...args); 46 | return true; 47 | } catch (e) { 48 | return false; 49 | } 50 | }, 51 | 52 | /** 53 | * Reads and parses a json file asynchronously. 54 | * 55 | * @param {String} filePath The Path to the JSON file. 56 | * @return {Promise} The Promise that resolves with the file contents. 57 | */ 58 | async readJson(filePath: string | any, encoding?: string = 'utf8'): Promise { 59 | try { 60 | const contents = await utils.readFileAsync(filePath, encoding); 61 | 62 | return JSON.parse(contents); 63 | } catch (e) { 64 | error(`Failure during parse of "${filePath}".`, e.message); 65 | } 66 | 67 | return {}; 68 | }, 69 | 70 | /** 71 | * Writes the contents to the given destination. 72 | * 73 | * @param {String} filePath The path to the file. 74 | * @param {*} contents The contents to write. 75 | * @param {String} encoding An optional encoding to use. 76 | * @return {Promise} The promise that resolves once the file was written. 77 | */ 78 | async writeFile(filePath: string, contents: any, encoding?: string = 'utf8') { 79 | await utils.writeFileAsync(filePath, contents, encoding); 80 | 81 | return contents; 82 | } 83 | }; 84 | 85 | module.exports = fileUtils; 86 | -------------------------------------------------------------------------------- /src/lib/file.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./logger.js'); 4 | 5 | const logger: any = require('./logger.js'); 6 | const file = require('./file.js'); 7 | 8 | describe('fileUtils.existsAsync()', () => { 9 | let accessAsync; 10 | 11 | beforeEach(() => { 12 | accessAsync = jest.spyOn(file.utils, 'accessAsync').mockImplementation(jest.fn()); 13 | }); 14 | 15 | afterEach(() => { 16 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 17 | jest.restoreAllMocks(); 18 | jest.clearAllMocks(); 19 | }); 20 | 21 | it('should be a function', () => { 22 | expect(typeof file.existsAsync).toBe('function'); 23 | }); 24 | 25 | it('should return a boolean indicating if the filePath exists or not.', async () => { 26 | const exists = await file.existsAsync('/foo/bar/baz.js'); 27 | 28 | expect(exists).toBe(true); 29 | }); 30 | 31 | it('should return a falsy boolean if the fs.access method throw an error.', async () => { 32 | accessAsync.mockReturnValueOnce(Promise.reject(new Error('Does not exist'))); 33 | 34 | const exists = await file.existsAsync('/foo/bar/qux.js'); 35 | 36 | expect(exists).toBe(false); 37 | }); 38 | }); 39 | 40 | describe('fileUtils.readJson()', () => { 41 | let readFileAsync; 42 | let error; 43 | 44 | beforeEach(() => { 45 | readFileAsync = jest.spyOn(file.utils, 'readFileAsync').mockImplementation(jest.fn()); 46 | error = jest.spyOn(logger, 'error').mockImplementation(jest.fn()); 47 | }); 48 | 49 | afterEach(() => { 50 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 51 | jest.restoreAllMocks(); 52 | jest.clearAllMocks(); 53 | }); 54 | 55 | it('should be a function', () => { 56 | expect(typeof file.readJson).toBe('function'); 57 | }); 58 | 59 | it('should return the parsed contents of the given path.', async () => { 60 | readFileAsync.mockReturnValueOnce('{"foo": "bar"}'); 61 | 62 | const json = await file.readJson('/foo/bar/baz.json'); 63 | 64 | expect(json).toEqual({foo: 'bar'}); 65 | }); 66 | 67 | it('should call the error logger method if something went wrong during the parsing.', async () => { 68 | readFileAsync.mockReturnValueOnce('foo'); 69 | 70 | await file.readJson('/foo/bar/baz.json'); 71 | 72 | expect(error.mock.calls.length).toBe(1); 73 | }); 74 | }); 75 | 76 | describe('fileUtils.writeFile()', () => { 77 | let writeFileAsync; 78 | 79 | beforeEach(() => { 80 | writeFileAsync = jest.spyOn(file.utils, 'writeFileAsync').mockImplementation(jest.fn()); 81 | }); 82 | 83 | afterEach(() => { 84 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 85 | jest.restoreAllMocks(); 86 | jest.clearAllMocks(); 87 | }); 88 | 89 | it('should be a function', () => { 90 | expect(typeof file.readJson).toBe('function'); 91 | }); 92 | 93 | it('should call the writeFileAsync method and propagate all arguments to it.', async () => { 94 | await file.writeFile('/foo/bar/baz.json', {foo: 'bar'}); 95 | 96 | expect(writeFileAsync.mock.calls[0]).toEqual(['/foo/bar/baz.json', {foo: 'bar'}, 'utf8']); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /src/lib/flowTyped.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const fs = require('fs'); 4 | const {join} = require('path'); 5 | const cli = require('yargs'); 6 | const exec = require('./exec'); 7 | const { 8 | readPackageJson, 9 | mergeDependenciesIntoMap 10 | } = require('./dependency'); 11 | const {log} = require('./logger'); 12 | 13 | const flowTypedUtils = { 14 | /** 15 | * Asynchronously checks if a file exists or not. 16 | * 17 | * @param {Array} args Arguments that will be propagated to the fs.stat method. 18 | * @return {Promise} The Promise that resolves with the boolean. 19 | */ 20 | parseArgs(argv: {[string]: any} = cli.argv): Array { 21 | const flowTypedInstallArgs = [ 22 | 'flowVersion', 23 | 'overwrite', 24 | 'verbose', 25 | 'skip', 26 | 'packageDir', 27 | 'libdefDir', 28 | 'ignoreDeps' 29 | ]; 30 | 31 | return Object.keys(argv).reduce((args, key) => { 32 | if (flowTypedInstallArgs.includes(key)) { 33 | const val = String(argv[key]); 34 | let arg = `--${key}`; 35 | 36 | if (val && val.length) { 37 | arg += `=${val}`; 38 | } 39 | 40 | args.push(arg); 41 | } 42 | 43 | return args; 44 | }, []); 45 | }, 46 | 47 | /** 48 | * Creates stubs for dependencies of a dependency. This is usefull if a package has it's own flow types that require other packages. 49 | * 50 | * 51 | * @param {[type]} cwd [description] 52 | * @param {[type]} dependencyKey [description] 53 | * @return {Promise} [description] 54 | */ 55 | async createStubsForInDirectDependencies(cwd: string, dependencyKey: string) { 56 | const dependencyPath = join(cwd, 'node_modules', dependencyKey); 57 | const flowConfigPath = join(cwd, '.flowconfig'); 58 | const hasNoFlowConfigInCwd = fs.existsSync(flowConfigPath) === false; 59 | const pkg = await readPackageJson(dependencyPath); 60 | const dependencies = mergeDependenciesIntoMap(pkg); 61 | const dependencyIdentifiers = Object.keys(dependencies) 62 | // Avoid creating stubs for the dependency itself 63 | .filter(key => key !== dependencyKey) 64 | .map(key => `${key}@${dependencies[key]}`); 65 | const dependencyIdentifiersTree = dependencyIdentifiers.map( 66 | (id, index) => `${index === dependencyIdentifiers.length - 1 ? '└──' : '├──'} ${id}` 67 | ); 68 | 69 | // Avoid executing an `flow-typed create-stub` without arguments. 70 | if (!dependencyIdentifiers.length) { 71 | return; 72 | } 73 | 74 | log(dependencyKey); 75 | dependencyIdentifiersTree.forEach(dependencyIdentifier => log(dependencyIdentifier)); 76 | 77 | if (hasNoFlowConfigInCwd) { 78 | fs.writeFileSync(flowConfigPath, '# Intermediate .flowconfig file created by `flow-mono-cli'); 79 | } 80 | 81 | await exec.asyncWithRetries('flow-typed', ['create-stub', ...dependencyIdentifiers], { 82 | preferLocal: true, 83 | localDir: cwd, 84 | cwd 85 | }); 86 | 87 | if (hasNoFlowConfigInCwd) { 88 | fs.unlinkSync(flowConfigPath); 89 | } 90 | } 91 | }; 92 | 93 | module.exports = flowTypedUtils; 94 | -------------------------------------------------------------------------------- /src/lib/flowTyped.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./logger.js'); 4 | jest.mock('./dependency.js'); 5 | jest.mock('./exec.js'); 6 | 7 | const fs = require('fs'); 8 | const exec: any = require('./exec.js'); 9 | const dependency: any = require('./../lib/dependency.js'); 10 | const flowTypedUtils = require('./flowTyped.js'); 11 | 12 | describe('flowTypedUtils.parseArgs()', () => { 13 | it('should be a function', () => { 14 | expect(typeof flowTypedUtils.parseArgs).toBe('function'); 15 | }); 16 | 17 | it('should not fail when executed without arguments.', () => { 18 | expect(() => flowTypedUtils.parseArgs()).not.toThrow(); 19 | }); 20 | 21 | it('should return a list of arguments that can be propagated to flowTyped.', () => { 22 | const args = flowTypedUtils.parseArgs({ 23 | foo: 'bar', 24 | overwrite: '', 25 | ignoreDeps: 'peer' 26 | }); 27 | 28 | expect(args).toEqual(['--overwrite', '--ignoreDeps=peer']); 29 | }); 30 | }); 31 | 32 | describe('flowTypedUtils.createStubsForInDirectDependencies()', () => { 33 | let existsSync; 34 | let writeFileSync; 35 | let unlinkSync; 36 | 37 | beforeEach(() => { 38 | existsSync = jest.spyOn(fs, 'existsSync').mockImplementation(jest.fn()); 39 | writeFileSync = jest.spyOn(fs, 'writeFileSync').mockImplementation(jest.fn()); 40 | unlinkSync = jest.spyOn(fs, 'unlinkSync').mockImplementation(jest.fn()); 41 | }); 42 | 43 | afterEach(() => { 44 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 45 | jest.restoreAllMocks(); 46 | jest.clearAllMocks(); 47 | }); 48 | 49 | it('should be a function', () => { 50 | expect(typeof flowTypedUtils.createStubsForInDirectDependencies).toBe('function'); 51 | }); 52 | 53 | it('should parse the dependencies package json and execute a "flow-type create-stub" command for all resolved in-idrect dependencies.', async () => { 54 | dependency.mergeDependenciesIntoMap.mockReturnValueOnce({ 55 | foo: '1.2.0', 56 | bar: '1.0.0', 57 | baz: '3.20.1' 58 | }); 59 | 60 | await flowTypedUtils.createStubsForInDirectDependencies('/foo/bar', 'some-package'); 61 | 62 | expect(dependency.readPackageJson.mock.calls).toEqual([['/foo/bar/node_modules/some-package']]); 63 | expect(exec.asyncWithRetries.mock.calls[0]).toEqual([ 64 | 'flow-typed', 65 | ['create-stub', 'foo@1.2.0', 'bar@1.0.0', 'baz@3.20.1'], 66 | {cwd: '/foo/bar', localDir: '/foo/bar', preferLocal: true} 67 | ]); 68 | }); 69 | 70 | it('should create a .flowconfig file if none exists in the given cwd since flow-typed would crash otherwise.', async () => { 71 | dependency.mergeDependenciesIntoMap.mockReturnValueOnce({ 72 | foo: '1.2.0', 73 | bar: '1.0.0', 74 | baz: '3.20.1' 75 | }); 76 | existsSync.mockReturnValue(false); 77 | 78 | await flowTypedUtils.createStubsForInDirectDependencies('/foo/bar', 'some-package'); 79 | 80 | expect(writeFileSync.mock.calls).toEqual([ 81 | ['/foo/bar/.flowconfig', '# Intermediate .flowconfig file created by `flow-mono-cli'] 82 | ]); 83 | expect(unlinkSync.mock.calls).toEqual([['/foo/bar/.flowconfig']]); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /src/lib/logger.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const debugLogger = require('debug-logger'); 4 | 5 | debugLogger.levels.info = { 6 | color: debugLogger.colors.blue, 7 | prefix: ' ', 8 | namespaceSuffix: ':info' 9 | }; 10 | 11 | debugLogger.levels.success = { 12 | color: debugLogger.colors.green, 13 | prefix: ' ', 14 | namespaceSuffix: ':success' 15 | }; 16 | 17 | module.exports = debugLogger('flow-mono-cli'); 18 | -------------------------------------------------------------------------------- /src/lib/logger.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const logger = require('./logger.js'); 4 | 5 | describe('logger', () => { 6 | it('should export essential log functions', () => { 7 | expect(typeof logger.info).toBe('function'); 8 | expect(typeof logger.log).toBe('function'); 9 | expect(typeof logger.success).toBe('function'); 10 | expect(typeof logger.error).toBe('function'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/lib/paths.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const {join} = require('path'); 4 | const glob = require('glob'); 5 | const {promisify} = require('util'); 6 | const findUp = require('find-up'); 7 | const file = require('./file.js'); 8 | 9 | const utils = { 10 | findUp, 11 | globAsync: promisify(glob) 12 | }; 13 | 14 | const pathUtils = { 15 | utils, 16 | 17 | /** 18 | * Resolves the mono repo root by traveling up the cwd until it find's the `package.json`. 19 | * 20 | * @return {Promise} The Promise that resolves with the complete path to the mono repo. 21 | */ 22 | async resolveMonoRepoRootPath(): Promise { 23 | const pkgJsonPath = await utils.findUp('package.json'); 24 | 25 | return pkgJsonPath.replace('package.json', ''); 26 | }, 27 | 28 | /** 29 | * Resolves all full paths to the mono repos packages that have a dependency to flow. 30 | * 31 | * @return {Promise} The Promise that resolves with the list of complete paths to all mono repo packages. 32 | */ 33 | async resolveMonoRepoPackagePaths(): Promise> { 34 | const rootPath = await this.resolveMonoRepoRootPath(); 35 | const {workspaces = []} = await file.readJson(join(rootPath, 'package.json')); 36 | const workspacesArray = Array.isArray(workspaces) ? workspaces : workspaces.packages || []; 37 | const packagePaths = []; 38 | 39 | await Promise.all( 40 | workspacesArray.map(async pattern => { 41 | const paths = await utils.globAsync(join(rootPath, pattern)); 42 | 43 | await Promise.all( 44 | paths.map(async packagePath => { 45 | const packageJsonPath = join(packagePath, 'package.json'); 46 | const existsPackageJson = await file.existsAsync(packageJsonPath); 47 | 48 | if (!existsPackageJson) { 49 | return false; 50 | } 51 | 52 | const {dependencies = {}, devDependencies = {}} = await file.readJson(packageJsonPath); 53 | 54 | if (dependencies['flow-bin'] || devDependencies['flow-bin']) { 55 | packagePaths.push(packagePath); 56 | } 57 | 58 | return true; 59 | }) 60 | ); 61 | }) 62 | ); 63 | 64 | return packagePaths; 65 | } 66 | }; 67 | 68 | module.exports = pathUtils; 69 | -------------------------------------------------------------------------------- /src/lib/paths.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | jest.mock('./file.js'); 4 | 5 | const pathUtils = require('./paths.js'); 6 | const file: any = require('./file.js'); 7 | 8 | describe('pathUtils.resolveMonoRepoRootPath()', () => { 9 | beforeEach(() => { 10 | jest.spyOn(pathUtils.utils, 'findUp').mockImplementation(jest.fn(() => '/foo/bar/package.json')); 11 | }); 12 | 13 | afterEach(() => { 14 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 15 | jest.restoreAllMocks(); 16 | jest.clearAllMocks(); 17 | }); 18 | 19 | it('should be a function', () => { 20 | expect(typeof pathUtils.resolveMonoRepoRootPath).toBe('function'); 21 | }); 22 | 23 | it('should resolve the nearest package.json of the process and return its basepath', async () => { 24 | const rootPath = await pathUtils.resolveMonoRepoRootPath(); 25 | 26 | expect(rootPath).toContain('/foo/bar'); 27 | }); 28 | }); 29 | 30 | describe('pathUtils.resolveMonoRepoPackagePaths()', () => { 31 | let globAsync; 32 | 33 | beforeEach(() => { 34 | jest.spyOn(pathUtils, 'resolveMonoRepoRootPath').mockImplementation(jest.fn(() => '/foo/bar')); 35 | globAsync = jest.spyOn(pathUtils.utils, 'globAsync').mockImplementation(jest.fn()); 36 | }); 37 | 38 | afterEach(() => { 39 | // $FlowFixMe: Ignore errors since the jest type-def is out of date. 40 | jest.restoreAllMocks(); 41 | jest.clearAllMocks(); 42 | }); 43 | 44 | it('should be a function', () => { 45 | expect(typeof pathUtils.resolveMonoRepoPackagePaths).toBe('function'); 46 | }); 47 | 48 | it('should resolve the with a list of package paths that have a dependency to "flow-bin"', async () => { 49 | file.readJson.mockReturnValueOnce({workspaces: ['packages/*']}); 50 | globAsync.mockReturnValueOnce(['/foo/bar/package-a', '/foo/bar/package-b', '/foo/bar/package-c']); 51 | file.existsAsync 52 | .mockReturnValueOnce(true) 53 | .mockReturnValueOnce(false) 54 | .mockReturnValueOnce(true); 55 | file.readJson 56 | .mockReturnValueOnce({ 57 | dependencies: {}, 58 | devDependencies: {'flow-bin': '1.1.1'} 59 | }) 60 | .mockReturnValueOnce({ 61 | dependencies: {'flow-bin': '1.1.1'}, 62 | devDependencies: {} 63 | }); 64 | 65 | const packages = await pathUtils.resolveMonoRepoPackagePaths(); 66 | 67 | expect(packages).toEqual(['/foo/bar/package-a', '/foo/bar/package-c']); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /src/lib/updateVersion.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const updateVersion = (obj: Object, dependencyType: string, dependencyKey: string, version: string) => { 4 | const pkgConfig = {...obj}; 5 | if (pkgConfig[dependencyType] && pkgConfig[dependencyType][dependencyKey]) { 6 | pkgConfig[dependencyType][dependencyKey] = version; 7 | } 8 | 9 | return pkgConfig; 10 | }; 11 | 12 | module.exports = updateVersion; 13 | -------------------------------------------------------------------------------- /src/lib/updateVersion.spec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const update = require('./updateVersion'); 4 | 5 | describe('updateVersion()', () => { 6 | let initialPkgConfig; 7 | 8 | beforeEach(() => { 9 | initialPkgConfig = { 10 | dependencies: { 11 | foo: '1.2.2' 12 | } 13 | }; 14 | }); 15 | 16 | it('should update version in correct path', () => { 17 | const updatedPkgConfig = update(initialPkgConfig, 'dependencies', 'foo', '1.4.0'); 18 | 19 | expect(updatedPkgConfig).toMatchObject({ 20 | dependencies: { 21 | foo: '1.4.0' 22 | } 23 | }); 24 | }); 25 | 26 | it('should skip when dependencyType is not available', () => { 27 | const updatedPkgConfig = update(initialPkgConfig, 'foo', 'foo', '1.4.0'); 28 | expect(updatedPkgConfig).toMatchObject({ 29 | dependencies: { 30 | foo: '1.2.2' 31 | } 32 | }); 33 | }); 34 | 35 | it('should skip when dependencyKey is not available', () => { 36 | const updatedPkgConfig = update(initialPkgConfig, 'dependencies', 'bar', '1.4.0'); 37 | expect(updatedPkgConfig).toMatchObject({ 38 | dependencies: { 39 | foo: '1.2.2' 40 | } 41 | }); 42 | }); 43 | }); 44 | --------------------------------------------------------------------------------