summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js')
-rw-r--r--deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js94
1 files changed, 94 insertions, 0 deletions
diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js b/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
new file mode 100644
index 0000000000..73f1e60d7c
--- /dev/null
+++ b/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
@@ -0,0 +1,94 @@
+const { depth } = require('treeverse')
+
+const calcDepFlags = (tree, resetRoot = true) => {
+ if (resetRoot) {
+ tree.dev = false
+ tree.optional = false
+ tree.devOptional = false
+ tree.peer = false
+ }
+ const ret = depth({
+ tree,
+ visit: node => calcDepFlagsStep(node),
+ filter: node => node,
+ getChildren: node => [...node.edgesOut.values()].map(edge => edge.to),
+ })
+ return ret
+}
+
+const calcDepFlagsStep = (node) => {
+ // This rewalk is necessary to handle cases where devDep and optional
+ // or normal dependency graphs overlap deep in the dep graph.
+ // Since we're only walking through deps that are not already flagged
+ // as non-dev/non-optional, it's typically a very shallow traversal
+ node.extraneous = false
+
+ // for links, map their hierarchy appropriately
+ if (node.target) {
+ node.target.dev = node.dev
+ node.target.optional = node.optional
+ node.target.devOptional = node.devOptional
+ node.target.peer = node.peer
+ node.target.extraneous = false
+ node = node.target
+ }
+
+ node.edgesOut.forEach(({peer, optional, dev, to}) => {
+ // if the dep is missing, then its flags are already maximally unset
+ if (!to)
+ return
+
+ // everything with any kind of edge into it is not extraneous
+ to.extraneous = false
+
+ // devOptional is the *overlap* of the dev and optional tree.
+ // however, for convenience and to save an extra rewalk, we leave
+ // it set when we are in *either* tree, and then omit it from the
+ // package-lock if either dev or optional are set.
+ const unsetDevOpt = !node.devOptional && !node.dev && !node.optional &&
+ !dev && !optional
+
+ // if we are not in the devOpt tree, then we're also not in
+ // either the dev or opt trees
+ const unsetDev = unsetDevOpt || !node.dev && !dev
+ const unsetOpt = unsetDevOpt ||
+ !node.optional && !optional
+ const unsetPeer = !node.peer && !peer
+
+ if (unsetPeer)
+ unsetFlag(to, 'peer')
+
+ if (unsetDevOpt)
+ unsetFlag(to, 'devOptional')
+
+ if (unsetDev)
+ unsetFlag(to, 'dev')
+
+ if (unsetOpt)
+ unsetFlag(to, 'optional')
+ })
+
+ return node
+}
+
+// typically a short walk, since it only traverses deps that
+// have the flag set.
+const unsetFlag = (node, flag) => {
+ if (node[flag]) {
+ node[flag] = false
+ depth({
+ tree: node,
+ visit: node => {
+ node.extraneous = node[flag] = false
+ if (node.target)
+ node.target.extraneous = node.target[flag] = false
+ },
+ getChildren: node => [...(node.target || node).edgesOut.values()]
+ .filter(edge => edge.to && edge.to[flag] &&
+ (flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod'))
+ .map(edge => edge.to),
+ })
+ }
+}
+
+module.exports = calcDepFlags