diff options
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.js | 94 |
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 |