@vltpkg/query 1.0.0-rc.32 → 1.0.0-rc.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/index.js +10 -6
  2. package/dist/parser.js +2 -1
  3. package/dist/pseudo/hostname.js +3 -1
  4. package/dist/pseudo/malware.d.ts +3 -16
  5. package/dist/pseudo/malware.js +11 -171
  6. package/dist/pseudo/scripts.js +1 -1
  7. package/dist/pseudo/vuln.d.ts +22 -0
  8. package/dist/pseudo/vuln.js +220 -0
  9. package/dist/pseudo.js +3 -3
  10. package/dist/types.d.ts +3 -2
  11. package/package.json +19 -10
  12. package/skills/dss-query/REFERENCE.md +123 -0
  13. package/skills/dss-query/SKILL.md +190 -0
  14. package/skills/dss-query/evals/README.md +79 -0
  15. package/skills/dss-query/evals/evals.json +89 -0
  16. package/skills/dss-query/evals/grade.mjs +480 -0
  17. package/src/attribute.ts +186 -0
  18. package/src/combinator.ts +132 -0
  19. package/src/id.ts +46 -0
  20. package/src/index.ts +620 -0
  21. package/src/parser.ts +122 -0
  22. package/src/pseudo/abandoned.ts +9 -0
  23. package/src/pseudo/attr.ts +92 -0
  24. package/src/pseudo/built.ts +19 -0
  25. package/src/pseudo/confused.ts +29 -0
  26. package/src/pseudo/cve.ts +93 -0
  27. package/src/pseudo/cwe.ts +97 -0
  28. package/src/pseudo/debug.ts +9 -0
  29. package/src/pseudo/deprecated.ts +9 -0
  30. package/src/pseudo/dev.ts +18 -0
  31. package/src/pseudo/diff.ts +90 -0
  32. package/src/pseudo/dist.ts +144 -0
  33. package/src/pseudo/dynamic.ts +9 -0
  34. package/src/pseudo/empty.ts +15 -0
  35. package/src/pseudo/entropic.ts +9 -0
  36. package/src/pseudo/env.ts +6 -0
  37. package/src/pseudo/eval.ts +9 -0
  38. package/src/pseudo/fs.ts +9 -0
  39. package/src/pseudo/helpers.ts +106 -0
  40. package/src/pseudo/host.ts +111 -0
  41. package/src/pseudo/hostname.ts +156 -0
  42. package/src/pseudo/license.ts +134 -0
  43. package/src/pseudo/link.ts +30 -0
  44. package/src/pseudo/malware.ts +41 -0
  45. package/src/pseudo/minified.ts +9 -0
  46. package/src/pseudo/missing.ts +16 -0
  47. package/src/pseudo/native.ts +9 -0
  48. package/src/pseudo/network.ts +9 -0
  49. package/src/pseudo/obfuscated.ts +9 -0
  50. package/src/pseudo/optional.ts +18 -0
  51. package/src/pseudo/outdated.ts +305 -0
  52. package/src/pseudo/overridden.ts +20 -0
  53. package/src/pseudo/path.ts +146 -0
  54. package/src/pseudo/peer.ts +18 -0
  55. package/src/pseudo/prerelease.ts +47 -0
  56. package/src/pseudo/private.ts +19 -0
  57. package/src/pseudo/prod.ts +18 -0
  58. package/src/pseudo/published.ts +248 -0
  59. package/src/pseudo/registry.ts +29 -0
  60. package/src/pseudo/root.ts +19 -0
  61. package/src/pseudo/scanned.ts +20 -0
  62. package/src/pseudo/score.ts +186 -0
  63. package/src/pseudo/scripts.ts +54 -0
  64. package/src/pseudo/semver.ts +320 -0
  65. package/src/pseudo/severity.ts +231 -0
  66. package/src/pseudo/shell.ts +9 -0
  67. package/src/pseudo/shrinkwrap.ts +9 -0
  68. package/src/pseudo/spec.ts +131 -0
  69. package/src/pseudo/squat.ts +225 -0
  70. package/src/pseudo/suspicious.ts +9 -0
  71. package/src/pseudo/tracker.ts +9 -0
  72. package/src/pseudo/trivial.ts +9 -0
  73. package/src/pseudo/type.ts +26 -0
  74. package/src/pseudo/undesirable.ts +9 -0
  75. package/src/pseudo/unknown.ts +9 -0
  76. package/src/pseudo/unmaintained.ts +9 -0
  77. package/src/pseudo/unpopular.ts +9 -0
  78. package/src/pseudo/unstable.ts +9 -0
  79. package/src/pseudo/vuln.ts +273 -0
  80. package/src/pseudo/workspace.ts +22 -0
  81. package/src/pseudo.ts +413 -0
  82. package/src/types.ts +165 -0
  83. package/tap-snapshots/test/attribute.ts.test.cjs +304 -0
  84. package/tap-snapshots/test/combinator.ts.test.cjs +333 -0
  85. package/tap-snapshots/test/id.ts.test.cjs +118 -0
  86. package/tap-snapshots/test/parser.ts.test.cjs +344 -0
  87. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +18 -0
  88. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +161 -0
  89. package/tap-snapshots/test/pseudo/built.ts.test.cjs +70 -0
  90. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +32 -0
  91. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +49 -0
  92. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +49 -0
  93. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +18 -0
  94. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +18 -0
  95. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +30 -0
  96. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +18 -0
  97. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +50 -0
  98. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +18 -0
  99. package/tap-snapshots/test/pseudo/env.ts.test.cjs +18 -0
  100. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +18 -0
  101. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +18 -0
  102. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +18 -0
  103. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +148 -0
  104. package/tap-snapshots/test/pseudo/license.ts.test.cjs +41 -0
  105. package/tap-snapshots/test/pseudo/link.ts.test.cjs +36 -0
  106. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +22 -0
  107. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +18 -0
  108. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +30 -0
  109. package/tap-snapshots/test/pseudo/native.ts.test.cjs +18 -0
  110. package/tap-snapshots/test/pseudo/network.ts.test.cjs +18 -0
  111. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +18 -0
  112. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +130 -0
  113. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +75 -0
  114. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +101 -0
  115. package/tap-snapshots/test/pseudo/private.ts.test.cjs +38 -0
  116. package/tap-snapshots/test/pseudo/published.ts.test.cjs +171 -0
  117. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +68 -0
  118. package/tap-snapshots/test/pseudo/root.ts.test.cjs +24 -0
  119. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +18 -0
  120. package/tap-snapshots/test/pseudo/score.ts.test.cjs +239 -0
  121. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +61 -0
  122. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +575 -0
  123. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +95 -0
  124. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +18 -0
  125. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +18 -0
  126. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +148 -0
  127. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +129 -0
  128. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +18 -0
  129. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +18 -0
  130. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +18 -0
  131. package/tap-snapshots/test/pseudo/type.ts.test.cjs +51 -0
  132. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +18 -0
  133. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +18 -0
  134. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +18 -0
  135. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +18 -0
  136. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +18 -0
  137. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +208 -0
  138. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +20 -0
  139. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +19 -0
  140. package/tap-snapshots/test/pseudo.ts.test.cjs +1247 -0
  141. package/test/attribute.ts +266 -0
  142. package/test/combinator.ts +168 -0
  143. package/test/fixtures/graph.ts +999 -0
  144. package/test/fixtures/selector.ts +103 -0
  145. package/test/fixtures/types.ts +7 -0
  146. package/test/id.ts +102 -0
  147. package/test/index.ts +1000 -0
  148. package/test/parser.ts +117 -0
  149. package/test/pseudo/abandoned.ts +98 -0
  150. package/test/pseudo/attr.ts +298 -0
  151. package/test/pseudo/built.ts +214 -0
  152. package/test/pseudo/confused.ts +160 -0
  153. package/test/pseudo/cve.ts +249 -0
  154. package/test/pseudo/cwe.ts +255 -0
  155. package/test/pseudo/debug.ts +98 -0
  156. package/test/pseudo/deprecated.ts +98 -0
  157. package/test/pseudo/dev.ts +61 -0
  158. package/test/pseudo/diff.ts +417 -0
  159. package/test/pseudo/dist.ts +215 -0
  160. package/test/pseudo/dynamic.ts +98 -0
  161. package/test/pseudo/empty.ts +108 -0
  162. package/test/pseudo/entropic.ts +101 -0
  163. package/test/pseudo/env.ts +98 -0
  164. package/test/pseudo/eval.ts +98 -0
  165. package/test/pseudo/fs.ts +98 -0
  166. package/test/pseudo/helpers.ts +370 -0
  167. package/test/pseudo/host-context.ts +276 -0
  168. package/test/pseudo/hostname.ts +314 -0
  169. package/test/pseudo/license.ts +265 -0
  170. package/test/pseudo/link.ts +94 -0
  171. package/test/pseudo/malware.ts +184 -0
  172. package/test/pseudo/minified.ts +98 -0
  173. package/test/pseudo/missing.ts +111 -0
  174. package/test/pseudo/native.ts +98 -0
  175. package/test/pseudo/network.ts +98 -0
  176. package/test/pseudo/obfuscated.ts +98 -0
  177. package/test/pseudo/optional.ts +73 -0
  178. package/test/pseudo/outdated.ts +331 -0
  179. package/test/pseudo/overridden.ts +317 -0
  180. package/test/pseudo/path.ts +680 -0
  181. package/test/pseudo/peer.ts +101 -0
  182. package/test/pseudo/prerelease.ts +279 -0
  183. package/test/pseudo/private.ts +108 -0
  184. package/test/pseudo/prod.ts +61 -0
  185. package/test/pseudo/published.ts +557 -0
  186. package/test/pseudo/registry.ts +122 -0
  187. package/test/pseudo/root.ts +66 -0
  188. package/test/pseudo/scanned.ts +78 -0
  189. package/test/pseudo/score.ts +591 -0
  190. package/test/pseudo/scripts.ts +294 -0
  191. package/test/pseudo/semver.ts +822 -0
  192. package/test/pseudo/severity.ts +310 -0
  193. package/test/pseudo/shell.ts +98 -0
  194. package/test/pseudo/shrinkwrap.ts +98 -0
  195. package/test/pseudo/spec.ts +525 -0
  196. package/test/pseudo/squat.ts +565 -0
  197. package/test/pseudo/suspicious.ts +98 -0
  198. package/test/pseudo/tracker.ts +98 -0
  199. package/test/pseudo/trivial.ts +98 -0
  200. package/test/pseudo/type.ts +105 -0
  201. package/test/pseudo/undesirable.ts +98 -0
  202. package/test/pseudo/unknown.ts +98 -0
  203. package/test/pseudo/unmaintained.ts +98 -0
  204. package/test/pseudo/unpopular.ts +98 -0
  205. package/test/pseudo/unstable.ts +98 -0
  206. package/test/pseudo/vuln.ts +625 -0
  207. package/test/pseudo/vulnerable.ts +137 -0
  208. package/test/pseudo/workspace.ts +111 -0
  209. package/test/pseudo.ts +558 -0
  210. package/tsconfig.json +3 -0
  211. package/tsconfig.publish.json +19 -0
  212. package/tsconfig.publish.tsbuildinfo +1 -0
  213. package/typedoc.mjs +2 -0
  214. package/dist/pseudo/vulnerable.d.ts +0 -8
  215. package/dist/pseudo/vulnerable.js +0 -17
@@ -0,0 +1,999 @@
1
+ import { joinDepIDTuple } from '@vltpkg/dep-id'
2
+ import { Spec } from '@vltpkg/spec/browser'
3
+ import { normalizeManifest } from '@vltpkg/types'
4
+ import type {
5
+ EdgeLike,
6
+ GraphLike,
7
+ NodeLike,
8
+ Manifest,
9
+ DependencyTypeShort,
10
+ } from '@vltpkg/types'
11
+ import type { SpecLike, SpecOptions } from '@vltpkg/spec/browser'
12
+
13
+ const specOptions = {
14
+ // there is no default registry any more, so these fixtures configure
15
+ // one explicitly
16
+ registry: 'https://registry.npmjs.org/',
17
+ registries: {
18
+ custom: 'http://example.com',
19
+ },
20
+ } satisfies SpecOptions
21
+
22
+ const projectRoot = '.'
23
+ export const newGraph = (rootName: string): GraphLike => {
24
+ const graph = {} as GraphLike
25
+ const addNode = newNode(graph)
26
+ const mainImporter = addNode(rootName)
27
+ mainImporter.id = joinDepIDTuple(['file', '.'])
28
+ mainImporter.mainImporter = true
29
+ mainImporter.importer = true
30
+ mainImporter.graph = graph
31
+ graph.importers = new Set([mainImporter])
32
+ graph.mainImporter = mainImporter
33
+ graph.nodes = new Map([[mainImporter.id, mainImporter]])
34
+ graph.edges = new Set()
35
+
36
+ return graph
37
+ }
38
+ export const newNode =
39
+ (graph: GraphLike) =>
40
+ (name: string, version = '1.0.0'): NodeLike => ({
41
+ projectRoot,
42
+ confused: false,
43
+ edgesIn: new Set(),
44
+ edgesOut: new Map(),
45
+ importer: false,
46
+ mainImporter: false,
47
+ graph,
48
+ id: joinDepIDTuple(['registry', '', `${name}@${version}`]),
49
+ name,
50
+ version,
51
+ location:
52
+ joinDepIDTuple(['registry', '', `${name}@${version}`]) +
53
+ `/node_modules/${name}`,
54
+ manifest: normalizeManifest({ name, version }),
55
+ integrity: 'sha512-deadbeef',
56
+ resolved: undefined,
57
+ dev: false,
58
+ optional: false,
59
+ options: specOptions,
60
+ setConfusedManifest() {},
61
+ setResolved() {},
62
+ maybeSetConfusedManifest() {},
63
+ workspaces: undefined,
64
+ toJSON() {
65
+ return {
66
+ id: this.id,
67
+ name: this.name,
68
+ version: this.version,
69
+ location: this.location,
70
+ importer: this.importer,
71
+ manifest: this.manifest,
72
+ projectRoot: this.projectRoot,
73
+ integrity: this.integrity,
74
+ resolved: this.resolved,
75
+ dev: this.dev,
76
+ optional: this.optional,
77
+ confused: false,
78
+ }
79
+ },
80
+ })
81
+ const newEdge = (
82
+ from: NodeLike,
83
+ spec: SpecLike<Spec>,
84
+ type: DependencyTypeShort,
85
+ to?: NodeLike,
86
+ ) => {
87
+ const edge = {
88
+ name: spec.name,
89
+ from,
90
+ to,
91
+ spec,
92
+ type,
93
+ get optional() {
94
+ return this.type === 'peerOptional' || this.type === 'optional'
95
+ },
96
+ get peer() {
97
+ return this.type === 'peer' || this.type === 'peerOptional'
98
+ },
99
+ }
100
+ from.edgesOut.set(spec.name, edge)
101
+ if (to) {
102
+ to.edgesIn.add(edge)
103
+ }
104
+ from.graph.edges.add(edge)
105
+ }
106
+
107
+ const updateNodeVersion = (
108
+ node: NodeLike,
109
+ version: string,
110
+ protocol = '',
111
+ ) => {
112
+ node.version = version
113
+ node.id = joinDepIDTuple([
114
+ 'registry',
115
+ protocol,
116
+ `${node.name}@${version}`,
117
+ ])
118
+ }
119
+
120
+ // Returns a graph that looks like:
121
+ //
122
+ // my-project (#a:prod, #b:dev, #e:prod, #@x/y:dev)
123
+ // +-- a
124
+ // +-- b (#c:prod, #d:prod)
125
+ // +-- c
126
+ // +-- d (#e:prod #f:optional)
127
+ // +-- e
128
+ // +-- f
129
+ // +-- e
130
+ // +-- @x/y
131
+ //
132
+ export const getSimpleGraph = (): GraphLike => {
133
+ const graph = newGraph('my-project')
134
+ const addNode = newNode(graph)
135
+ const [a, b, c, d, e, f, y] = [
136
+ 'a',
137
+ 'b',
138
+ 'c',
139
+ 'd',
140
+ 'e',
141
+ 'f',
142
+ '@x/y',
143
+ ].map(i => addNode(i)) as [
144
+ NodeLike,
145
+ NodeLike,
146
+ NodeLike,
147
+ NodeLike,
148
+ NodeLike,
149
+ NodeLike,
150
+ NodeLike,
151
+ NodeLike,
152
+ ]
153
+ b.dev = c.dev = d.dev = e.dev = f.dev = y.dev = true // deps of dev deps
154
+ f.optional = true
155
+ y.id = joinDepIDTuple(['file', 'y'])
156
+ ;[a, b, c, d, e, f, y].forEach(i => {
157
+ graph.nodes.set(i.id, i)
158
+ })
159
+ newEdge(
160
+ graph.mainImporter,
161
+ Spec.parse('a', '^1.0.0', specOptions),
162
+ 'prod',
163
+ a,
164
+ )
165
+ newEdge(
166
+ graph.mainImporter,
167
+ Spec.parse('b', '^1.0.0', specOptions),
168
+ 'dev',
169
+ b,
170
+ )
171
+ newEdge(
172
+ graph.mainImporter,
173
+ Spec.parse('e', '^1.0.0', specOptions),
174
+ 'prod',
175
+ e,
176
+ )
177
+ newEdge(
178
+ graph.mainImporter,
179
+ Spec.parse('@x/y', 'file:y', specOptions),
180
+ 'dev',
181
+ y,
182
+ )
183
+ newEdge(b, Spec.parse('c', '^1.0.0', specOptions), 'prod', c)
184
+ newEdge(b, Spec.parse('d', '^1.0.0', specOptions), 'prod', d)
185
+ newEdge(d, Spec.parse('e', '^1.0.0', specOptions), 'prod', e)
186
+ newEdge(d, Spec.parse('f', '^1.0.0', specOptions), 'optional', f)
187
+
188
+ // give some nodes an expanded manifest so that we can test
189
+ // more attribute selector scenarios
190
+ b.manifest = normalizeManifest({
191
+ ...b.manifest,
192
+ version: '2.0.0',
193
+ scripts: {
194
+ postinstall: 'postinstall',
195
+ test: 'test',
196
+ },
197
+ contributors: [
198
+ {
199
+ name: 'Ruy Adorno',
200
+ email: 'ruyadorno@example.com',
201
+ },
202
+ ],
203
+ } as Manifest)
204
+
205
+ c.manifest = normalizeManifest({
206
+ ...c.manifest,
207
+ peerDependenciesMeta: {
208
+ foo: {
209
+ optional: true,
210
+ },
211
+ },
212
+ keywords: ['something', 'someother'],
213
+ } as Manifest)
214
+
215
+ d.manifest = normalizeManifest({
216
+ ...d.manifest,
217
+ private: true,
218
+ a: {
219
+ b: [
220
+ {
221
+ c: {
222
+ d: 'foo',
223
+ },
224
+ },
225
+ {
226
+ c: {
227
+ d: 'bar',
228
+ },
229
+ },
230
+ ],
231
+ e: ['foo', 'bar'],
232
+ },
233
+ } as Manifest)
234
+ return graph
235
+ }
236
+
237
+ // Returns a graph with a root node and a single workspace
238
+ export const getSingleWorkspaceGraph = (): GraphLike => {
239
+ const graph = newGraph('ws')
240
+ const addNode = newNode(graph)
241
+ const w = addNode('w')
242
+ w.id = joinDepIDTuple(['workspace', 'w'])
243
+ graph.nodes.set(w.id, w)
244
+ graph.importers.add(w)
245
+ graph.mainImporter.workspaces = new Map()
246
+ graph.mainImporter.workspaces.set('w', {
247
+ name: 'w',
248
+ from: graph.mainImporter,
249
+ spec: Spec.parse('w', 'workspace:*', specOptions),
250
+ type: 'prod',
251
+ } satisfies EdgeLike)
252
+ w.importer = true
253
+ return graph
254
+ }
255
+
256
+ // Returns a complex graph with a multiple workspaces with dependencies
257
+ export const getMultiWorkspaceGraph = (): GraphLike => {
258
+ const graph = newGraph('ws')
259
+ const addNode = newNode(graph)
260
+ const a = addNode('a')
261
+ a.id = joinDepIDTuple(['workspace', 'a'])
262
+ graph.nodes.set(a.id, a)
263
+ graph.importers.add(a)
264
+ a.importer = true
265
+ const b = addNode('b')
266
+ b.id = joinDepIDTuple(['workspace', 'b'])
267
+ graph.nodes.set(b.id, b)
268
+ graph.importers.add(b)
269
+ b.importer = true
270
+ const c = addNode('c')
271
+ c.id = joinDepIDTuple(['workspace', 'c'])
272
+ graph.nodes.set(c.id, c)
273
+ graph.importers.add(c)
274
+ c.importer = true
275
+
276
+ // Set up workspaces property on mainImporter
277
+ graph.mainImporter.workspaces = new Map()
278
+ graph.mainImporter.workspaces.set('a', {
279
+ name: 'a',
280
+ from: graph.mainImporter,
281
+ spec: Spec.parse('a', 'workspace:*', specOptions),
282
+ type: 'prod',
283
+ } satisfies EdgeLike)
284
+ graph.mainImporter.workspaces.set('b', {
285
+ name: 'b',
286
+ from: graph.mainImporter,
287
+ spec: Spec.parse('b', 'workspace:*', specOptions),
288
+ type: 'prod',
289
+ } satisfies EdgeLike)
290
+ graph.mainImporter.workspaces.set('c', {
291
+ name: 'c',
292
+ from: graph.mainImporter,
293
+ spec: Spec.parse('c', 'workspace:*', specOptions),
294
+ type: 'prod',
295
+ } satisfies EdgeLike)
296
+
297
+ const [d, e, f, y] = ['d', 'e', 'f', '@x/y'].map(i =>
298
+ addNode(i),
299
+ ) as [NodeLike, NodeLike, NodeLike, NodeLike, NodeLike]
300
+
301
+ newEdge(b, Spec.parse('a', 'workspace:*', specOptions), 'prod', a)
302
+ newEdge(b, Spec.parse('d', '^1.0.0', specOptions), 'prod', d)
303
+ newEdge(b, Spec.parse('e', '^1.0.0', specOptions), 'prod', e)
304
+ newEdge(a, Spec.parse('f', '^1.0.0', specOptions), 'prod', f)
305
+ newEdge(
306
+ graph.mainImporter,
307
+ Spec.parse('@x/y', '^1.0.0', specOptions),
308
+ 'prod',
309
+ y,
310
+ )
311
+ return graph
312
+ }
313
+
314
+ // Returns a graph that looks like:
315
+ //
316
+ // cycle-project (#a:prod)
317
+ // +-> a <--------------+
318
+ // +-> b (#a:prod) --+
319
+ //
320
+ export const getCycleGraph = (): GraphLike => {
321
+ const graph = newGraph('cycle-project')
322
+ graph.mainImporter.manifest = {
323
+ ...graph.mainImporter.manifest,
324
+ dependencies: {
325
+ a: '^1.0.0',
326
+ },
327
+ }
328
+ const addNode = newNode(graph)
329
+
330
+ const a = addNode('a')
331
+ a.manifest = {
332
+ ...a.manifest,
333
+ scripts: {
334
+ test: 'foo',
335
+ },
336
+ dependencies: {
337
+ b: '^1.0.0',
338
+ },
339
+ }
340
+ graph.nodes.set(a.id, a)
341
+ newEdge(
342
+ graph.mainImporter,
343
+ Spec.parse('a', '^1.0.0', specOptions),
344
+ 'prod',
345
+ a,
346
+ )
347
+
348
+ const b = addNode('b')
349
+ b.manifest = {
350
+ ...b.manifest,
351
+ scripts: {
352
+ test: 'bar',
353
+ },
354
+ dependencies: {
355
+ a: '^1.0.0',
356
+ },
357
+ }
358
+ graph.nodes.set(b.id, b)
359
+ newEdge(a, Spec.parse('b', '^1.0.0', specOptions), 'prod', b)
360
+ newEdge(b, Spec.parse('a', '^1.0.0', specOptions), 'prod', a)
361
+
362
+ return graph
363
+ }
364
+
365
+ // Returns a graph in which nodes have no manifest data
366
+ export const getMissingManifestsGraph = (): GraphLike => {
367
+ const graph = newGraph('missing-manifest-project')
368
+ delete graph.mainImporter.manifest
369
+
370
+ const addNode = newNode(graph)
371
+ const a = addNode('a')
372
+ delete a.manifest
373
+ graph.nodes.set(a.id, a)
374
+ newEdge(
375
+ graph.mainImporter,
376
+ Spec.parse('a', '^1.0.0', specOptions),
377
+ 'prod',
378
+ a,
379
+ )
380
+ return graph
381
+ }
382
+
383
+ // Returns a graph in which nodes are missing
384
+ export const getMissingNodeGraph = (): GraphLike => {
385
+ const graph = newGraph('node-missing-project')
386
+ newEdge(
387
+ graph.mainImporter,
388
+ Spec.parse('a', '^1.0.0', specOptions),
389
+ 'prod',
390
+ )
391
+ newEdge(
392
+ graph.mainImporter,
393
+ Spec.parse('b', '^1.0.0', specOptions),
394
+ 'dev',
395
+ )
396
+ return graph
397
+ }
398
+
399
+ export const getSemverRichGraph = (): GraphLike => {
400
+ const graph = newGraph('semver-rich-project')
401
+ const addNode = newNode(graph)
402
+ const [a, b, c, d, e, f, g] = [
403
+ 'a',
404
+ 'b',
405
+ 'c',
406
+ 'd',
407
+ 'e',
408
+ 'f',
409
+ 'g',
410
+ ].map(i => addNode(i)) as [
411
+ NodeLike,
412
+ NodeLike,
413
+ NodeLike,
414
+ NodeLike,
415
+ NodeLike,
416
+ NodeLike,
417
+ NodeLike,
418
+ ]
419
+ ;[a, b, c, d, e, f, g].forEach(i => {
420
+ graph.nodes.set(i.id, i)
421
+ })
422
+ newEdge(
423
+ graph.mainImporter,
424
+ Spec.parse('a', '^1.0.0', specOptions),
425
+ 'prod',
426
+ a,
427
+ )
428
+ newEdge(
429
+ graph.mainImporter,
430
+ Spec.parse('b', '~2.2.0', specOptions),
431
+ 'prod',
432
+ b,
433
+ )
434
+ newEdge(b, Spec.parse('c', '3 || 4 || 5', specOptions), 'prod', c)
435
+ newEdge(b, Spec.parse('d', '1.2 - 2.3.4', specOptions), 'prod', d)
436
+ newEdge(
437
+ graph.mainImporter,
438
+ Spec.parse('e', '<=120', specOptions),
439
+ 'prod',
440
+ e,
441
+ )
442
+ newEdge(d, Spec.parse('f', '4.x.x', specOptions), 'prod', f)
443
+ newEdge(
444
+ graph.mainImporter,
445
+ Spec.parse('g', '1.2.3-rc.1+rev.2', specOptions),
446
+ 'prod',
447
+ g,
448
+ )
449
+ graph.mainImporter.manifest = {
450
+ ...graph.mainImporter.manifest,
451
+ dependencies: {
452
+ a: '^1.0.0',
453
+ b: '~2.2.0',
454
+ e: '<=120',
455
+ },
456
+ }
457
+ updateNodeVersion(a, '1.0.1')
458
+ a.manifest = {
459
+ ...a.manifest,
460
+ version: '1.0.1',
461
+ }
462
+ updateNodeVersion(b, '2.2.1')
463
+ b.manifest = {
464
+ ...b.manifest,
465
+ version: '2.2.1',
466
+ dependencies: {
467
+ c: '3 || 4 || 5',
468
+ d: '1.2 - 2.3.4',
469
+ },
470
+ engines: {
471
+ node: '>=10',
472
+ },
473
+ }
474
+ updateNodeVersion(c, '3.4.0', 'custom')
475
+ c.manifest = {
476
+ ...c.manifest,
477
+ engines: {
478
+ node: '>=24',
479
+ },
480
+ version: '3.4.0',
481
+ }
482
+ updateNodeVersion(d, '2.3.4')
483
+ d.manifest = {
484
+ ...d.manifest,
485
+ version: '2.3.4',
486
+ dependencies: {
487
+ e: '1.3.4-beta.1',
488
+ f: '4.x.x',
489
+ },
490
+ }
491
+ updateNodeVersion(e, '120.0.0')
492
+ e.manifest = {
493
+ ...e.manifest,
494
+ version: '120.0.0',
495
+ }
496
+ const e2 = addNode('e', '1.3.4-beta.1')
497
+ graph.nodes.set(e2.id, e2)
498
+ newEdge(
499
+ d,
500
+ Spec.parse('e', '=1.3.4-beta.1', specOptions),
501
+ 'prod',
502
+ e2,
503
+ )
504
+ updateNodeVersion(f, '4.5.6')
505
+ f.manifest = normalizeManifest({
506
+ ...f.manifest,
507
+ version: '4.5.6',
508
+ arbitrarySemverValue: '2.0.0',
509
+ } as Manifest)
510
+ updateNodeVersion(g, '1.2.3-rc.1+rev.2')
511
+ g.manifest = {
512
+ ...g.manifest,
513
+ version: '1.2.3-rc.1+rev.2',
514
+ }
515
+ // dist-tag edge (spec.semver is undefined, only bareSpec is set)
516
+ const h = addNode('h')
517
+ graph.nodes.set(h.id, h)
518
+ newEdge(
519
+ graph.mainImporter,
520
+ Spec.parse('h', 'latest', specOptions),
521
+ 'prod',
522
+ h,
523
+ )
524
+ updateNodeVersion(h, '1.0.0')
525
+ h.manifest = {
526
+ ...h.manifest,
527
+ version: '1.0.0',
528
+ }
529
+ return graph
530
+ }
531
+
532
+ // Returns a graph that looks like:
533
+ //
534
+ // link-project (#a.file, #b.registry, #c.tar.gz)
535
+ // +-- a (file link)
536
+ // +-- b (registry package)
537
+ // +-- c (tar.gz archive)
538
+ //
539
+ export const getLinkedGraph = (): GraphLike => {
540
+ const graph = newGraph('link-project')
541
+ const addNode = newNode(graph)
542
+
543
+ // Create file link node 'a'
544
+ const a = addNode('a')
545
+ a.id = joinDepIDTuple(['file', 'a'])
546
+
547
+ // Create registry node 'b'
548
+ const b = addNode('b')
549
+
550
+ // Create tar.gz node 'c'
551
+ const c = addNode('c')
552
+ c.id = joinDepIDTuple(['file', 'package.tar.gz'])
553
+
554
+ // Add nodes to graph
555
+ ;[a, b, c].forEach(i => {
556
+ graph.nodes.set(i.id, i)
557
+ })
558
+
559
+ // Add edges from main importer to nodes
560
+ newEdge(
561
+ graph.mainImporter,
562
+ Spec.parse('a', 'file:a', specOptions),
563
+ 'prod',
564
+ a,
565
+ )
566
+ newEdge(
567
+ graph.mainImporter,
568
+ Spec.parse('b', '^1.0.0', specOptions),
569
+ 'prod',
570
+ b,
571
+ )
572
+ newEdge(
573
+ graph.mainImporter,
574
+ Spec.parse('c', 'file:package.tar.gz', specOptions),
575
+ 'prod',
576
+ c,
577
+ )
578
+ newEdge(
579
+ graph.mainImporter,
580
+ Spec.parse('d', 'file:d', specOptions),
581
+ 'prod',
582
+ )
583
+ newEdge(
584
+ graph.mainImporter,
585
+ Spec.parse('e', 'file:e.tar.gz', specOptions),
586
+ 'prod',
587
+ )
588
+
589
+ return graph
590
+ }
591
+
592
+ // Returns a graph that looks like:
593
+ //
594
+ // aliased-project (#a:prod, #b[alias for foo]:prod, #c[alias for custom:c]:prod)
595
+ // +-- a (regular dependency)
596
+ // +-- b (aliased dependency for foo, npm:foo@^1.0.0)
597
+ // +-- bar (aliased dependency for d, npm:d@^1.0.0)
598
+ // +-- c (custom registry aliased dependency, custom:c@^1.0.0)
599
+ //
600
+ export const getAliasedGraph = (): GraphLike => {
601
+ const graph = newGraph('aliased-project')
602
+ const addNode = newNode(graph)
603
+
604
+ // Update main importer manifest to include
605
+ // dependencies definitions
606
+ graph.mainImporter.manifest = {
607
+ ...graph.mainImporter.manifest,
608
+ dependencies: {
609
+ a: '^1.0.0',
610
+ b: 'npm:foo@^1.0.0',
611
+ c: 'custom:c@^1.0.0',
612
+ },
613
+ }
614
+
615
+ // Create regular node 'a'
616
+ const a = addNode('a')
617
+ a.manifest = {
618
+ ...a.manifest,
619
+ version: '1.0.0',
620
+ }
621
+
622
+ // Create 'foo' node that will be aliased as 'b'
623
+ const foo = addNode('foo')
624
+ foo.manifest = {
625
+ ...foo.manifest,
626
+ dependencies: {
627
+ bar: 'npm:d@^1.0.0',
628
+ },
629
+ version: '1.0.0',
630
+ }
631
+
632
+ // Create 'd' node that will be aliased as 'bar' (dependency of 'b')
633
+ const d = addNode('d')
634
+ d.manifest = {
635
+ ...d.manifest,
636
+ version: '1.0.0',
637
+ }
638
+
639
+ // Create 'c' node from custom registry
640
+ const c = addNode('c')
641
+ c.id = joinDepIDTuple(['registry', 'custom', 'c@1.0.0'])
642
+ c.manifest = {
643
+ ...c.manifest,
644
+ version: '1.0.0',
645
+ }
646
+
647
+ // Add nodes to graph
648
+ ;[a, foo, d, c].forEach(i => {
649
+ graph.nodes.set(i.id, i)
650
+ })
651
+
652
+ // Add edges from main importer to nodes
653
+ newEdge(
654
+ graph.mainImporter,
655
+ Spec.parse('a', '^1.0.0', specOptions),
656
+ 'prod',
657
+ a,
658
+ )
659
+
660
+ // Add edge for aliased dependency 'b' -> 'foo'
661
+ newEdge(
662
+ graph.mainImporter,
663
+ Spec.parse('b', 'npm:foo@^1.0.0', specOptions),
664
+ 'prod',
665
+ foo,
666
+ )
667
+
668
+ // Add edge for custom registry aliased dependency 'c'
669
+ newEdge(
670
+ graph.mainImporter,
671
+ Spec.parse('c', 'custom:c@^1.0.0', specOptions),
672
+ 'prod',
673
+ c,
674
+ )
675
+
676
+ // Add edge for nested aliased dependency 'bar' -> 'd'
677
+ newEdge(
678
+ foo,
679
+ Spec.parse('bar', 'npm:d@^1.0.0', specOptions),
680
+ 'prod',
681
+ d,
682
+ )
683
+
684
+ return graph
685
+ }
686
+
687
+ // Returns a graph with path-based dependencies for testing :path() selector
688
+ //
689
+ // flowchart TD
690
+ // root --> a:::workspace
691
+ // root --> b:::workspace
692
+ // root --> c:::workspace
693
+ // c --> b
694
+ // b --> a
695
+ // c --> x:::file
696
+ // b --> x:::file
697
+ // c --> y:::file
698
+ //
699
+ // classDef workspace fill:skyblue
700
+ // classDef file fill:lightgray
701
+ // classDef dev fill:palegreen
702
+ // classDef optional fill:cornsilk
703
+ //
704
+ export const getPathBasedGraph = (): GraphLike => {
705
+ const graph = newGraph('path-based-project')
706
+ const addNode = newNode(graph)
707
+
708
+ // Create workspace nodes
709
+ const a = addNode('a')
710
+ a.id = joinDepIDTuple(['workspace', 'packages/a'])
711
+ a.location = 'packages/a'
712
+ a.importer = true
713
+
714
+ const b = addNode('b')
715
+ b.id = joinDepIDTuple(['workspace', 'packages/b'])
716
+ b.location = 'packages/b'
717
+ b.importer = true
718
+
719
+ const c = addNode('c')
720
+ c.id = joinDepIDTuple(['workspace', 'c'])
721
+ c.location = 'c'
722
+ c.importer = true
723
+
724
+ // Create file nodes
725
+ const x = addNode('x')
726
+ x.id = joinDepIDTuple(['file', 'x'])
727
+ x.location = 'x'
728
+
729
+ const y = addNode('y')
730
+ y.id = joinDepIDTuple(['file', 'packages/a/y'])
731
+ y.location = 'packages/a/y'
732
+
733
+ // Add nodes to graph
734
+ ;[a, b, c, x, y].forEach(i => {
735
+ graph.nodes.set(i.id, i)
736
+ })
737
+
738
+ // Add workspace nodes as importers
739
+ graph.importers.add(a)
740
+ graph.importers.add(b)
741
+ graph.importers.add(c)
742
+
743
+ // Set up workspaces property on mainImporter
744
+ graph.mainImporter.workspaces = new Map()
745
+ graph.mainImporter.workspaces.set('a', {
746
+ name: 'a',
747
+ from: graph.mainImporter,
748
+ spec: Spec.parse('a', 'workspace:*', specOptions),
749
+ type: 'prod',
750
+ } satisfies EdgeLike)
751
+ graph.mainImporter.workspaces.set('b', {
752
+ name: 'b',
753
+ from: graph.mainImporter,
754
+ spec: Spec.parse('b', 'workspace:*', specOptions),
755
+ type: 'prod',
756
+ } satisfies EdgeLike)
757
+ graph.mainImporter.workspaces.set('c', {
758
+ name: 'c',
759
+ from: graph.mainImporter,
760
+ spec: Spec.parse('c', 'workspace:*', specOptions),
761
+ type: 'prod',
762
+ } satisfies EdgeLike)
763
+
764
+ // Add edges to create the dependency structure
765
+ newEdge(
766
+ graph.mainImporter,
767
+ Spec.parse('a', 'workspace:*', specOptions),
768
+ 'prod',
769
+ a,
770
+ )
771
+ newEdge(
772
+ graph.mainImporter,
773
+ Spec.parse('b', 'workspace:*', specOptions),
774
+ 'prod',
775
+ b,
776
+ )
777
+ newEdge(
778
+ graph.mainImporter,
779
+ Spec.parse('c', 'workspace:*', specOptions),
780
+ 'prod',
781
+ c,
782
+ )
783
+
784
+ // c -> b
785
+ newEdge(c, Spec.parse('b', 'workspace:*', specOptions), 'prod', b)
786
+
787
+ // b -> a
788
+ newEdge(b, Spec.parse('a', 'workspace:*', specOptions), 'prod', a)
789
+
790
+ // c -> x
791
+ newEdge(c, Spec.parse('x', 'file:x', specOptions), 'prod', x)
792
+
793
+ // b -> x
794
+ newEdge(b, Spec.parse('x', 'file:x', specOptions), 'prod', x)
795
+
796
+ // c -> y
797
+ newEdge(
798
+ c,
799
+ Spec.parse('y', 'file:packages/a/y', specOptions),
800
+ 'prod',
801
+ y,
802
+ )
803
+
804
+ return graph
805
+ }
806
+
807
+ // Returns a graph with git dependencies for testing :hostname() selector
808
+ //
809
+ // git-project (#a:prod[github], #b:prod[gitlab], #c:prod[full-url-git])
810
+ // +-- a (github:user/repo)
811
+ // +-- b (gitlab:user/repo)
812
+ // +-- c (git+ssh://git@custom-git.example.com/repo.git)
813
+ //
814
+ export const getGitGraph = (): GraphLike => {
815
+ const graph = newGraph('git-project')
816
+ const addNode = newNode(graph)
817
+
818
+ const a = addNode('a')
819
+ a.id = joinDepIDTuple(['git', 'github:user/repo', 'semver:^1.0.0'])
820
+ graph.nodes.set(a.id, a)
821
+
822
+ const b = addNode('b')
823
+ b.id = joinDepIDTuple(['git', 'gitlab:user/repo', 'semver:^1.0.0'])
824
+ graph.nodes.set(b.id, b)
825
+
826
+ const c = addNode('c')
827
+ c.id = joinDepIDTuple([
828
+ 'git',
829
+ 'git+ssh://git@custom-git.example.com/repo.git',
830
+ 'semver:^1.0.0',
831
+ ])
832
+ graph.nodes.set(c.id, c)
833
+
834
+ newEdge(
835
+ graph.mainImporter,
836
+ Spec.parse('a', 'github:user/repo', specOptions),
837
+ 'prod',
838
+ a,
839
+ )
840
+ newEdge(
841
+ graph.mainImporter,
842
+ Spec.parse('b', 'gitlab:user/repo', specOptions),
843
+ 'prod',
844
+ b,
845
+ )
846
+ newEdge(
847
+ graph.mainImporter,
848
+ Spec.parse(
849
+ 'c',
850
+ 'git+ssh://git@custom-git.example.com/repo.git',
851
+ specOptions,
852
+ ),
853
+ 'prod',
854
+ c,
855
+ )
856
+
857
+ return graph
858
+ }
859
+
860
+ // Returns a graph with a dep from an unknown registry name
861
+ // (to test the fallback to options.registry)
862
+ //
863
+ // unknown-registry-project (#a:prod[unknownreg])
864
+ // +-- a (from registry "unknownreg" that doesn't exist in registries map)
865
+ //
866
+ export const getUnknownRegistryGraph = (): GraphLike => {
867
+ const graph = newGraph('unknown-registry-project')
868
+ const addNode = newNode(graph)
869
+
870
+ const a = addNode('a')
871
+ a.id = joinDepIDTuple(['registry', 'unknownreg', 'a@1.0.0'])
872
+ graph.nodes.set(a.id, a)
873
+
874
+ newEdge(
875
+ graph.mainImporter,
876
+ Spec.parse('a', '^1.0.0', specOptions),
877
+ 'prod',
878
+ a,
879
+ )
880
+
881
+ return graph
882
+ }
883
+
884
+ // Returns a graph with a custom named git host (not in gitHostWebsites)
885
+ // to test the fallback path that parses git-hosts template URLs
886
+ //
887
+ // custom-git-host-project (#a:prod[customhost])
888
+ // +-- a (customhost:user/repo)
889
+ //
890
+ export const getCustomGitHostGraph = (): GraphLike => {
891
+ const graph = newGraph('custom-git-host-project')
892
+ const addNode = newNode(graph)
893
+
894
+ const a = addNode('a')
895
+ a.id = joinDepIDTuple([
896
+ 'git',
897
+ 'customhost:user/repo',
898
+ 'semver:^1.0.0',
899
+ ])
900
+ // Override options to include custom git host
901
+ a.options = {
902
+ ...specOptions,
903
+ 'git-hosts': {
904
+ customhost: 'git+ssh://git@myserver.example.com:$1/$2.git',
905
+ },
906
+ }
907
+ graph.nodes.set(a.id, a)
908
+
909
+ newEdge(
910
+ graph.mainImporter,
911
+ Spec.parse('a', 'github:user/repo', specOptions),
912
+ 'prod',
913
+ a,
914
+ )
915
+
916
+ return graph
917
+ }
918
+
919
+ // Returns a graph with a git dep whose remote is an
920
+ // unparseable URL (to cover the catch branch)
921
+ //
922
+ // broken-git-project (#a:prod[broken-git])
923
+ // +-- a (notahost:broken:url)
924
+ //
925
+ export const getBrokenGitGraph = (): GraphLike => {
926
+ const graph = newGraph('broken-git-project')
927
+ const addNode = newNode(graph)
928
+
929
+ const a = addNode('a')
930
+ a.id = joinDepIDTuple([
931
+ 'git',
932
+ 'notahost:broken:url',
933
+ 'semver:^1.0.0',
934
+ ])
935
+ graph.nodes.set(a.id, a)
936
+
937
+ newEdge(
938
+ graph.mainImporter,
939
+ Spec.parse('a', 'github:user/repo', specOptions),
940
+ 'prod',
941
+ a,
942
+ )
943
+
944
+ return graph
945
+ }
946
+
947
+ // Returns a graph with an https:// git remote (plain URL, no named host)
948
+ //
949
+ // https-git-project (#a:prod[https-git])
950
+ // +-- a (https://git.example.org/repo.git)
951
+ //
952
+ export const getHttpsGitGraph = (): GraphLike => {
953
+ const graph = newGraph('https-git-project')
954
+ const addNode = newNode(graph)
955
+
956
+ const a = addNode('a')
957
+ a.id = joinDepIDTuple([
958
+ 'git',
959
+ 'https://git.example.org/repo.git',
960
+ 'semver:^1.0.0',
961
+ ])
962
+ graph.nodes.set(a.id, a)
963
+
964
+ newEdge(
965
+ graph.mainImporter,
966
+ Spec.parse(
967
+ 'a',
968
+ 'git+https://git.example.org/repo.git',
969
+ specOptions,
970
+ ),
971
+ 'prod',
972
+ a,
973
+ )
974
+
975
+ return graph
976
+ }
977
+
978
+ // Returns a graph with a remote (URL) dependency
979
+ //
980
+ // remote-project (#a:prod[remote])
981
+ // +-- a (https://cdn.example.com/pkg.tgz)
982
+ //
983
+ export const getRemoteGraph = (): GraphLike => {
984
+ const graph = newGraph('remote-project')
985
+ const addNode = newNode(graph)
986
+
987
+ const a = addNode('a')
988
+ a.id = joinDepIDTuple(['remote', 'https://cdn.example.com/pkg.tgz'])
989
+ graph.nodes.set(a.id, a)
990
+
991
+ newEdge(
992
+ graph.mainImporter,
993
+ Spec.parse('a', 'https://cdn.example.com/pkg.tgz', specOptions),
994
+ 'prod',
995
+ a,
996
+ )
997
+
998
+ return graph
999
+ }