1// when an optional dep fails to install, we need to remove the branch of the
2// graph up to the first optionalDependencies, as well as any nodes that are
3// only required by other nodes in the set.
4//
5// This function finds the set of nodes that will need to be removed in that
6// case.
7//
8// Note that this is *only* going to work with trees where calcDepFlags
9// has been called, because we rely on the node.optional flag.
10
11const gatherDepSet = require('./gather-dep-set.js')
12const optionalSet = node => {
13  if (!node.optional) {
14    return new Set()
15  }
16
17  // start with the node, then walk up the dependency graph until we
18  // get to the boundaries that define the optional set.  since the
19  // node is optional, we know that all paths INTO this area of the
20  // graph are optional, but there may be non-optional dependencies
21  // WITHIN the area.
22  const set = new Set([node])
23  for (const node of set) {
24    for (const edge of node.edgesIn) {
25      if (!edge.optional) {
26        set.add(edge.from)
27      }
28    }
29  }
30
31  // now that we've hit the boundary, gather the rest of the nodes in
32  // the optional section.  that's the set of dependencies that are only
33  // depended upon by other nodes within the set, or optional dependencies
34  // from outside the set.
35  return gatherDepSet(set, edge => !edge.optional)
36}
37
38module.exports = optionalSet
39