Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRuy Adorno <ruyadorno@hotmail.com>2022-08-01 21:29:56 +0300
committerGitHub <noreply@github.com>2022-08-01 21:29:56 +0300
commit3c024ace60904c69e61da00e1fb56c0c1735804a (patch)
tree20455ad5af7395f9a25943127d6d4ed36421eab7 /lib
parent050284d2abb6aa91a0f9ffad5b0c4f074e5dbf6d (diff)
feat: add npm query cmd (#5000)
Co-authored-by: Gar <gar+gh@danger.computer>
Diffstat (limited to 'lib')
-rw-r--r--lib/commands/query.js104
-rw-r--r--lib/utils/cmd-list.js1
2 files changed, 105 insertions, 0 deletions
diff --git a/lib/commands/query.js b/lib/commands/query.js
new file mode 100644
index 000000000..371fddef9
--- /dev/null
+++ b/lib/commands/query.js
@@ -0,0 +1,104 @@
+'use strict'
+
+const { resolve } = require('path')
+const Arborist = require('@npmcli/arborist')
+const BaseCommand = require('../base-command.js')
+
+class QuerySelectorItem {
+ constructor (node) {
+ // all enumerable properties from the target
+ Object.assign(this, node.target.package)
+
+ // append extra info
+ this.pkgid = node.target.pkgid
+ this.location = node.target.location
+ this.path = node.target.path
+ this.realpath = node.target.realpath
+ this.resolved = node.target.resolved
+ this.from = []
+ this.to = []
+ this.dev = node.target.dev
+ this.inBundle = node.target.inBundle
+ this.deduped = this.from.length > 1
+ for (const edge of node.target.edgesIn) {
+ this.from.push(edge.from.location)
+ }
+ for (const [, edge] of node.target.edgesOut) {
+ if (edge.to) {
+ this.to.push(edge.to.location)
+ }
+ }
+ }
+}
+
+class Query extends BaseCommand {
+ #response = [] // response is the query response
+ #seen = new Set() // paths we've seen so we can keep response deduped
+
+ static description = 'Retrieve a filtered list of packages'
+ static name = 'query'
+ static usage = ['<selector>']
+
+ static ignoreImplicitWorkspace = false
+
+ static params = [
+ 'global',
+ 'workspace',
+ 'workspaces',
+ 'include-workspace-root',
+ ]
+
+ get parsedResponse () {
+ return JSON.stringify(this.#response, null, 2)
+ }
+
+ async exec (args) {
+ // one dir up from wherever node_modules lives
+ const where = resolve(this.npm.dir, '..')
+ const opts = {
+ ...this.npm.flatOptions,
+ path: where,
+ }
+ const arb = new Arborist(opts)
+ const tree = await arb.loadActual(opts)
+ const items = await tree.querySelectorAll(args[0])
+ this.buildResponse(items)
+
+ this.npm.output(this.parsedResponse)
+ }
+
+ async execWorkspaces (args, filters) {
+ await this.setWorkspaces(filters)
+ const opts = {
+ ...this.npm.flatOptions,
+ path: this.npm.prefix,
+ }
+ const arb = new Arborist(opts)
+ const tree = await arb.loadActual(opts)
+ for (const workspacePath of this.workspacePaths) {
+ let items
+ if (workspacePath === tree.root.path) {
+ // include-workspace-root
+ items = await tree.querySelectorAll(args[0])
+ } else {
+ const [workspace] = await tree.querySelectorAll(`.workspace:path(${workspacePath})`)
+ items = await workspace.target.querySelectorAll(args[0])
+ }
+ this.buildResponse(items)
+ }
+ this.npm.output(this.parsedResponse)
+ }
+
+ // builds a normalized inventory
+ buildResponse (items) {
+ for (const node of items) {
+ if (!this.#seen.has(node.target.location)) {
+ const item = new QuerySelectorItem(node)
+ this.#response.push(item)
+ this.#seen.add(item.location)
+ }
+ }
+ }
+}
+
+module.exports = Query
diff --git a/lib/utils/cmd-list.js b/lib/utils/cmd-list.js
index c1d20186a..38439542a 100644
--- a/lib/utils/cmd-list.js
+++ b/lib/utils/cmd-list.js
@@ -114,6 +114,7 @@ const cmdList = [
'profile',
'prune',
'publish',
+ 'query',
'rebuild',
'repo',
'restart',