1QUERYING(7) QUERYING(7)
2
3
4
6 Querying - Dependency Selector Syntax & Querying
7
8 Description
9 The npm help query command exposes a new dependency selector syntax
10 (informed by & respecting many aspects of the CSS Selectors 4 Spec
11 ⟨https://dev.w3.org/csswg/selectors4/#relational⟩) which:
12
13 • Standardizes the shape of, & querying of, dependency graphs with a
14 robust object model, metadata & selector syntax
15
16 • Leverages existing, known language syntax & operators from CSS to
17 make disparate package information broadly accessible
18
19 • Unlocks the ability to answer complex, multi-faceted questions
20 about dependencies, their relationships & associative metadata
21
22 • Consolidates redundant logic of similar query commands in npm (ex.
23 npm fund, npm ls, npm outdated, npm audit ...)
24
25
26 Dependency Selector Syntax v1.0.0
27 Overview:
28 • there is no "type" or "tag" selectors (ex. div, h1, a) as a depen‐
29 dency/target is the only type of Node that can be queried
30
31 • the term "dependencies" is in reference to any Node found in a tree
32 returned by Arborist
33
34
35 Combinators
36 • > direct descendant/child
37
38 •
39 any descendant/child
40
41 • ~ sibling
42
43
44 Selectors
45 • * universal selector
46
47 • #<name> dependency selector (equivalent to [name="..."])
48
49 • #<name>@<version> (equivalent to [name=<name>]:semver(<version>))
50
51 • , selector list delimiter
52
53 • . dependency type selector
54
55 • : pseudo selector
56
57
58 Dependency Type Selectors
59 • .prod dependency found in the dependencies section of package.json,
60 or is a child of said dependency
61
62 • .dev dependency found in the devDependencies section of pack‐
63 age.json, or is a child of said dependency
64
65 • .optional dependency found in the optionalDependencies section of
66 package.json, or has "optional": true set in its entry in the
67 peerDependenciesMeta section of package.json, or a child of said
68 dependency
69
70 • .peer dependency found in the peerDependencies section of pack‐
71 age.json
72
73 • .workspace dependency found in the workspaces
74 ⟨https://docs.npmjs.com/cli/v8/using-npm/workspaces⟩ section of
75 package.json
76
77 • .bundled dependency found in the bundleDependencies section of
78 package.json, or is a child of said dependency
79
80
81 Pseudo Selectors
82 • :not(<selector>) ⟨https://developer.mozilla.org/en-
83 US/docs/Web/CSS/:not⟩
84
85 • :has(<selector>) ⟨https://developer.mozilla.org/en-
86 US/docs/Web/CSS/:has⟩
87
88 • :is(<selector list>) ⟨https://developer.mozilla.org/en-
89 US/docs/Web/CSS/:is⟩
90
91 • :root ⟨https://developer.mozilla.org/en-US/docs/Web/CSS/:root⟩
92 matches the root node/dependency
93
94 • :scope ⟨https://developer.mozilla.org/en-US/docs/Web/CSS/:scope⟩
95 matches node/dependency it was queried against
96
97 • :empty ⟨https://developer.mozilla.org/en-US/docs/Web/CSS/:empty⟩
98 when a dependency has no dependencies
99
100 • :private ⟨https://docs.npmjs.com/cli/v8/configuring-npm/package-
101 json#private⟩ when a dependency is private
102
103 • :link when a dependency is linked (for instance, workspaces or
104 packages manually linked ⟨https://docs.npmjs.com/cli/v8/com‐
105 mands/npm-link⟩
106
107 • :deduped when a dependency has been deduped (note that this does
108 not always mean the dependency has been hoisted to the root of
109 node_modules)
110
111 • :overridden when a dependency has been overridden
112
113 • :extraneous when a dependency exists but is not defined as a depen‐
114 dency of any node
115
116 • :invalid when a dependency version is out of its ancestors speci‐
117 fied range
118
119 • :missing when a dependency is not found on disk
120
121 • :semver(<spec>, [selector], [function]) match a valid node-semver
122 ⟨https://github.com/npm/node-semver⟩ version or range to a selector
123
124 • :path(<path>) glob ⟨https://www.npmjs.com/package/glob⟩ matching
125 based on dependencies path relative to the project
126
127 • :type(<type>) based on currently recognized types
128 ⟨https://github.com/npm/npm-package-arg#result-object⟩
129
130 • :outdated(<type>) when a dependency is outdated
131
132
133 :semver(<spec>, [selector], [function])
134 The :semver() pseudo selector allows comparing fields from each node's
135 package.json using semver ⟨https://github.com/npm/node-semver#readme⟩
136 methods. It accepts up to 3 parameters, all but the first of which are
137 optional.
138
139 • spec a semver version or range
140
141 • selector an attribute selector for each node (default [version])
142
143 • function a semver method to apply, one of: satisfies, intersects,
144 subset, gt, gte, gtr, lt, lte, ltr, eq, neq or the special function
145 infer (default infer)
146
147
148 When the special infer function is used the spec and the actual value
149 from the node are compared. If both are versions, according to
150 semver.valid(), eq is used. If both values are ranges, according to
151 !semver.valid(), intersects is used. If the values are mixed types sat‐
152 isfies is used.
153
154 Some examples:
155
156 • :semver(^1.0.0) returns every node that has a version satisfied by
157 the provided range ^1.0.0
158
159 • :semver(16.0.0, :attr(engines, [node])) returns every node which
160 has an engines.node property satisfying the version 16.0.0
161
162 • :semver(1.0.0, [version], lt) every node with a version less than
163 1.0.0
164
165
166 :outdated(<type>)
167 The :outdated pseudo selector retrieves data from the registry and re‐
168 turns information about which of your dependencies are outdated. The
169 type parameter may be one of the following:
170
171 • any (default) a version exists that is greater than the current one
172
173 • in-range a version exists that is greater than the current one, and
174 satisfies at least one if its dependents
175
176 • out-of-range a version exists that is greater than the current one,
177 does not satisfy at least one of its dependents
178
179 • major a version exists that is a semver major greater than the cur‐
180 rent one
181
182 • minor a version exists that is a semver minor greater than the cur‐
183 rent one
184
185 • patch a version exists that is a semver patch greater than the cur‐
186 rent one
187
188
189 In addition to the filtering performed by the pseudo selector, some ex‐
190 tra data is added to the resulting objects. The following data can be
191 found under the queryContext property of each node.
192
193 • versions an array of every available version of the given node
194
195 • outdated.inRange an array of objects, each with a from and ver‐
196 sions, where from is the on-disk location of the node that depends
197 on the current node and versions is an array of all available ver‐
198 sions that satisfies that dependency. This is only populated if
199 :outdated(in-range) is used.
200
201 • outdated.outOfRange an array of objects, identical in shape to in‐
202 Range, but where the versions array is every available version that
203 does not satisfy the dependency. This is only populated if :out‐
204 dated(out-of-range) is used.
205
206
207 Some examples:
208
209 • :root > :outdated(major) returns every direct dependency that has a
210 new semver major release
211
212 • .prod:outdated(in-range) returns production dependencies that have
213 a new release that satisfies at least one of its edges in
214
215
216 Attribute Selectors ⟨https://developer.mozilla.org/en-US/docs/Web/CSS/At‐
217 tribute_selectors⟩
218 The attribute selector evaluates the key/value pairs in package.json if
219 they are Strings.
220
221 • [] attribute selector (ie. existence of attribute)
222
223 • [attribute=value] attribute value is equivalant...
224
225 • [attribute~=value] attribute value contains word...
226
227 • [attribute*=value] attribute value contains string...
228
229 • [attribute|=value] attribute value is equal to or starts with...
230
231 • [attribute^=value] attribute value starts with...
232
233 • [attribute$=value] attribute value ends with...
234
235
236 Array & Object Attribute Selectors
237 The generic :attr() pseudo selector standardizes a pattern which can be
238 used for attribute selection of Objects, Arrays or Arrays of Objects
239 accessible via Arborist's Node.package metadata. This allows for itera‐
240 tive attribute selection beyond top-level String evaluation. The last
241 argument passed to :attr() must be an attribute selector or a nested
242 :attr(). See examples below:
243
244 Objects
245 /* return dependencies that have a `scripts.test` containing `"tap"` */
246 *:attr(scripts, [test~=tap])
247
248 Nested Objects
249 Nested objects are expressed as sequential arguments to :attr().
250
251 /* return dependencies that have a testling config for opera browsers */
252 *:attr(testling, browsers, [~=opera])
253
254 Arrays
255 Arrays specifically uses a special/reserved . character in place of a
256 typical attribute name. Arrays also support exact value matching when a
257 String is passed to the selector.
258
259 Example of an Array Attribute Selection:
260 /* removes the distinction between properties & arrays */
261 /* ie. we'd have to check the property & iterate to match selection */
262 *:attr([keywords^=react])
263 *:attr(contributors, :attr([name~=Jordan]))
264
265 Example of an Array matching directly to a value:
266 /* return dependencies that have the exact keyword "react" */
267 /* this is equivalent to `*:keywords([value="react"])` */
268 *:attr([keywords=react])
269
270 Example of an Array of Objects:
271 /* returns */
272 *:attr(contributors, [email=ruyadorno@github.com])
273
274 Groups
275 Dependency groups are defined by the package relationships to their an‐
276 cestors (ie. the dependency types that are defined in package.json).
277 This approach is user-centric as the ecosystem has been taught to think
278 about dependencies in these groups first-and-foremost. Dependencies are
279 allowed to be included in multiple groups (ex. a prod dependency may
280 also be a dev dependency (in that it's also required by another dev de‐
281 pendency) & may also be bundled - a selector for that type of depen‐
282 dency would look like: *.prod.dev.bundled).
283
284 • .prod
285
286 • .dev
287
288 • .optional
289
290 • .peer
291
292 • .bundled
293
294 • .workspace
295
296
297 Please note that currently workspace deps are always prod dependencies.
298 Additionally the .root dependency is also considered a prod dependency.
299
300 Programmatic Usage
301 • Arborist's Node Class has a .querySelectorAll() method
302
303 • this method will return a filtered, flattened dependency Ar‐
304 borist Node list based on a valid query selector
305
306
307
308 const Arborist = require('@npmcli/arborist')
309 const arb = new Arborist({})
310
311 // root-level
312 arb.loadActual().then(async (tree) => {
313 // query all production dependencies
314 const results = await tree.querySelectorAll('.prod')
315 console.log(results)
316 })
317
318 // iterative
319 arb.loadActual().then(async (tree) => {
320 // query for the deduped version of react
321 const results = await tree.querySelectorAll('#react:not(:deduped)')
322 // query the deduped react for git deps
323 const deps = await results[0].querySelectorAll(':type(git)')
324 console.log(deps)
325 })
326
328 • npm help query
329
330 • @npmcli/arborist ⟨https://npm.im/@npmcli/arborist⟩
331
332
333
334 November 2023 QUERYING(7)