Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
explain.js129 linesDownload Raw Back to commands
1const { explainNode } = require('../utils/explain-dep.js')
2const npa = require('npm-package-arg')
3const semver = require('semver')
4const { relative, resolve } = require('node:path')
5const validName = require('validate-npm-package-name')
6const { output } = require('proc-log')
7const ArboristWorkspaceCmd = require('../arborist-cmd.js')
8
9class Explain extends ArboristWorkspaceCmd {
10  static description = 'Explain installed packages'
11  static name = 'explain'
12  static usage = ['<package-spec>']
13  static params = [
14    'json',
15    'workspace',
16  ]
17
18  static ignoreImplicitWorkspace = false
19
20  static async completion (opts, npm) {
21    const completion = require('../utils/installed-deep.js')
22    return completion(npm, opts)
23  }
24
25  async exec (args) {
26    if (!args.length) {
27      throw this.usageError()
28    }
29
30    const Arborist = require('@npmcli/arborist')
31    const arb = new Arborist({ path: this.npm.prefix, ...this.npm.flatOptions })
32    const tree = await arb.loadActual()
33
34    if (this.npm.flatOptions.workspacesEnabled
35      && this.workspaceNames
36      && this.workspaceNames.length
37    ) {
38      this.filterSet = arb.workspaceDependencySet(tree, this.workspaceNames)
39    } else if (!this.npm.flatOptions.workspacesEnabled) {
40      this.filterSet =
41        arb.excludeWorkspacesDependencySet(tree)
42    }
43
44    const nodes = new Set()
45    for (const arg of args) {
46      for (const node of this.getNodes(tree, arg)) {
47        const filteredOut = this.filterSet
48          && this.filterSet.size > 0
49          && !this.filterSet.has(node)
50        if (!filteredOut) {
51          nodes.add(node)
52        }
53      }
54    }
55    if (nodes.size === 0) {
56      throw new Error(`No dependencies found matching ${args.join(', ')}`)
57    }
58
59    const expls = []
60    for (const node of nodes) {
61      const { extraneous, dev, optional, devOptional, peer, inBundle, overridden } = node
62      const expl = node.explain()
63      if (extraneous) {
64        expl.extraneous = true
65      } else {
66        expl.dev = dev
67        expl.optional = optional
68        expl.devOptional = devOptional
69        expl.peer = peer
70        expl.bundled = inBundle
71        expl.overridden = overridden
72      }
73      expls.push(expl)
74    }
75
76    if (this.npm.flatOptions.json) {
77      output.buffer(expls)
78    } else {
79      output.standard(expls.map(expl => {
80        return explainNode(expl, Infinity, this.npm.chalk)
81      }).join('\n\n'))
82    }
83  }
84
85  getNodes (tree, arg) {
86    // if it's just a name, return packages by that name
87    const { validForOldPackages: valid } = validName(arg)
88    if (valid) {
89      return tree.inventory.query('packageName', arg)
90    }
91
92    // if it's a location, get that node
93    const maybeLoc = arg.replace(/\\/g, '/').replace(/(?<!\/)\/+$/, '')
94    const nodeByLoc = tree.inventory.get(maybeLoc)
95    if (nodeByLoc) {
96      return [nodeByLoc]
97    }
98
99    // maybe a path to a node_modules folder
100    const maybePath = relative(this.npm.prefix, resolve(maybeLoc))
101      .replace(/\\/g, '/').replace(/(?<!\/)\/+$/, '')
102    const nodeByPath = tree.inventory.get(maybePath)
103    if (nodeByPath) {
104      return [nodeByPath]
105    }
106
107    // otherwise, try to select all matching nodes
108    try {
109      return this.getNodesByVersion(tree, arg)
110    } catch {
111      return []
112    }
113  }
114
115  getNodesByVersion (tree, arg) {
116    const spec = npa(arg, this.npm.prefix)
117    if (spec.type !== 'version' && spec.type !== 'range') {
118      return []
119    }
120
121    return tree.inventory.filter(node => {
122      return node.package.name === spec.name &&
123        semver.satisfies(node.package.version, spec.rawSpec)
124    })
125  }
126}
127
128module.exports = Explain
129 
codekingpro/portable-devtools · Team Ai