The npm query
commmand exposes a new dependency selector syntax (informed by & respecting many aspects of the CSS Selectors 4 Spec) which:
npm
(ex. npm fund
, npm ls
, npm outdated
, npm audit
...)v1.0.0
div, h1, a
) as a dependency/target is the only type of Node
that can be queriedNode
found in a tree
returned by Arborist
>
direct descendant/child
any descendant/child~
sibling*
universal selector#<name>
dependency selector (equivalent to [name="..."]
)#<name>@<version>
(equivalent to [name=<name>]:semver(<version>)
),
selector list delimiter.
dependency type selector:
pseudo selector.prod
dependency found in the dependencies
section of package.json
, or is a child of said dependency.dev
dependency found in the devDependencies
section of package.json
, or is a child of said dependency.optional
dependency found in the optionalDependencies
section of package.json
, or has "optional": true
set in its entry in the peerDependenciesMeta
section of package.json
, or a child of said dependency.peer
dependency found in the peerDependencies
section of package.json
.workspace
dependency found in the workspaces
section of package.json
.bundled
dependency found in the bundleDependencies
section of package.json
, or is a child of said dependency:not(<selector>)
:has(<selector>)
:is(<selector list>)
:root
matches the root node/dependency:scope
matches node/dependency it was queried against:empty
when a dependency has no dependencies:private
when a dependency is private:link
when a dependency is linked (for instance, workspaces or packages manually linked
:deduped
when a dependency has been deduped (note that this does not always mean the dependency has been hoisted to the root of node_modules):overridden
when a dependency has been overridden:extraneous
when a dependency exists but is not defined as a dependency of any node:invalid
when a dependency version is out of its ancestors specified range:missing
when a dependency is not found on disk:semver(<spec>)
matching a valid node-semver
spec:path(<path>)
glob matching based on dependencies path relative to the project:type(<type>)
based on currently recognized typesThe attribute selector evaluates the key/value pairs in package.json
if they are String
s.
[]
attribute selector (ie. existence of attribute)[attribute=value]
attribute value is equivalant...[attribute~=value]
attribute value contains word...[attribute*=value]
attribute value contains string...[attribute|=value]
attribute value is equal to or starts with...[attribute^=value]
attribute value starts with...[attribute$=value]
attribute value ends with...Array
& Object
Attribute SelectorsThe generic :attr()
pseudo selector standardizes a pattern which can be used for attribute selection of Object
s, Array
s or Arrays
of Object
s accessible via Arborist
's Node.package
metadata. This allows for iterative attribute selection beyond top-level String
evaluation. The last argument passed to :attr()
must be an attribute
selector or a nested :attr()
. See examples below:
Objects
/* return dependencies that have a `scripts.test` containing `"tap"` */*:attr(scripts, [test~=tap])
Objects
Nested objects are expressed as sequential arguments to :attr()
.
/* return dependencies that have a testling config for opera browsers */*:attr(testling, browsers, [~=opera])
Arrays
Array
s specifically uses a special/reserved .
character in place of a typical attribute name. Arrays
also support exact value
matching when a String
is passed to the selector.
Array
Attribute Selection:/* removes the distinction between properties & arrays *//* ie. we'd have to check the property & iterate to match selection */*:attr([keywords^=react])*:attr(contributors, :attr([name~=Jordan]))
Array
matching directly to a value:/* return dependencies that have the exact keyword "react" *//* this is equivalent to `*:keywords([value="react"])` */*:attr([keywords=react])
Array
of Object
s:/* returns */*:attr(contributors, [email=ruyadorno@github.com])
Dependency groups are defined by the package relationships to their ancestors (ie. the dependency types that are defined in package.json
). This approach is user-centric as the ecosystem has been taught to think about dependencies in these groups first-and-foremost. Dependencies are allowed to be included in multiple groups (ex. a prod
dependency may also be a dev
dependency (in that it's also required by another dev
dependency) & may also be bundled
- a selector for that type of dependency would look like: *.prod.dev.bundled
).
.prod
.dev
.optional
.peer
.bundled
.workspace
Please note that currently workspace
deps are always prod
dependencies. Additionally the .root
dependency is also considered a prod
dependency.
Arborist
's Node
Class has a .querySelectorAll()
methodNode
list based on a valid query selectorconst Arborist = require('@npmcli/arborist')const arb = new Arborist({})
// root-levelarb.loadActual().then(async (tree) => {// query all production dependenciesconst results = await tree.querySelectorAll('.prod')console.log(results)})
// iterativearb.loadActual().then(async (tree) => {// query for the deduped version of reactconst results = await tree.querySelectorAll('#react:not(:deduped)')// query the deduped react for git depsconst deps = await results[0].querySelectorAll(':type(git)')console.log(deps)})