Dependency Selector Syntax & Querying
Dependency Selector Syntax & QueryingVersion 8.19.2 (Latest Release)
- Version 8.19.2 (Latest Release)
- Version 9.0.0 (Current Release)
Description
The npm query commmand exposes a new dependency selector syntax (informed by & respecting many aspects of the CSS Selectors 4 Spec) which:
- Standardizes the shape of, & querying of, dependency graphs with a robust object model, metadata & selector syntax
- Leverages existing, known language syntax & operators from CSS to make disparate package information broadly accessible
- Unlocks the ability to answer complex, multi-faceted questions about dependencies, their relationships & associative metadata
- Consolidates redundant logic of similar query commands in npm(ex.npm fund,npm ls,npm outdated,npm audit...)
Dependency Selector Syntax v1.0.0
Overview:
- there is no "type" or "tag" selectors (ex. div, h1, a) as a dependency/target is the only type ofNodethat can be queried
- the term "dependencies" is in reference to any Nodefound in atreereturned byArborist
Combinators
- >direct descendant/child
- ~sibling
Selectors
- *universal selector
- #<name>dependency selector (equivalent to- [name="..."])
- #<name>@<version>(equivalent to- [name=<name>]:semver(<version>))
- ,selector list delimiter
- .dependency type selector
- :pseudo selector
Dependency Type Selectors
- .proddependency found in the- dependenciessection of- package.json, or is a child of said dependency
- .devdependency found in the- devDependenciessection of- package.json, or is a child of said dependency
- .optionaldependency found in the- optionalDependenciessection of- package.json, or has- "optional": trueset in its entry in the- peerDependenciesMetasection of- package.json, or a child of said dependency
- .peerdependency found in the- peerDependenciessection of- package.json
- .workspacedependency found in the- workspacessection of- package.json
- .bundleddependency found in the- bundleDependenciessection of- package.json, or is a child of said dependency
Pseudo Selectors
- :not(<selector>)
- :has(<selector>)
- :is(<selector list>)
- :rootmatches the root node/dependency
- :scopematches node/dependency it was queried against
- :emptywhen a dependency has no dependencies
- :privatewhen a dependency is private
- :linkwhen a dependency is linked (for instance, workspaces or packages manually- linked
- :dedupedwhen a dependency has been deduped (note that this does not always mean the dependency has been hoisted to the root of node_modules)
- :overriddenwhen a dependency has been overridden
- :extraneouswhen a dependency exists but is not defined as a dependency of any node
- :invalidwhen a dependency version is out of its ancestors specified range
- :missingwhen a dependency is not found on disk
- :semver(<spec>)matching a valid- node-semverspec
- :path(<path>)glob matching based on dependencies path relative to the project
- :type(<type>)based on currently recognized types
Attribute Selectors
The attribute selector evaluates the key/value pairs in package.json if they are Strings.
- []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 Selectors
The generic :attr() pseudo selector standardizes a pattern which can be used for attribute selection of Objects, Arrays or Arrays of Objects 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])
Nested 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
Arrays 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.
Example of an 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]))
Example of an Array matching directly to a value:
/* return dependencies that have the exact keyword "react" *//* this is equivalent to `*:keywords([value="react"])` */*:attr([keywords=react])
Example of an Array of Objects:
/* returns */*:attr(contributors, [email=ruyadorno@github.com])
Groups
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.
Programmatic Usage
- Arborist's- NodeClass has a- .querySelectorAll()method- this method will return a filtered, flattened dependency Arborist Nodelist based on a valid query selector
 
- this method will return a filtered, flattened dependency Arborist 
const 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)})