diff --git a/lib/utils/explain-eresolve.js b/lib/utils/explain-eresolve.js index fa3c6bda52293..b25e3e4a9ccd0 100644 --- a/lib/utils/explain-eresolve.js +++ b/lib/utils/explain-eresolve.js @@ -9,26 +9,33 @@ const { explainEdge, explainNode, printNode } = require('./explain-dep.js') // The full report (ie, depth=Infinity) is always written to the cache folder // at ${cache}/eresolve-report.txt along with full json. const explain = (expl, color, depth) => { - const { edge, current, peerConflict, currentEdge } = expl + const { edge, dep, current, peerConflict, currentEdge } = expl const out = [] - if (edge.from && edge.from.whileInstalling) - out.push('While resolving: ' + printNode(edge.from.whileInstalling, color)) + const whileInstalling = dep && dep.whileInstalling || + current && current.whileInstalling || + edge && edge.from && edge.from.whileInstalling + if (whileInstalling) + out.push('While resolving: ' + printNode(whileInstalling, color)) // it "should" be impossible for an ERESOLVE explanation to lack both // current and currentEdge, but better to have a less helpful error // than a crashing failure. if (current) out.push('Found: ' + explainNode(current, depth, color)) + else if (peerConflict && peerConflict.current) + out.push('Found: ' + explainNode(peerConflict.current, depth, color)) else if (currentEdge) out.push('Found: ' + explainEdge(currentEdge, depth, color)) + else /* istanbul ignore else - should always have one */ if (edge) + out.push('Found: ' + explainEdge(edge, depth, color)) out.push('\nCould not resolve dependency:\n' + explainEdge(edge, depth, color)) if (peerConflict) { const heading = '\nConflicting peer dependency:' - const pc = explainNode(peerConflict, depth, color) + const pc = explainNode(peerConflict.peer, depth, color) out.push(heading + ' ' + pc) } diff --git a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs index 4c84aaca4ceeb..354081d110319 100644 --- a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs +++ b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs @@ -215,6 +215,142 @@ to accept an incorrect (and potentially broken) dependency resolution. See \${REPORT} for a full report. ` +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with color, depth of 2 1`] = ` +While resolving: eslint-plugin-react@7.24.0 +Found: eslint@6.8.0 +node_modules/eslint + dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project + 3 more (@typescript-eslint/parser, ...) + +Could not resolve dependency: +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Conflicting peer dependency: eslint@7.31.0 +node_modules/eslint + peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1 + node_modules/eslint-plugin-eslint-plugin + dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project +` + +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with no color, depth of 6 1`] = ` +While resolving: eslint-plugin-react@7.24.0 +Found: eslint@6.8.0 +node_modules/eslint + dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project + peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0 + node_modules/@typescript-eslint/parser + dev @typescript-eslint/parser@"^2.34.0" from the root project + peer eslint@"^5.16.0 || ^6.8.0 || ^7.2.0" from eslint-config-airbnb-base@14.2.1 + node_modules/eslint-config-airbnb-base + dev eslint-config-airbnb-base@"^14.2.1" from the root project + 1 more (eslint-plugin-import) + +Could not resolve dependency: +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Conflicting peer dependency: eslint@7.31.0 +node_modules/eslint + peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1 + node_modules/eslint-plugin-eslint-plugin + dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project +` + +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report 1`] = ` +# npm resolution error report + +\${TIME} + +While resolving: eslint-plugin-react@7.24.0 +Found: eslint@6.8.0 +node_modules/eslint + dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project + peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0 + node_modules/@typescript-eslint/parser + dev @typescript-eslint/parser@"^2.34.0" from the root project + peer eslint@"^5.16.0 || ^6.8.0 || ^7.2.0" from eslint-config-airbnb-base@14.2.1 + node_modules/eslint-config-airbnb-base + dev eslint-config-airbnb-base@"^14.2.1" from the root project + peer eslint@"^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" from eslint-plugin-import@2.23.4 + node_modules/eslint-plugin-import + dev eslint-plugin-import@"^2.23.4" from the root project + peer eslint-plugin-import@"^2.22.1" from eslint-config-airbnb-base@14.2.1 + node_modules/eslint-config-airbnb-base + dev eslint-config-airbnb-base@"^14.2.1" from the root project + +Could not resolve dependency: +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Conflicting peer dependency: eslint@7.31.0 +node_modules/eslint + peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1 + node_modules/eslint-plugin-eslint-plugin + dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Fix the upstream dependency conflict, or retry +this command with --force, or --legacy-peer-deps +to accept an incorrect (and potentially broken) dependency resolution. + +Raw JSON explanation object: + +{ + "name": "eslint-plugin case", + "json": true +} + +` + +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with color 1`] = ` +While resolving: eslint-plugin-react@7.24.0 +Found: eslint@6.8.0 +node_modules/eslint + dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project + peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0 + node_modules/@typescript-eslint/parser + dev @typescript-eslint/parser@"^2.34.0" from the root project + 2 more (eslint-config-airbnb-base, eslint-plugin-import) + +Could not resolve dependency: +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Conflicting peer dependency: eslint@7.31.0 +node_modules/eslint + peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1 + node_modules/eslint-plugin-eslint-plugin + dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Fix the upstream dependency conflict, or retry +this command with --force, or --legacy-peer-deps +to accept an incorrect (and potentially broken) dependency resolution. + +See \${REPORT} for a full report. +` + +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with no color 1`] = ` +While resolving: eslint-plugin-react@7.24.0 +Found: eslint@6.8.0 +node_modules/eslint + dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project + peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0 + node_modules/@typescript-eslint/parser + dev @typescript-eslint/parser@"^2.34.0" from the root project + 2 more (eslint-config-airbnb-base, eslint-plugin-import) + +Could not resolve dependency: +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Conflicting peer dependency: eslint@7.31.0 +node_modules/eslint + peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1 + node_modules/eslint-plugin-eslint-plugin + dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project + +Fix the upstream dependency conflict, or retry +this command with --force, or --legacy-peer-deps +to accept an incorrect (and potentially broken) dependency resolution. + +See \${REPORT} for a full report. +` + exports[`test/lib/utils/explain-eresolve.js TAP gatsby > explain with color, depth of 2 1`] = ` While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 @@ -433,6 +569,9 @@ See \${REPORT} for a full report. exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with color, depth of 2 1`] = ` While resolving: eslint@7.22.0 +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 +node_modules/eslint-plugin-jsdoc + dev eslint-plugin-jsdoc@"^22.1.0" from the root project Could not resolve dependency: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 @@ -442,6 +581,9 @@ Could not resolve dependency: exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with no color, depth of 6 1`] = ` While resolving: eslint@7.22.0 +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 +node_modules/eslint-plugin-jsdoc + dev eslint-plugin-jsdoc@"^22.1.0" from the root project Could not resolve dependency: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 @@ -455,6 +597,9 @@ exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge \${TIME} While resolving: eslint@7.22.0 +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 +node_modules/eslint-plugin-jsdoc + dev eslint-plugin-jsdoc@"^22.1.0" from the root project Could not resolve dependency: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 @@ -476,6 +621,9 @@ Raw JSON explanation object: exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with color 1`] = ` While resolving: eslint@7.22.0 +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 +node_modules/eslint-plugin-jsdoc + dev eslint-plugin-jsdoc@"^22.1.0" from the root project Could not resolve dependency: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 @@ -491,6 +639,9 @@ See \${REPORT} for a full report. exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with no color 1`] = ` While resolving: eslint@7.22.0 +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 +node_modules/eslint-plugin-jsdoc + dev eslint-plugin-jsdoc@"^22.1.0" from the root project Could not resolve dependency: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 diff --git a/test/fixtures/eresolve-explanations.js b/test/fixtures/eresolve-explanations.js index b6ccac7d3d627..c34424c7f857a 100644 --- a/test/fixtures/eresolve-explanations.js +++ b/test/fixtures/eresolve-explanations.js @@ -35,43 +35,45 @@ module.exports = { ], }, peerConflict: { - name: '@isaacs/peer-dep-cycle-c', - version: '1.0.0', - whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' }, - location: 'node_modules/@isaacs/peer-dep-cycle-c', - dependents: [ - { - type: 'peer', - name: '@isaacs/peer-dep-cycle-c', - spec: '1', - from: { - name: '@isaacs/peer-dep-cycle-b', - version: '1.0.0', - whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' }, - location: 'node_modules/@isaacs/peer-dep-cycle-b', - dependents: [ - { - type: 'peer', - name: '@isaacs/peer-dep-cycle-b', - spec: '1', - from: { - name: '@isaacs/peer-dep-cycle-a', - version: '1.0.0', - location: 'node_modules/@isaacs/peer-dep-cycle-a', - dependents: [ - { - type: 'prod', - name: '@isaacs/peer-dep-cycle-a', - spec: '1.x', - from: { location: '/some/project' }, - }, - ], + peer: { + name: '@isaacs/peer-dep-cycle-c', + version: '1.0.0', + whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' }, + location: 'node_modules/@isaacs/peer-dep-cycle-c', + dependents: [ + { + type: 'peer', + name: '@isaacs/peer-dep-cycle-c', + spec: '1', + from: { + name: '@isaacs/peer-dep-cycle-b', + version: '1.0.0', + whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' }, + location: 'node_modules/@isaacs/peer-dep-cycle-b', + dependents: [ + { + type: 'peer', + name: '@isaacs/peer-dep-cycle-b', + spec: '1', + from: { + name: '@isaacs/peer-dep-cycle-a', + version: '1.0.0', + location: 'node_modules/@isaacs/peer-dep-cycle-a', + dependents: [ + { + type: 'prod', + name: '@isaacs/peer-dep-cycle-a', + spec: '1.x', + from: { location: '/some/project' }, + }, + ], + }, }, - }, - ], + ], + }, }, - }, - ], + ], + }, }, strictPeerDeps: true, }, @@ -373,4 +375,185 @@ module.exports = { strictPeerDeps: false, force: false, }, + + 'eslint-plugin case': { + code: 'ERESOLVE', + edge: { + type: 'dev', + name: 'eslint-plugin-eslint-plugin', + spec: '^3.1.0', + error: 'MISSING', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + dep: { + name: 'eslint-plugin-eslint-plugin', + version: '3.5.1', + whileInstalling: { + name: 'eslint-plugin-react', + version: '7.24.0', + path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + location: 'node_modules/eslint-plugin-eslint-plugin', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint-plugin-eslint-plugin', + spec: '^3.1.0', + error: 'MISSING', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + ], + }, + current: null, + peerConflict: { + current: { + name: 'eslint', + version: '6.8.0', + location: 'node_modules/eslint', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint', + spec: '^3 || ^4 || ^5 || ^6 || ^7', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + { + type: 'peer', + name: 'eslint', + spec: '^5.0.0 || ^6.0.0', + from: { + name: '@typescript-eslint/parser', + version: '2.34.0', + location: 'node_modules/@typescript-eslint/parser', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: '@typescript-eslint/parser', + spec: '^2.34.0', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + ], + }, + }, + { + type: 'peer', + name: 'eslint', + spec: '^5.16.0 || ^6.8.0 || ^7.2.0', + from: { + name: 'eslint-config-airbnb-base', + version: '14.2.1', + location: 'node_modules/eslint-config-airbnb-base', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint-config-airbnb-base', + spec: '^14.2.1', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + ], + }, + }, + { + type: 'peer', + name: 'eslint', + spec: '^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0', + from: { + name: 'eslint-plugin-import', + version: '2.23.4', + location: 'node_modules/eslint-plugin-import', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint-plugin-import', + spec: '^2.23.4', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + { + type: 'peer', + name: 'eslint-plugin-import', + spec: '^2.22.1', + from: { + name: 'eslint-config-airbnb-base', + version: '14.2.1', + location: 'node_modules/eslint-config-airbnb-base', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint-config-airbnb-base', + spec: '^14.2.1', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + peer: { + name: 'eslint', + version: '7.31.0', + whileInstalling: { + name: 'eslint-plugin-react', + version: '7.24.0', + path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + location: 'node_modules/eslint', + isWorkspace: false, + dependents: [ + { + type: 'peer', + name: 'eslint', + spec: '^7.0.0', + from: { + name: 'eslint-plugin-eslint-plugin', + version: '3.5.1', + whileInstalling: { + name: 'eslint-plugin-react', + version: '7.24.0', + path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + location: 'node_modules/eslint-plugin-eslint-plugin', + isWorkspace: false, + dependents: [ + { + type: 'dev', + name: 'eslint-plugin-eslint-plugin', + spec: '^3.1.0', + error: 'MISSING', + from: { + location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react', + }, + }, + ], + }, + }, + ], + }, + }, + strictPeerDeps: false, + force: false, + isMine: true, + }, }