Dependency Selector Syntax & Querying
Select CLI Version:
See Details
Table of contents
Description
Thenpm query commmand exposes a new dependency selector syntax (informed by & respecting many aspects of theCSS 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 Syntaxv1.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/childany 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 thedependenciessection ofpackage.json, or is a child of said dependency.devdependency found in thedevDependenciessection ofpackage.json, or is a child of said dependency.optionaldependency found in theoptionalDependenciessection ofpackage.json, or has"optional": trueset in its entry in thepeerDependenciesMetasection ofpackage.json, or a child of said dependency.peerdependency found in thepeerDependenciessection ofpackage.json.workspacedependency found in theworkspacessection ofpackage.json.bundleddependency found in thebundleDependenciessection ofpackage.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 manuallylinked:dedupedwhen a dependency has been deduped (note that this doesnot 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 validnode-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 inpackage.json if they areStrings.
[]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 ofObjects,Arrays orArrays ofObjects accessible viaArborist'sNode.package metadata. This allows for iterative attribute selection beyond top-levelString evaluation. The last argument passed to:attr() must be anattribute selector or a nested:attr(). See examples below:
Objects
/* return dependencies that have a `scripts.test` containing `"tap"` */*:attr(scripts, [test~=tap]);
NestedObjects
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 exactvalue matching when aString is passed to the selector.
Example of anArray 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 anArray 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 anArray ofObjects:
/* 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 inpackage.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. aprod dependency may also be adev dependency (in that it's also required by anotherdev dependency) & may also bebundled - a selector for that type of dependency would look like:*.prod.dev.bundled).
.prod.dev.optional.peer.bundled.workspace
Please note that currentlyworkspace deps are alwaysprod dependencies. Additionally the.root dependency is also considered aprod dependency.
Programmatic Usage
Arborist'sNodeClass 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
constArborist=require("@npmcli/arborist");const arb=newArborist({});
// 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);});
