Dependency Selector Syntax & Querying

Dependency Selector Syntax & Querying

Table of contents

Description

The npm query command exposes a new dependency selector syntax (informed by & respecting many aspects of the CSS Selectors 4 Spec) which:

Dependency Selector Syntax

Overview:

Combinators

Selectors

Dependency Type Selectors

Pseudo Selectors

:semver(<spec>, [selector], [function])

The :semver() pseudo selector allows comparing fields from each node's package.json using semver methods. It accepts up to 3 parameters, all but the first of which are optional.

When the special infer function is used the spec and the actual value from the node are compared. If both are versions, according to semver.valid(), eq is used. If both values are ranges, according to !semver.valid(), intersects is used. If the values are mixed types satisfies is used.

Some examples:

:outdated(<type>)

The :outdated pseudo selector retrieves data from the registry and returns information about which of your dependencies are outdated. The type parameter may be one of the following:

In addition to the filtering performed by the pseudo selector, some extra data is added to the resulting objects. The following data can be found under the queryContext property of each node.

Some examples:

:vuln

The :vuln pseudo selector retrieves data from the registry and returns information about which if your dependencies has a known vulnerability. Only dependencies whose current version matches a vulnerability will be returned. For example if you have semver@7.6.0 in your tree, a vulnerability for semver which affects versions <=6.3.1 will not match.

You can also filter results by certain attributes in advisories. Currently that includes severity and cwe. Note that severity filtering is done per severity, it does not include severities "higher" or "lower" than the one specified.

In addition to the filtering performed by the pseudo selector, info about each relevant advisory will be added to the queryContext attribute of each node under the advisories attribute.

Some examples:

Attribute Selectors

The attribute selector evaluates the key/value pairs in package.json if they are Strings.

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).

Please note that currently workspace deps are always prod dependencies. Additionally the .root dependency is also considered a prod dependency.

Programmatic Usage

const Arborist = require('@npmcli/arborist')
const arb = new Arborist({})
// root-level
arb.loadActual().then(async (tree) => {
  // query all production dependencies
  const results = await tree.querySelectorAll('.prod')
  console.log(results)
})
// iterative
arb.loadActual().then(async (tree) => {
  // query for the deduped version of react
  const results = await tree.querySelectorAll('#react:not(:deduped)')
  // query the deduped react for git deps
  const deps = await results[0].querySelectorAll(':type(git)')
  console.log(deps)
})

See Also