1DEPENDENCY() DEPENDENCY()
2
3
4
6 Dependency
7
8 Description
9 The npm help query commmand 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 about
20 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 package.json,
63 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 peerDe‐
67 pendenciesMeta section of package.json, or a child of said dependency
68
69 • .peer dependency found in the peerDependencies section of pack‐
70 age.json
71
72 • .workspace dependency found in the workspaces
73 https://docs.npmjs.com/cli/v8/using-npm/workspaces section of pack‐
74 age.json
75
76 • .bundled dependency found in the bundleDependencies section of pack‐
77 age.json, or is a child of said dependency
78
79
80 Pseudo Selectors
81 • :not(<selector>) https://devel‐
82 oper.mozilla.org/en-US/docs/Web/CSS/:not
83
84 • :has(<selector>) https://devel‐
85 oper.mozilla.org/en-US/docs/Web/CSS/:has
86
87 • :is(<selector list>) https://devel‐
88 oper.mozilla.org/en-US/docs/Web/CSS/:is
89
90 • :root https://developer.mozilla.org/en-US/docs/Web/CSS/:root matches
91 the root node/dependency
92
93 • :scope https://developer.mozilla.org/en-US/docs/Web/CSS/:scope
94 matches node/dependency it was queried against
95
96 • :empty https://developer.mozilla.org/en-US/docs/Web/CSS/:empty when a
97 dependency has no dependencies
98
99 • :private https://docs.npmjs.com/cli/v8/configuring-npm/pack‐
100 age-json#private when a dependency is private
101
102 • :link when a dependency is linked (for instance, workspaces or pack‐
103 ages manually linked https://docs.npmjs.com/cli/v8/commands/npm-link
104
105 • :deduped when a dependency has been deduped (note that this does not
106 always mean the dependency has been hoisted to the root of node_mod‐
107 ules)
108
109 • :overridden when a dependency has been overridden
110
111 • :extraneous when a dependency exists but is not defined as a depen‐
112 dency of any node
113
114 • :invalid when a dependency version is out of its ancestors specified
115 range
116
117 • :missing when a dependency is not found on disk
118
119 • :semver(<spec>) matching a valid node-semver
120 https://github.com/npm/node-semver spec
121
122 • :path(<path>) glob https://www.npmjs.com/package/glob matching based
123 on dependencies path relative to the project
124
125 • :type(<type>) based on currently recognized types
126 https://github.com/npm/npm-package-arg#result-object
127
128
129 Attribute Selectors https://developer.mozilla.org/en-US/docs/Web/CSS/Attri‐
130 bute_selectors
131 The attribute selector evaluates the key/value pairs in package.json if
132 they are Strings.
133
134 • [] attribute selector (ie. existence of attribute)
135
136 • [attribute=value] attribute value is equivalant...
137
138 • [attribute~=value] attribute value contains word...
139
140 • [attribute*=value] attribute value contains string...
141
142 • [attribute|=value] attribute value is equal to or starts with...
143
144 • [attribute^=value] attribute value starts with...
145
146 • [attribute$=value] attribute value ends with...
147
148
149 Array & Object Attribute Selectors
150 The generic :attr() pseudo selector standardizes a pattern which can be
151 used for attribute selection of Objects, Arrays or Arrays of Objects
152 accessible via Arborist's Node.package metadata. This allows for itera‐
153 tive attribute selection beyond top-level String evaluation. The last
154 argument passed to :attr() must be an attribute selector or a nested
155 :attr(). See examples below:
156
157 Objects
158 /* return dependencies that have a `scripts.test` containing `"tap"` */
159 *:attr(scripts, [test~=tap])
160
161 Nested Objects
162 Nested objects are expressed as sequential arguments to :attr().
163
164 /* return dependencies that have a testling config for opera browsers */
165 *:attr(testling, browsers, [~=opera])
166
167 Arrays
168 Arrays specifically uses a special/reserved . character in place of a
169 typical attribute name. Arrays also support exact value matching when a
170 String is passed to the selector.
171
172 Example of an Array Attribute Selection:
173 /* removes the distinction between properties & arrays */
174 /* ie. we'd have to check the property & iterate to match selection */
175 *:attr([keywords^=react])
176 *:attr(contributors, :attr([name~=Jordan]))
177
178 Example of an Array matching directly to a value:
179 /* return dependencies that have the exact keyword "react" */
180 /* this is equivalent to `*:keywords([value="react"])` */
181 *:attr([keywords=react])
182
183 Example of an Array of Objects:
184 /* returns */
185 *:attr(contributors, [email=ruyadorno@github.com])
186
187 Groups
188 Dependency groups are defined by the package relationships to their an‐
189 cestors (ie. the dependency types that are defined in package.json).
190 This approach is user-centric as the ecosystem has been taught to think
191 about dependencies in these groups first-and-foremost. Dependencies are
192 allowed to be included in multiple groups (ex. a prod dependency may
193 also be a dev dependency (in that it's also required by another dev de‐
194 pendency) & may also be bundled - a selector for that type of depen‐
195 dency would look like: *.prod.dev.bundled).
196
197 • .prod
198
199 • .dev
200
201 • .optional
202
203 • .peer
204
205 • .bundled
206
207 • .workspace
208
209
210 Please note that currently workspace deps are always prod dependencies.
211 Additionally the .root dependency is also considered a prod dependency.
212
213 Programmatic Usage
214 • Arborist's Node Class has a .querySelectorAll() method
215
216 • this method will return a filtered, flattened dependency Arborist
217 Node list based on a valid query selector
218
219
220
221 const Arborist = require('@npmcli/arborist')
222 const arb = new Arborist({})
223
224 // root-level
225 arb.loadActual().then(async (tree) => {
226 // query all production dependencies
227 const results = await tree.querySelectorAll('.prod')
228 console.log(results)
229 })
230
231 // iterative
232 arb.loadActual().then(async (tree) => {
233 // query for the deduped version of react
234 const results = await tree.querySelectorAll('#react:not(:deduped)')
235 // query the deduped react for git deps
236 const deps = await results[0].querySelectorAll(':type(git)')
237 console.log(deps)
238 })
239
241 • npm help query
242
243 • @npmcli/arborist https://npm.im/@npmcli/arborist
244
245
246
247
248 September 2022 DEPENDENCY()