reggi/dev-engines
@reggi/path-to-regexp
dependabot/npm_and_yarn/main/copy-to-clipboard-4.0.2
dependabot/npm_and_yarn/main/eslint-10.4.0
dependabot/npm_and_yarn/main/npmcli/eslint-config-7.0.0
dependabot/npm_and_yarn/main/proc-log-7.0.0
dependabot/npm_and_yarn/npm_and_yarn-826852524d
dependabot/npm_and_yarn/npm_and_yarn-ab9a7f4bc2
deprecate-totp-2fa
dhei/classic-tokens
gat-bypass-2fa-docs
jpg619/fix-accessibility-content-flow
jpg619/version-bump-tar-2
kartykp/gat-bypass-2fa-docs
kartykp/upgrade-path-to-regex
main
maitxn/version-bump-tar
patch-1
reggi/cache-based-on-version
reggi/dev-engines
reggi/fix-transform-prettier
reggi/overrides
update-search-sensitivity
| 1 | --- |
| 2 | title: Dependency Selector Syntax & Querying |
| 3 | section: 7 |
| 4 | description: Dependency Selector Syntax & Querying |
| 5 | github_repo: npm/cli |
| 6 | github_branch: release/v8 |
| 7 | github_path: docs/lib/content/using-npm/dependency-selectors.md |
| 8 | redirect_from: |
| 9 | - /cli-documentation/v8/misc/dependency-selectors |
| 10 | - /cli-documentation/v8/using-npm/dependency-selectors |
| 11 | - /cli/v8/misc/dependency-selectors |
| 12 | --- |
| 13 | |
| 14 | ### Description |
| 15 | |
| 16 | The [`npm query`](/cli/v8/commands/npm-query) commmand exposes a new dependency selector syntax (informed by & respecting many aspects of the [CSS Selectors 4 Spec](https://dev.w3.org/csswg/selectors4/#relational)) which: |
| 17 | |
| 18 | - Standardizes the shape of, & querying of, dependency graphs with a robust object model, metadata & selector syntax |
| 19 | - Leverages existing, known language syntax & operators from CSS to make disparate package information broadly accessible |
| 20 | - Unlocks the ability to answer complex, multi-faceted questions about dependencies, their relationships & associative metadata |
| 21 | - Consolidates redundant logic of similar query commands in `npm` (ex. `npm fund`, `npm ls`, `npm outdated`, `npm audit` ...) |
| 22 | |
| 23 | ### Dependency Selector Syntax `v1.0.0` |
| 24 | |
| 25 | #### Overview: |
| 26 | |
| 27 | - there is no "type" or "tag" selectors (ex. `div, h1, a`) as a dependency/target is the only type of `Node` that can be queried |
| 28 | - the term "dependencies" is in reference to any `Node` found in a `tree` returned by `Arborist` |
| 29 | |
| 30 | #### Combinators |
| 31 | |
| 32 | - `>` direct descendant/child |
| 33 | - ` ` any descendant/child |
| 34 | - `~` sibling |
| 35 | |
| 36 | #### Selectors |
| 37 | |
| 38 | - `*` universal selector |
| 39 | - `#<name>` dependency selector (equivalent to `[name="..."]`) |
| 40 | - `#<name>@<version>` (equivalent to `[name=<name>]:semver(<version>)`) |
| 41 | - `,` selector list delimiter |
| 42 | - `.` dependency type selector |
| 43 | - `:` pseudo selector |
| 44 | |
| 45 | #### Dependency Type Selectors |
| 46 | |
| 47 | - `.prod` dependency found in the `dependencies` section of `package.json`, or is a child of said dependency |
| 48 | - `.dev` dependency found in the `devDependencies` section of `package.json`, or is a child of said dependency |
| 49 | - `.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 |
| 50 | - `.peer` dependency found in the `peerDependencies` section of `package.json` |
| 51 | - `.workspace` dependency found in the [`workspaces`](https://docs.npmjs.com/cli/v8/using-npm/workspaces) section of `package.json` |
| 52 | - `.bundled` dependency found in the `bundleDependencies` section of `package.json`, or is a child of said dependency |
| 53 | |
| 54 | #### Pseudo Selectors |
| 55 | |
| 56 | - [`:not(<selector>)`](https://developer.mozilla.org/en-US/docs/Web/CSS/:not) |
| 57 | - [`:has(<selector>)`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has) |
| 58 | - [`:is(<selector list>)`](https://developer.mozilla.org/en-US/docs/Web/CSS/:is) |
| 59 | - [`:root`](https://developer.mozilla.org/en-US/docs/Web/CSS/:root) matches the root node/dependency |
| 60 | - [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope) matches node/dependency it was queried against |
| 61 | - [`:empty`](https://developer.mozilla.org/en-US/docs/Web/CSS/:empty) when a dependency has no dependencies |
| 62 | - [`:private`](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#private) when a dependency is private |
| 63 | - `:link` when a dependency is linked (for instance, workspaces or packages manually [`linked`](https://docs.npmjs.com/cli/v8/commands/npm-link) |
| 64 | - `: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) |
| 65 | - `:overridden` when a dependency has been overridden |
| 66 | - `:extraneous` when a dependency exists but is not defined as a dependency of any node |
| 67 | - `:invalid` when a dependency version is out of its ancestors specified range |
| 68 | - `:missing` when a dependency is not found on disk |
| 69 | - `:semver(<spec>)` matching a valid [`node-semver`](https://github.com/npm/node-semver) spec |
| 70 | - `:path(<path>)` [glob](https://www.npmjs.com/package/glob) matching based on dependencies path relative to the project |
| 71 | - `:type(<type>)` [based on currently recognized types](https://github.com/npm/npm-package-arg#result-object) |
| 72 | |
| 73 | #### [Attribute Selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) |
| 74 | |
| 75 | The attribute selector evaluates the key/value pairs in `package.json` if they are `String`s. |
| 76 | |
| 77 | - `[]` attribute selector (ie. existence of attribute) |
| 78 | - `[attribute=value]` attribute value is equivalant... |
| 79 | - `[attribute~=value]` attribute value contains word... |
| 80 | - `[attribute*=value]` attribute value contains string... |
| 81 | - `[attribute|=value]` attribute value is equal to or starts with... |
| 82 | - `[attribute^=value]` attribute value starts with... |
| 83 | - `[attribute$=value]` attribute value ends with... |
| 84 | |
| 85 | #### `Array` & `Object` Attribute Selectors |
| 86 | |
| 87 | The 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: |
| 88 | |
| 89 | #### `Objects` |
| 90 | |
| 91 | ```css |
| 92 | /* return dependencies that have a `scripts.test` containing `"tap"` */ |
| 93 | *: attr(scripts, [test~=tap]); |
| 94 | ``` |
| 95 | |
| 96 | #### Nested `Objects` |
| 97 | |
| 98 | Nested objects are expressed as sequential arguments to `:attr()`. |
| 99 | |
| 100 | ```css |
| 101 | /* return dependencies that have a testling config for opera browsers */ |
| 102 | *: attr(testling, browsers, [~=opera]); |
| 103 | ``` |
| 104 | |
| 105 | #### `Arrays` |
| 106 | |
| 107 | `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. |
| 108 | |
| 109 | ##### Example of an `Array` Attribute Selection: |
| 110 | |
| 111 | ```css |
| 112 | /* removes the distinction between properties & arrays */ |
| 113 | /* ie. we'd have to check the property & iterate to match selection */ |
| 114 | *:attr([keywords^=react]) |
| 115 | *:attr(contributors, :attr([name~=Jordan])) |
| 116 | ``` |
| 117 | |
| 118 | ##### Example of an `Array` matching directly to a value: |
| 119 | |
| 120 | ```css |
| 121 | /* return dependencies that have the exact keyword "react" */ |
| 122 | /* this is equivalent to `*:keywords([value="react"])` */ |
| 123 | *: attr([keywords=react]); |
| 124 | ``` |
| 125 | |
| 126 | ##### Example of an `Array` of `Object`s: |
| 127 | |
| 128 | ```css |
| 129 | /* returns */ |
| 130 | *: attr(contributors, [email=ruyadorno @github.com]); |
| 131 | ``` |
| 132 | |
| 133 | ### Groups |
| 134 | |
| 135 | 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`). |
| 136 | |
| 137 | - `.prod` |
| 138 | - `.dev` |
| 139 | - `.optional` |
| 140 | - `.peer` |
| 141 | - `.bundled` |
| 142 | - `.workspace` |
| 143 | |
| 144 | Please note that currently `workspace` deps are always `prod` dependencies. Additionally the `.root` dependency is also considered a `prod` dependency. |
| 145 | |
| 146 | ### Programmatic Usage |
| 147 | |
| 148 | - `Arborist`'s `Node` Class has a `.querySelectorAll()` method |
| 149 | - this method will return a filtered, flattened dependency Arborist `Node` list based on a valid query selector |
| 150 | |
| 151 | ```js |
| 152 | const Arborist = require("@npmcli/arborist"); |
| 153 | const arb = new Arborist({}); |
| 154 | ``` |
| 155 | |
| 156 | ```js |
| 157 | // root-level |
| 158 | arb.loadActual().then(async (tree) => { |
| 159 | // query all production dependencies |
| 160 | const results = await tree.querySelectorAll(".prod"); |
| 161 | console.log(results); |
| 162 | }); |
| 163 | ``` |
| 164 | |
| 165 | ```js |
| 166 | // iterative |
| 167 | arb.loadActual().then(async (tree) => { |
| 168 | // query for the deduped version of react |
| 169 | const results = await tree.querySelectorAll("#react:not(:deduped)"); |
| 170 | // query the deduped react for git deps |
| 171 | const deps = await results[0].querySelectorAll(":type(git)"); |
| 172 | console.log(deps); |
| 173 | }); |
| 174 | ``` |
| 175 | |
| 176 | ## See Also |
| 177 | |
| 178 | - [npm query](/cli/v8/commands/npm-query) |
| 179 | - [@npmcli/arborist](https://npm.im/@npmcli/arborist) |