@vltpkg/query 1.4.0 → 1.6.0

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 (213) hide show
  1. package/dist/index.d.ts +7 -2
  2. package/dist/index.js +23 -4
  3. package/dist/pseudo/skill.d.ts +7 -0
  4. package/dist/pseudo/skill.js +52 -0
  5. package/dist/pseudo/skills.d.ts +6 -0
  6. package/dist/pseudo/skills.js +26 -0
  7. package/dist/pseudo.js +7 -0
  8. package/dist/types.d.ts +29 -1
  9. package/package.json +10 -12
  10. package/skills/dss-query/REFERENCE.md +0 -123
  11. package/skills/dss-query/SKILL.md +0 -190
  12. package/skills/dss-query/evals/README.md +0 -81
  13. package/skills/dss-query/evals/evals.json +0 -89
  14. package/skills/dss-query/evals/grade.mjs +0 -481
  15. package/src/attribute.ts +0 -190
  16. package/src/combinator.ts +0 -135
  17. package/src/error.ts +0 -78
  18. package/src/id.ts +0 -46
  19. package/src/index.ts +0 -640
  20. package/src/parser.ts +0 -122
  21. package/src/pseudo/abandoned.ts +0 -9
  22. package/src/pseudo/attr.ts +0 -92
  23. package/src/pseudo/built.ts +0 -19
  24. package/src/pseudo/confused.ts +0 -29
  25. package/src/pseudo/cve.ts +0 -93
  26. package/src/pseudo/cwe.ts +0 -97
  27. package/src/pseudo/debug.ts +0 -9
  28. package/src/pseudo/deprecated.ts +0 -9
  29. package/src/pseudo/dev.ts +0 -18
  30. package/src/pseudo/diff.ts +0 -90
  31. package/src/pseudo/dist.ts +0 -148
  32. package/src/pseudo/dynamic.ts +0 -9
  33. package/src/pseudo/empty.ts +0 -15
  34. package/src/pseudo/entropic.ts +0 -9
  35. package/src/pseudo/env.ts +0 -6
  36. package/src/pseudo/eval.ts +0 -9
  37. package/src/pseudo/fs.ts +0 -9
  38. package/src/pseudo/helpers.ts +0 -106
  39. package/src/pseudo/host.ts +0 -111
  40. package/src/pseudo/hostname.ts +0 -156
  41. package/src/pseudo/license.ts +0 -134
  42. package/src/pseudo/link.ts +0 -30
  43. package/src/pseudo/malware.ts +0 -41
  44. package/src/pseudo/minified.ts +0 -9
  45. package/src/pseudo/missing.ts +0 -16
  46. package/src/pseudo/native.ts +0 -9
  47. package/src/pseudo/network.ts +0 -9
  48. package/src/pseudo/obfuscated.ts +0 -9
  49. package/src/pseudo/optional.ts +0 -18
  50. package/src/pseudo/outdated.ts +0 -345
  51. package/src/pseudo/overridden.ts +0 -20
  52. package/src/pseudo/path.ts +0 -146
  53. package/src/pseudo/peer.ts +0 -18
  54. package/src/pseudo/prerelease.ts +0 -47
  55. package/src/pseudo/private.ts +0 -19
  56. package/src/pseudo/prod.ts +0 -18
  57. package/src/pseudo/published.ts +0 -250
  58. package/src/pseudo/registry.ts +0 -29
  59. package/src/pseudo/root.ts +0 -19
  60. package/src/pseudo/scanned.ts +0 -20
  61. package/src/pseudo/score.ts +0 -186
  62. package/src/pseudo/scripts.ts +0 -61
  63. package/src/pseudo/semver.ts +0 -320
  64. package/src/pseudo/severity.ts +0 -231
  65. package/src/pseudo/shell.ts +0 -9
  66. package/src/pseudo/shrinkwrap.ts +0 -9
  67. package/src/pseudo/spec.ts +0 -131
  68. package/src/pseudo/squat.ts +0 -225
  69. package/src/pseudo/suspicious.ts +0 -9
  70. package/src/pseudo/tracker.ts +0 -9
  71. package/src/pseudo/trivial.ts +0 -9
  72. package/src/pseudo/type.ts +0 -26
  73. package/src/pseudo/undesirable.ts +0 -9
  74. package/src/pseudo/unknown.ts +0 -9
  75. package/src/pseudo/unmaintained.ts +0 -9
  76. package/src/pseudo/unpopular.ts +0 -9
  77. package/src/pseudo/unstable.ts +0 -9
  78. package/src/pseudo/vuln.ts +0 -273
  79. package/src/pseudo/workspace.ts +0 -22
  80. package/src/pseudo.ts +0 -433
  81. package/src/types.ts +0 -176
  82. package/tap-snapshots/test/attribute.ts.test.cjs +0 -304
  83. package/tap-snapshots/test/combinator.ts.test.cjs +0 -333
  84. package/tap-snapshots/test/id.ts.test.cjs +0 -118
  85. package/tap-snapshots/test/parser.ts.test.cjs +0 -344
  86. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +0 -18
  87. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +0 -161
  88. package/tap-snapshots/test/pseudo/built.ts.test.cjs +0 -70
  89. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +0 -32
  90. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +0 -49
  91. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +0 -49
  92. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +0 -18
  93. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +0 -18
  94. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +0 -30
  95. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +0 -18
  96. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +0 -50
  97. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +0 -18
  98. package/tap-snapshots/test/pseudo/env.ts.test.cjs +0 -18
  99. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +0 -18
  100. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +0 -18
  101. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +0 -18
  102. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +0 -148
  103. package/tap-snapshots/test/pseudo/license.ts.test.cjs +0 -41
  104. package/tap-snapshots/test/pseudo/link.ts.test.cjs +0 -36
  105. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +0 -22
  106. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +0 -18
  107. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +0 -30
  108. package/tap-snapshots/test/pseudo/native.ts.test.cjs +0 -18
  109. package/tap-snapshots/test/pseudo/network.ts.test.cjs +0 -18
  110. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +0 -18
  111. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +0 -132
  112. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +0 -75
  113. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +0 -101
  114. package/tap-snapshots/test/pseudo/private.ts.test.cjs +0 -38
  115. package/tap-snapshots/test/pseudo/published.ts.test.cjs +0 -171
  116. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +0 -68
  117. package/tap-snapshots/test/pseudo/root.ts.test.cjs +0 -24
  118. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +0 -18
  119. package/tap-snapshots/test/pseudo/score.ts.test.cjs +0 -239
  120. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +0 -62
  121. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +0 -575
  122. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +0 -122
  123. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +0 -18
  124. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +0 -18
  125. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +0 -148
  126. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +0 -129
  127. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +0 -18
  128. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +0 -18
  129. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +0 -18
  130. package/tap-snapshots/test/pseudo/type.ts.test.cjs +0 -51
  131. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +0 -18
  132. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +0 -18
  133. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +0 -18
  134. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +0 -18
  135. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +0 -18
  136. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +0 -208
  137. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +0 -20
  138. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +0 -19
  139. package/tap-snapshots/test/pseudo.ts.test.cjs +0 -1247
  140. package/test/attribute.ts +0 -273
  141. package/test/combinator.ts +0 -175
  142. package/test/error.ts +0 -60
  143. package/test/fixtures/graph.ts +0 -999
  144. package/test/fixtures/selector.ts +0 -103
  145. package/test/fixtures/types.ts +0 -7
  146. package/test/id.ts +0 -102
  147. package/test/index.ts +0 -1049
  148. package/test/parser.ts +0 -117
  149. package/test/pseudo/abandoned.ts +0 -98
  150. package/test/pseudo/attr.ts +0 -298
  151. package/test/pseudo/built.ts +0 -214
  152. package/test/pseudo/confused.ts +0 -160
  153. package/test/pseudo/cve.ts +0 -249
  154. package/test/pseudo/cwe.ts +0 -255
  155. package/test/pseudo/debug.ts +0 -98
  156. package/test/pseudo/deprecated.ts +0 -98
  157. package/test/pseudo/dev.ts +0 -61
  158. package/test/pseudo/diff.ts +0 -417
  159. package/test/pseudo/dist.ts +0 -215
  160. package/test/pseudo/dynamic.ts +0 -98
  161. package/test/pseudo/empty.ts +0 -108
  162. package/test/pseudo/entropic.ts +0 -101
  163. package/test/pseudo/env.ts +0 -98
  164. package/test/pseudo/eval.ts +0 -98
  165. package/test/pseudo/fs.ts +0 -98
  166. package/test/pseudo/helpers.ts +0 -370
  167. package/test/pseudo/host-context.ts +0 -276
  168. package/test/pseudo/hostname.ts +0 -314
  169. package/test/pseudo/license.ts +0 -265
  170. package/test/pseudo/link.ts +0 -94
  171. package/test/pseudo/malware.ts +0 -184
  172. package/test/pseudo/minified.ts +0 -98
  173. package/test/pseudo/missing.ts +0 -111
  174. package/test/pseudo/native.ts +0 -98
  175. package/test/pseudo/network.ts +0 -98
  176. package/test/pseudo/obfuscated.ts +0 -98
  177. package/test/pseudo/optional.ts +0 -73
  178. package/test/pseudo/outdated.ts +0 -461
  179. package/test/pseudo/overridden.ts +0 -317
  180. package/test/pseudo/path.ts +0 -680
  181. package/test/pseudo/peer.ts +0 -101
  182. package/test/pseudo/prerelease.ts +0 -279
  183. package/test/pseudo/private.ts +0 -108
  184. package/test/pseudo/prod.ts +0 -61
  185. package/test/pseudo/published.ts +0 -557
  186. package/test/pseudo/registry.ts +0 -122
  187. package/test/pseudo/root.ts +0 -66
  188. package/test/pseudo/scanned.ts +0 -144
  189. package/test/pseudo/score.ts +0 -591
  190. package/test/pseudo/scripts.ts +0 -324
  191. package/test/pseudo/semver.ts +0 -822
  192. package/test/pseudo/severity.ts +0 -342
  193. package/test/pseudo/shell.ts +0 -98
  194. package/test/pseudo/shrinkwrap.ts +0 -98
  195. package/test/pseudo/spec.ts +0 -525
  196. package/test/pseudo/squat.ts +0 -565
  197. package/test/pseudo/suspicious.ts +0 -98
  198. package/test/pseudo/tracker.ts +0 -98
  199. package/test/pseudo/trivial.ts +0 -98
  200. package/test/pseudo/type.ts +0 -105
  201. package/test/pseudo/undesirable.ts +0 -98
  202. package/test/pseudo/unknown.ts +0 -98
  203. package/test/pseudo/unmaintained.ts +0 -98
  204. package/test/pseudo/unpopular.ts +0 -98
  205. package/test/pseudo/unstable.ts +0 -98
  206. package/test/pseudo/vuln.ts +0 -625
  207. package/test/pseudo/vulnerable.ts +0 -137
  208. package/test/pseudo/workspace.ts +0 -111
  209. package/test/pseudo.ts +0 -584
  210. package/tsconfig.json +0 -3
  211. package/tsconfig.publish.json +0 -19
  212. package/tsconfig.publish.tsbuildinfo +0 -1
  213. package/typedoc.mjs +0 -2
package/src/index.ts DELETED
@@ -1,640 +0,0 @@
1
- import { joinDepIDTuple } from '@vltpkg/dep-id/browser'
2
- import {
3
- parse,
4
- isPostcssNodeWithChildren,
5
- asPostcssNodeWithChildren,
6
- isSelectorNode,
7
- isPseudoNode,
8
- isIdentifierNode,
9
- isAttributeNode,
10
- } from '@vltpkg/dss-parser'
11
- import { attribute } from './attribute.ts'
12
- import { combinator } from './combinator.ts'
13
- import { id } from './id.ts'
14
- import { pseudo, pseudoSelectorNames } from './pseudo.ts'
15
- import { queryError, selectorText } from './error.ts'
16
- import type { EdgeLike, NodeLike } from '@vltpkg/types'
17
- import type { SecurityArchiveLike } from '@vltpkg/security-archive'
18
- import type {
19
- PostcssNode,
20
- PostcssNodeWithChildren,
21
- } from '@vltpkg/dss-parser'
22
- import type {
23
- DiffFilesProvider,
24
- GetAuthHeader,
25
- HostContextsMap,
26
- ParsedSelectorToken,
27
- ParserState,
28
- ParserFn,
29
- QueryResponse,
30
- QueryResponseNode,
31
- QueryResponseEdge,
32
- } from './types.ts'
33
- import type { DepID } from '@vltpkg/dep-id'
34
-
35
- export * from './types.ts'
36
-
37
- export type SearchOptions = {
38
- signal: AbortSignal
39
- scopeIDs?: DepID[]
40
- }
41
-
42
- const noopFn = async (state: ParserState) => state
43
-
44
- /**
45
- * `.dev` and a bare `dev` are the two ways a css habit shows up in a
46
- * query. Neither is valid DSS, but the intent is usually a pseudo-class
47
- * of that name, and otherwise a package name.
48
- */
49
- const unsupportedName = (state: ParserState) => {
50
- const text = selectorText(state.current)
51
- const name = text.replace(/^[.#]/, '')
52
- return queryError('Unsupported selector', state.current, {
53
- wanted:
54
- pseudoSelectorNames.has(name) ? `:${name}`
55
- : name ? `#${name}`
56
- : undefined,
57
- })
58
- }
59
-
60
- const selectors = {
61
- attribute,
62
- /* c8 ignore start -- dss-parser reports `.foo` as an escaped tag */
63
- class: async (state: ParserState) => {
64
- throw unsupportedName(state)
65
- },
66
- /* c8 ignore end */
67
- combinator,
68
- comment: async (state: ParserState) => {
69
- if (state.current.value && !state.comment) {
70
- const commentValue = state.current.value
71
- const cleanComment = commentValue
72
- .replace(/^\/\*/, '')
73
- .replace(/\*\/$/, '')
74
- .trim()
75
- state.comment = cleanComment
76
- }
77
- return state
78
- },
79
- id,
80
- nesting: noopFn,
81
- pseudo,
82
- root: noopFn,
83
- selector: async (state: ParserState) => {
84
- state.partial.nodes = new Set(state.initial.nodes)
85
- state.partial.edges = new Set(state.initial.edges)
86
- return state
87
- },
88
- string: async (state: ParserState) => {
89
- throw queryError('Unsupported selector', state.current)
90
- },
91
- tag: async (state: ParserState) => {
92
- if (state.current.value !== '{' && state.current.value !== '}') {
93
- throw unsupportedName(state)
94
- }
95
- return state
96
- },
97
- universal: noopFn,
98
- }
99
- const selectorsMap = new Map<string, ParserFn>(
100
- Object.entries(selectors),
101
- )
102
-
103
- export const walk = async (
104
- state: ParserState,
105
- ): Promise<ParserState> => {
106
- await state.cancellable()
107
-
108
- const parserFn = selectorsMap.get(state.current.type)
109
-
110
- if (!parserFn) {
111
- if (state.loose) {
112
- return state
113
- }
114
-
115
- throw queryError(
116
- `Missing parser for query node: ${state.current.type}`,
117
- state.current,
118
- )
119
- }
120
- state = await parserFn(state)
121
-
122
- // pseudo selectors handle their own sub selectors
123
- if (
124
- isPostcssNodeWithChildren(state.current) &&
125
- state.current.type !== 'pseudo'
126
- ) {
127
- const node: PostcssNodeWithChildren = asPostcssNodeWithChildren(
128
- state.current,
129
- )
130
-
131
- if (node.nodes.length) {
132
- for (let i = 0; i < node.nodes.length; i++) {
133
- const current = node.nodes[i]
134
- /* c8 ignore next -- impossible but TS doesn't know that */
135
- if (!current) continue
136
-
137
- const childState: ParserState = {
138
- ...state,
139
- current,
140
- next: node.nodes[i + 1],
141
- prev: node.nodes[i - 1],
142
- }
143
- state = await walk(childState)
144
- }
145
- }
146
-
147
- if (isSelectorNode(node)) {
148
- for (const edge of state.partial.edges) {
149
- state.collect.edges.add(edge)
150
- }
151
- for (const node of state.partial.nodes) {
152
- state.collect.nodes.add(node)
153
- }
154
- }
155
- }
156
- return state
157
- }
158
-
159
- export type QueryOptions = {
160
- edges: Set<EdgeLike>
161
- nodes: Set<NodeLike>
162
- importers: Set<NodeLike>
163
- retries?: number
164
- securityArchive: SecurityArchiveLike | undefined
165
- hostContexts?: HostContextsMap
166
- diffFiles?: DiffFilesProvider
167
- getAuthHeader?: GetAuthHeader
168
- }
169
-
170
- // A list of known security selectors that rely on
171
- // data from the security-archive in order to work
172
- const securitySelectors = new Set([
173
- ':abandoned',
174
- ':confused',
175
- ':cve',
176
- ':cwe',
177
- ':debug',
178
- ':deprecated',
179
- ':dynamic',
180
- ':entropic',
181
- ':env',
182
- ':eval',
183
- ':fs',
184
- ':license',
185
- ':malware',
186
- ':minified',
187
- ':native',
188
- ':network',
189
- ':obfuscated',
190
- ':scanned',
191
- ':score',
192
- ':sev',
193
- ':severity',
194
- ':shell',
195
- ':shrinkwrap',
196
- ':squat',
197
- ':suspicious',
198
- ':tracker',
199
- ':trivial',
200
- ':undesirable',
201
- ':unknown',
202
- ':unmaintained',
203
- ':unpopular',
204
- ':unstable',
205
- ':vuln',
206
- ':vulnerable',
207
- ])
208
-
209
- const setMethodToJSON = (node: QueryResponseNode) => {
210
- const { toJSON } = node
211
- const insights = node.insights
212
- node.toJSON = () => ({
213
- ...toJSON.call(node),
214
- insights,
215
- })
216
- }
217
-
218
- /**
219
- * The Query class is used to search the graph for nodes and edges
220
- * using the Dependency Selector Syntax (DSS).
221
- */
222
- export class Query {
223
- #cache: Map<string, QueryResponse>
224
- #diffFiles: DiffFilesProvider | undefined
225
- #getAuthHeader: GetAuthHeader | undefined
226
- #edges: Set<EdgeLike>
227
- #nodes: Set<NodeLike>
228
- #importers: Set<NodeLike>
229
- #retries: number
230
- #securityArchive: SecurityArchiveLike | undefined
231
- #hostContexts: HostContextsMap | undefined
232
-
233
- /**
234
- * Helper method to determine if a given query string is using any of
235
- * the known security selectors. This is useful so that operations can
236
- * skip hydrating the security archive if it's not needed.
237
- */
238
- static hasSecuritySelectors(query: string): boolean {
239
- for (const selector of securitySelectors) {
240
- if (query.includes(selector)) {
241
- return true
242
- }
243
- }
244
- return false
245
- }
246
-
247
- /**
248
- * Sorts an array of QueryResponse objects by specificity. Objects with
249
- * higher idCounter values come first, if idCounter values are equal,
250
- * then objects with higher commonCounter values come first. Otherwise,
251
- * the original order is preserved.
252
- */
253
- static specificitySort(
254
- responses: QueryResponse[],
255
- ): QueryResponse[] {
256
- return [...responses].sort((a, b) => {
257
- // First compare by idCounter (higher comes first)
258
- if (a.specificity.idCounter !== b.specificity.idCounter) {
259
- return b.specificity.idCounter - a.specificity.idCounter
260
- }
261
-
262
- // If idCounter values are equal, compare by commonCounter
263
- if (
264
- a.specificity.commonCounter !== b.specificity.commonCounter
265
- ) {
266
- return (
267
- b.specificity.commonCounter - a.specificity.commonCounter
268
- )
269
- }
270
-
271
- // If both counters are equal, preserve original order
272
- return 0
273
- })
274
- }
275
-
276
- constructor({
277
- edges,
278
- nodes,
279
- importers,
280
- retries,
281
- securityArchive,
282
- hostContexts,
283
- diffFiles,
284
- getAuthHeader,
285
- }: QueryOptions) {
286
- this.#cache = new Map()
287
- this.#diffFiles = diffFiles
288
- this.#getAuthHeader = getAuthHeader
289
- this.#edges = edges
290
- this.#nodes = nodes
291
- this.#importers = importers
292
- this.#retries = retries ?? 3
293
- this.#securityArchive = securityArchive
294
- this.#hostContexts = hostContexts
295
- }
296
-
297
- #getQueryResponseEdges(_edges: Set<EdgeLike>): QueryResponseEdge[] {
298
- return Array.from(_edges) as QueryResponseEdge[]
299
- }
300
-
301
- #getQueryResponseNodes(_nodes: Set<NodeLike>): QueryResponseNode[] {
302
- const nodes = Array.from(_nodes) as QueryResponseNode[]
303
- for (const node of nodes) {
304
- const securityArchiveEntry = this.#securityArchive?.get(node.id)
305
-
306
- // if a security archive entry is not found then the insights object
307
- // should just be empty with scanned=false
308
- if (!securityArchiveEntry) {
309
- node.insights = {
310
- scanned: false,
311
- }
312
-
313
- setMethodToJSON(node)
314
- continue
315
- }
316
-
317
- // if a security archive entry is found then we can populate the insights
318
- node.insights = {
319
- scanned: true,
320
- score: securityArchiveEntry.score,
321
- abandoned: securityArchiveEntry.alerts.some(
322
- i => i.type === 'missingAuthor',
323
- ),
324
- confused: securityArchiveEntry.alerts.some(
325
- i => i.type === 'manifestConfusion',
326
- ),
327
- cve: securityArchiveEntry.alerts
328
- .map(i => i.props?.cveId)
329
- .filter(i => i !== undefined),
330
- cwe: Array.from(
331
- new Set(
332
- securityArchiveEntry.alerts
333
- .filter(i => i.props?.cveId)
334
- .flatMap(i => i.props?.cwes?.map(j => j.id)),
335
- ),
336
- ) as `CWE-${string}`[],
337
- debug: securityArchiveEntry.alerts.some(
338
- i => i.type === 'debugAccess',
339
- ),
340
- deprecated: securityArchiveEntry.alerts.some(
341
- i => i.type === 'deprecated',
342
- ),
343
- dynamic: securityArchiveEntry.alerts.some(
344
- i => i.type === 'dynamicRequire',
345
- ),
346
- entropic: securityArchiveEntry.alerts.some(
347
- i => i.type === 'highEntropyStrings',
348
- ),
349
- env: securityArchiveEntry.alerts.some(
350
- i => i.type === 'envVars',
351
- ),
352
- eval: securityArchiveEntry.alerts.some(
353
- i => i.type === 'usesEval',
354
- ),
355
- fs: securityArchiveEntry.alerts.some(
356
- i => i.type === 'filesystemAccess',
357
- ),
358
- license: {
359
- unlicensed: securityArchiveEntry.alerts.some(
360
- i => i.type === 'explicitlyUnlicensedItem',
361
- ),
362
- misc: securityArchiveEntry.alerts.some(
363
- i => i.type === 'miscLicenseIssues',
364
- ),
365
- restricted: securityArchiveEntry.alerts.some(
366
- i => i.type === 'nonpermissiveLicense',
367
- ),
368
- ambiguous: securityArchiveEntry.alerts.some(
369
- i => i.type === 'ambiguousClassifier',
370
- ),
371
- copyleft: securityArchiveEntry.alerts.some(
372
- i => i.type === 'copyleftLicense',
373
- ),
374
- unknown: securityArchiveEntry.alerts.some(
375
- i => i.type === 'unidentifiedLicense',
376
- ),
377
- none: securityArchiveEntry.alerts.some(
378
- i => i.type === 'noLicenseFound',
379
- ),
380
- exception: securityArchiveEntry.alerts.some(
381
- i => i.type === 'licenseException',
382
- ),
383
- },
384
- malware: securityArchiveEntry.alerts.some(
385
- i => i.type === 'malware' || i.type === 'gptMalware',
386
- ),
387
- minified: securityArchiveEntry.alerts.some(
388
- i => i.type === 'minifiedFile',
389
- ),
390
- native: securityArchiveEntry.alerts.some(
391
- i => i.type === 'hasNativeCode',
392
- ),
393
- network: securityArchiveEntry.alerts.some(
394
- i => i.type === 'networkAccess',
395
- ),
396
- obfuscated: securityArchiveEntry.alerts.some(
397
- i => i.type === 'obfuscatedFile',
398
- ),
399
- scripts: securityArchiveEntry.alerts.some(
400
- i => i.type === 'installScripts',
401
- ),
402
- severity: {
403
- low: securityArchiveEntry.alerts.some(
404
- i => i.type === 'mildCVE',
405
- ),
406
- medium: securityArchiveEntry.alerts.some(
407
- i => i.type === 'potentialVulnerability',
408
- ),
409
- high: securityArchiveEntry.alerts.some(
410
- i => i.type === 'cve',
411
- ),
412
- critical: securityArchiveEntry.alerts.some(
413
- i => i.type === 'criticalCVE',
414
- ),
415
- },
416
- shell: securityArchiveEntry.alerts.some(
417
- i => i.type === 'shellAccess',
418
- ),
419
- shrinkwrap: securityArchiveEntry.alerts.some(
420
- i => i.type === 'shrinkwrap',
421
- ),
422
- squat: {
423
- medium: securityArchiveEntry.alerts.some(
424
- i => i.type === 'gptDidYouMean',
425
- ),
426
- critical: securityArchiveEntry.alerts.some(
427
- i => i.type === 'didYouMean',
428
- ),
429
- },
430
- suspicious: securityArchiveEntry.alerts.some(
431
- i => i.type === 'suspiciousStarActivity',
432
- ),
433
- tracker: securityArchiveEntry.alerts.some(
434
- i => i.type === 'telemetry',
435
- ),
436
- trivial: securityArchiveEntry.alerts.some(
437
- i => i.type === 'trivialPackage',
438
- ),
439
- undesirable: securityArchiveEntry.alerts.some(
440
- i => i.type === 'troll',
441
- ),
442
- unknown: securityArchiveEntry.alerts.some(
443
- i => i.type === 'newAuthor',
444
- ),
445
- unmaintained: securityArchiveEntry.alerts.some(
446
- i => i.type === 'unmaintained',
447
- ),
448
- unpopular: securityArchiveEntry.alerts.some(
449
- i => i.type === 'unpopularPackage',
450
- ),
451
- unstable: securityArchiveEntry.alerts.some(
452
- i => i.type === 'unstableOwnership',
453
- ),
454
- vuln: {
455
- low: securityArchiveEntry.alerts.some(
456
- i => i.type === 'mildCVE' || i.type === 'gptAnomaly',
457
- ),
458
- medium: securityArchiveEntry.alerts.some(
459
- i =>
460
- i.type === 'potentialVulnerability' ||
461
- i.type === 'gptSecurity',
462
- ),
463
- high: securityArchiveEntry.alerts.some(
464
- i => i.type === 'cve',
465
- ),
466
- critical: securityArchiveEntry.alerts.some(
467
- i => i.type === 'criticalCVE',
468
- ),
469
- },
470
- }
471
-
472
- setMethodToJSON(node)
473
- }
474
- return nodes
475
- }
476
-
477
- /**
478
- * Search the graph for nodes and edges that match the given query.
479
- */
480
- async search(
481
- query: string,
482
- {
483
- signal,
484
- scopeIDs = [joinDepIDTuple(['file', '.'])],
485
- }: SearchOptions,
486
- ): Promise<QueryResponse> {
487
- if (!query)
488
- return {
489
- edges: [],
490
- nodes: [],
491
- importers: [],
492
- comment: '',
493
- specificity: { idCounter: 0, commonCounter: 0 },
494
- }
495
-
496
- const cachedResult = this.#cache.get(query)
497
- if (cachedResult) {
498
- return cachedResult
499
- }
500
-
501
- const nodes = this.#nodes
502
- const edges = this.#edges
503
- const importers = this.#importers
504
-
505
- // includes virtual workspace edges in the searched edges
506
- for (const importer of importers) {
507
- if (!importer.workspaces) continue
508
- for (const edge of importer.workspaces.values()) {
509
- edges.add(edge)
510
- }
511
- }
512
-
513
- // parse the query string into AST
514
- const current = parse(query, { loose: true })
515
- // set loose mode for the entire parse in case there are multiple selectors
516
- // so that using invalid pseudo selectors or other query language parser
517
- // errors won't throw an error,
518
- // e.g: `:root > *, #a, :foo` still returns results for `:root > ` and `#a`
519
- // while :foo is ignored
520
- const loose = asPostcssNodeWithChildren(current).nodes.length > 1
521
- // builds initial state and walks over it,
522
- // retrieving the collected result
523
- const {
524
- collect,
525
- comment,
526
- importers: stateResultImporters,
527
- specificity,
528
- } = await walk({
529
- cancellable: async () => {
530
- await new Promise(resolve => {
531
- setTimeout(resolve, 0)
532
- })
533
- signal.throwIfAborted()
534
- },
535
- current,
536
- initial: {
537
- nodes: new Set(nodes),
538
- edges: new Set(edges),
539
- },
540
- collect: {
541
- nodes: new Set<NodeLike>(),
542
- edges: new Set<EdgeLike>(),
543
- },
544
- comment: '',
545
- diffFiles: this.#diffFiles,
546
- getAuthHeader: this.#getAuthHeader,
547
- loose,
548
- importers,
549
- partial: { nodes, edges },
550
- retries: this.#retries,
551
- signal,
552
- securityArchive: this.#securityArchive,
553
- scopeIDs,
554
- walk,
555
- specificity: { idCounter: 0, commonCounter: 0 },
556
- hostContexts: this.#hostContexts,
557
- })
558
-
559
- const res: QueryResponse = {
560
- edges: this.#getQueryResponseEdges(collect.edges),
561
- nodes: this.#getQueryResponseNodes(collect.nodes),
562
- importers: this.#getQueryResponseNodes(stateResultImporters),
563
- comment,
564
- specificity,
565
- }
566
- this.#cache.set(query, res)
567
- return res
568
- }
569
-
570
- /**
571
- * Parses a query string in order to retrieve an array of tokens.
572
- */
573
- static getQueryTokens(query: string): ParsedSelectorToken[] {
574
- if (!query) return []
575
-
576
- const tokens: ParsedSelectorToken[] = []
577
-
578
- const ast = (q: string) => {
579
- try {
580
- return parse(q, { loose: true })
581
- } catch (_e) {
582
- return ast(q.slice(0, -1))
583
- }
584
- }
585
-
586
- const processNode = (node: PostcssNode) => {
587
- for (const key of selectorsMap.keys()) {
588
- if (node.type === key && node.type !== 'root') {
589
- let token = `${node.spaces.before}${node.value}${node.spaces.after}`
590
-
591
- if (isIdentifierNode(node)) {
592
- token = `${node.spaces.before}#${node.value}${node.spaces.after}`
593
- } else if (isSelectorNode(node)) {
594
- token = `${node.spaces.before},${node.spaces.after}`
595
- } else if (isAttributeNode(node)) {
596
- token = String(
597
- node.source?.start?.column &&
598
- node.source.end?.column &&
599
- `${node.spaces.before}${query.slice(node.source.start.column - 1, node.source.end.column)}${node.spaces.after}`,
600
- )
601
- }
602
-
603
- if (
604
- isPostcssNodeWithChildren(node) &&
605
- isPseudoNode(node) &&
606
- node.nodes.length
607
- ) {
608
- token = String(token.split('(')[0])
609
- token += '('
610
- }
611
-
612
- if (
613
- !isSelectorNode(node) ||
614
- node.parent?.nodes.indexOf(node) !== 0
615
- ) {
616
- tokens.push({
617
- ...node,
618
- token,
619
- } as ParsedSelectorToken)
620
- }
621
- }
622
- }
623
- if (isPostcssNodeWithChildren(node)) {
624
- for (const child of node.nodes) {
625
- processNode(child)
626
- }
627
- if (isPseudoNode(node) && node.nodes.length) {
628
- tokens.push({
629
- ...node,
630
- token: ')' + node.spaces.after,
631
- type: 'pseudo',
632
- } as ParsedSelectorToken)
633
- }
634
- }
635
- }
636
-
637
- processNode(ast(query))
638
- return tokens
639
- }
640
- }