From 5ba68391a7d42d29909c0b47c325cecee5fd2903 Mon Sep 17 00:00:00 2001 From: Stanislav Beresnev Date: Thu, 31 May 2018 12:42:08 +0200 Subject: [PATCH] feat(resolutions): yarn resolutions support added --- README.md | 10 +++++++ __tests__/check-peer-deps.test.js | 7 +++++ .../fixtures/peerDepWithResolution/.gitignore | 1 + .../eslint-config-airbnb-base/package.json | 6 +++++ .../node_modules/eslint/package.json | 3 +++ .../peerDepWithResolution/package.json | 9 +++++++ check-peer-deps.js | 27 +++++++++++++++++++ 7 files changed, 63 insertions(+) create mode 100644 __tests__/fixtures/peerDepWithResolution/.gitignore create mode 100644 __tests__/fixtures/peerDepWithResolution/node_modules/eslint-config-airbnb-base/package.json create mode 100644 __tests__/fixtures/peerDepWithResolution/node_modules/eslint/package.json create mode 100644 __tests__/fixtures/peerDepWithResolution/package.json diff --git a/README.md b/README.md index 8f373ce..0cfb195 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,13 @@ allowing a potential issue to arise if `eslint@4.6.0` was installed and not updated before installing. The output also tells you that although the _minimum_ allowed version is too low, the _maximum_ allowed version does satisfy the `peerDependencies` requirement. + + +If you use resolutions section in your package.json file in order to resolve some unmet peer dependencies +and want the program to take it into the account run it with include-resolutions option: + +``` +> check-peer-deps --include-resolutions=true +``` + +Read more about resolutions: https://yarnpkg.com/lang/en/docs/selective-version-resolutions/ diff --git a/__tests__/check-peer-deps.test.js b/__tests__/check-peer-deps.test.js index 7f6ee35..84ca4d1 100644 --- a/__tests__/check-peer-deps.test.js +++ b/__tests__/check-peer-deps.test.js @@ -40,3 +40,10 @@ test('Finds nothing wrong with no peerDependencies in the tree', async () => { expect(output.stdout).toBe(''); expect(output.stderr).toBe(''); }); + +test('Finds nothing wrong with a broken dependency tree backed up with resolutions', async () => { + expect.assertions(2); + const output = await runCPD(['--include-resolutions=true'], { cwd: path.join(fixtures, 'peerDepWithResolution') }); + expect(output.stdout).toBe(''); + expect(output.stderr).toBe(''); +}); diff --git a/__tests__/fixtures/peerDepWithResolution/.gitignore b/__tests__/fixtures/peerDepWithResolution/.gitignore new file mode 100644 index 0000000..ddf3424 --- /dev/null +++ b/__tests__/fixtures/peerDepWithResolution/.gitignore @@ -0,0 +1 @@ +!node_modules/ diff --git a/__tests__/fixtures/peerDepWithResolution/node_modules/eslint-config-airbnb-base/package.json b/__tests__/fixtures/peerDepWithResolution/node_modules/eslint-config-airbnb-base/package.json new file mode 100644 index 0000000..fe01853 --- /dev/null +++ b/__tests__/fixtures/peerDepWithResolution/node_modules/eslint-config-airbnb-base/package.json @@ -0,0 +1,6 @@ +{ + "version": "12.1.0", + "peerDependencies": { + "eslint": "4.0.9" + } +} diff --git a/__tests__/fixtures/peerDepWithResolution/node_modules/eslint/package.json b/__tests__/fixtures/peerDepWithResolution/node_modules/eslint/package.json new file mode 100644 index 0000000..c362453 --- /dev/null +++ b/__tests__/fixtures/peerDepWithResolution/node_modules/eslint/package.json @@ -0,0 +1,3 @@ +{ + "version": "4.9.0" +} diff --git a/__tests__/fixtures/peerDepWithResolution/package.json b/__tests__/fixtures/peerDepWithResolution/package.json new file mode 100644 index 0000000..05e5bd2 --- /dev/null +++ b/__tests__/fixtures/peerDepWithResolution/package.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "eslint": "4.9.0", + "eslint-config-airbnb-base": "12.1.0" + }, + "resolutions": { + "eslint-config-airbnb-base/eslint": "4.0.9" + } +} diff --git a/check-peer-deps.js b/check-peer-deps.js index 58c073b..81b1579 100644 --- a/check-peer-deps.js +++ b/check-peer-deps.js @@ -28,6 +28,11 @@ const optionDefinitions = [ 'peerDependency has been satisfied', defaultValue: false, }, + { + name: 'include-resolutions', + description: 'Check for resolutions section of package.json when checking whether a peerDependency has been satisfied', + defaultValue: false, + }, { name: 'max-retries', description: 'Specify how many retries are allowed for [underline]{npm} commands', @@ -63,6 +68,7 @@ let options; const deps = new Map(); const npmVers = new Map(); const peerDeps = new Map(); +const resolutions = new Map(); const log = (value) => { if (options.debug) { @@ -80,6 +86,16 @@ const addDeps = (dependencies) => { }); }; +const addResolutions = (res) => { + if (!res) { + return; + } + Object.entries(res).forEach((entry) => { + const [name, range] = entry; + resolutions.set(name, range); + }); +}; + const readPackageConfig = async (path) => { let packageConfig = {}; try { @@ -206,6 +222,13 @@ const checkPeerDependencies = async (peerDependencies, name) => } } + if (resolutions.has(`${name}/${peerDepName}`)) { + const minAllowedVer = resolutions.get(`${name}/${peerDepName}`); + if (semver.satisfies(minAllowedVer, peerDepRange)) { + found = true; + } + } + if (!found) { console.error(`A dependency satisfying ${name}'s peerDependency of '${peerDepName}@${peerDepRange}' was not found!`); @@ -232,6 +255,10 @@ const findDependencies = async () => { // Get the dependencies to process addDeps(packageConfig.dependencies); + if (options['include-resolutions'] && packageConfig.resolutions) { + addResolutions(packageConfig.resolutions); + } + if (!options['no-include-dev'] && packageConfig.devDependencies) { addDeps(packageConfig.devDependencies); }