1// this is called when an ERESOLVE error is caught in the exit-handler, 2// or when there's a log.warn('eresolve', msg, explanation), to turn it 3// into a human-intelligible explanation of what's wrong and how to fix. 4const { explainEdge, explainNode, printNode } = require('./explain-dep.js') 5 6// expl is an explanation object that comes from Arborist. It looks like: 7// Depth is how far we want to want to descend into the object making a report. 8// The full report (ie, depth=Infinity) is always written to the cache folder 9// at ${cache}/eresolve-report.txt along with full json. 10const explain = (expl, chalk, depth) => { 11 const { edge, dep, current, peerConflict, currentEdge } = expl 12 13 const out = [] 14 const whileInstalling = dep && dep.whileInstalling || 15 current && current.whileInstalling || 16 edge && edge.from && edge.from.whileInstalling 17 if (whileInstalling) { 18 out.push('While resolving: ' + printNode(whileInstalling, chalk)) 19 } 20 21 // it "should" be impossible for an ERESOLVE explanation to lack both 22 // current and currentEdge, but better to have a less helpful error 23 // than a crashing failure. 24 if (current) { 25 out.push('Found: ' + explainNode(current, depth, chalk)) 26 } else if (peerConflict && peerConflict.current) { 27 out.push('Found: ' + explainNode(peerConflict.current, depth, chalk)) 28 } else if (currentEdge) { 29 out.push('Found: ' + explainEdge(currentEdge, depth, chalk)) 30 } else /* istanbul ignore else - should always have one */ if (edge) { 31 out.push('Found: ' + explainEdge(edge, depth, chalk)) 32 } 33 34 out.push('\nCould not resolve dependency:\n' + 35 explainEdge(edge, depth, chalk)) 36 37 if (peerConflict) { 38 const heading = '\nConflicting peer dependency:' 39 const pc = explainNode(peerConflict.peer, depth, chalk) 40 out.push(heading + ' ' + pc) 41 } 42 43 return out.join('\n') 44} 45 46// generate a full verbose report and tell the user how to fix it 47const report = (expl, chalk, noColorChalk) => { 48 const flags = [ 49 expl.strictPeerDeps ? '--no-strict-peer-deps' : '', 50 '--force', 51 '--legacy-peer-deps', 52 ].filter(Boolean) 53 54 const or = (arr) => arr.length <= 2 55 ? arr.join(' or ') : 56 arr.map((v, i, l) => i + 1 === l.length ? `or ${v}` : v).join(', ') 57 58 const fix = `Fix the upstream dependency conflict, or retry 59this command with ${or(flags)} 60to accept an incorrect (and potentially broken) dependency resolution.` 61 62 return { 63 explanation: `${explain(expl, chalk, 4)}\n\n${fix}`, 64 file: `# npm resolution error report\n\n${explain(expl, noColorChalk, Infinity)}\n\n${fix}`, 65 } 66} 67 68module.exports = { 69 explain, 70 report, 71} 72