• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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