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.0div, 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 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 SelectorsThe 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])
ObjectsNested objects are expressed as sequential arguments to :attr().
/* return dependencies that have a testling config for opera browsers */*:attr(testling, browsers, [~=opera])
ArraysArrays 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 Objects:/* 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.workspacePlease 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)})