diff --git a/cli/src/commands/__tests__/install-test.js b/cli/src/commands/__tests__/install-test.js index 11a6e02daa..3e2c7b1bc0 100644 --- a/cli/src/commands/__tests__/install-test.js +++ b/cli/src/commands/__tests__/install-test.js @@ -969,6 +969,68 @@ describe('install (command)', () => { }); }); + it("doesn't install definitions if ignored with flow-typed.config.js", () => { + return fakeProjectEnv(async FLOWPROJ_DIR => { + // Create some dependencies + await Promise.all([ + mkdirp(path.join(FLOWPROJ_DIR, 'src')), + writePkgJson(path.join(FLOWPROJ_DIR, 'package.json'), { + name: 'test', + devDependencies: { + 'flow-bin': '^0.43.0', + }, + dependencies: { + '@scoped/package': '1.2.3', + foo: '1.2.3', + }, + }), + mkdirp(path.join(FLOWPROJ_DIR, 'node_modules', 'foo')), + mkdirp(path.join(FLOWPROJ_DIR, 'node_modules', 'flow-bin')), + ]); + + await touchFile(path.join(FLOWPROJ_DIR, 'src', '.flowconfig')); + await mkdirp(path.join(FLOWPROJ_DIR, 'src', 'flow-typed')); + await touchFile( + path.join(FLOWPROJ_DIR, 'src', 'flow-typed.config.json'), + ); + await fs.writeJson( + path.join(FLOWPROJ_DIR, 'src', 'flow-typed.config.json'), + {ignore: ['foo', '@scoped']}, + ); + + // Run the install command + await run({ + ...defaultRunProps, + rootDir: path.join(FLOWPROJ_DIR, 'src'), + }); + + // Installs libdef + expect( + await fs.exists( + path.join( + FLOWPROJ_DIR, + 'src', + 'flow-typed', + 'npm', + '@scoped', + 'package_vx.x.x.js', + ), + ), + ).toEqual(false); + expect( + await fs.exists( + path.join( + FLOWPROJ_DIR, + 'src', + 'flow-typed', + 'npm', + 'foo_vx.x.x.js', + ), + ), + ).toEqual(false); + }); + }); + it('treats dependency prefixed with `>=` the same as `^`', () => { return fakeProjectEnv(async FLOWPROJ_DIR => { // Create some dependencies diff --git a/cli/src/commands/install.js b/cli/src/commands/install.js index dc1882e0ee..58530fe4be 100644 --- a/cli/src/commands/install.js +++ b/cli/src/commands/install.js @@ -190,6 +190,7 @@ export async function run(args: Args): Promise { skipCache: Boolean(args.skipCache), ignoreDeps: ignoreDeps, useCacheUntil: Number(args.useCacheUntil) || CACHE_REPO_EXPIRY, + ftConfig, }); if (npmLibDefResult !== 0) { return npmLibDefResult; @@ -348,6 +349,7 @@ type installNpmLibDefsArgs = {| skipCache: boolean, ignoreDeps: Array, useCacheUntil: number, + ftConfig?: FtConfig, |}; async function installNpmLibDefs({ cwd, @@ -360,6 +362,7 @@ async function installNpmLibDefs({ skipCache, ignoreDeps, useCacheUntil, + ftConfig = {}, }: installNpmLibDefsArgs): Promise { const flowProjectRoot = await findFlowRoot(cwd); if (flowProjectRoot === null) { @@ -374,17 +377,22 @@ async function installNpmLibDefs({ const libdefsToSearchFor: Map = new Map(); let ignoreDefs; - try { - ignoreDefs = fs - .readFileSync(path.join(cwd, libdefDir, '.ignore'), 'utf-8') - .replace(/"/g, '') - .split('\n'); - } catch (err) { - // If the error is unrelated to file not existing we should continue throwing - if (err.code !== 'ENOENT') { - throw err; + + if (Array.isArray(ftConfig.ignore)) { + ignoreDefs = ftConfig.ignore; + } else { + try { + ignoreDefs = fs + .readFileSync(path.join(cwd, libdefDir, '.ignore'), 'utf-8') + .replace(/"/g, '') + .split('\n'); + } catch (err) { + // If the error is unrelated to file not existing we should continue throwing + if (err.code !== 'ENOENT') { + throw err; + } + ignoreDefs = []; } - ignoreDefs = []; } // If a specific pkg/version was specified, only add those packages. diff --git a/cli/src/lib/ftConfig.js b/cli/src/lib/ftConfig.js index 4477e07e1a..bec216df55 100644 --- a/cli/src/lib/ftConfig.js +++ b/cli/src/lib/ftConfig.js @@ -3,6 +3,7 @@ import {fs, path} from './node'; export type FtConfig = { env?: mixed, // Array, + ignore?: Array, }; export const getFtConfig = (cwd: string): FtConfig | void => { diff --git a/docs/flow-typed-config.md b/docs/flow-typed-config.md index 2d30aa9cd8..8c83600d33 100644 --- a/docs/flow-typed-config.md +++ b/docs/flow-typed-config.md @@ -8,10 +8,20 @@ Flow-typed supports a config file to help you set various project level settings `env` accepts an array of strings that map to environment definitions that you can you can find [here](https://github.com/flow-typed/flow-typed/tree/master/definitions/environments). -```json +```js { - "env": ["jsx", "node"] + env: ['jsx', 'node'], } ``` Learn more about [environment definitions](env-definitions.md) + +## ignore + +When you have a dependencies you don't want updated or swapped out during the `install` command you can add this property which takes an array of strings referencing either package scopes or package names explicitly to ignore. + +```js +{ + ignore: ['@babel', '@custom/', 'eslint', 'eslint-plugin-ft-flow'] +} +``` diff --git a/docs/install.md b/docs/install.md index 19ed5e8e08..e60962d6f6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -31,8 +31,11 @@ flow-typed install --ignoreDeps peer bundle ### Ignoring dependencies -Sometimes you will come across dependencies that you both don't use in code and aren't defined in `flow-typed`, `@babel/core` is a good example and you don't want it polluting your codebase or causing unnecessarily large diffs during updates. Alternatively you may have some specific libdef version different to what is referenced in package.json and you don't want that swapped out. +Sometimes you will come across dependencies that you both don't use in code and aren't defined in `flow-typed`. `@babel/core` is a good example of this where you don't want it polluting your codebase or causing unnecessarily large diffs during updates. Alternatively you may have some specific libdef version different to what is referenced in package.json and you don't want that swapped out. +You can achieve this with the `ignore` property in [flow-typed.config.js](flow-typed-config.md) + +#### .ignore _(deprecated)_ The `.ignore` file which you can place in `./flow-typed` can solve this by referencing scopes or packages you'd like to explicitly exclude when `flow-typed` tries to install/update libdefs for you. ```