@vltpkg/query 1.5.0 → 1.6.1

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 (211) hide show
  1. package/dist/id.js +12 -5
  2. package/package.json +10 -12
  3. package/skills/dss-query/REFERENCE.md +0 -125
  4. package/skills/dss-query/SKILL.md +0 -190
  5. package/skills/dss-query/evals/README.md +0 -81
  6. package/skills/dss-query/evals/evals.json +0 -89
  7. package/skills/dss-query/evals/grade.mjs +0 -481
  8. package/src/attribute.ts +0 -190
  9. package/src/combinator.ts +0 -135
  10. package/src/error.ts +0 -78
  11. package/src/id.ts +0 -46
  12. package/src/index.ts +0 -670
  13. package/src/parser.ts +0 -122
  14. package/src/pseudo/abandoned.ts +0 -9
  15. package/src/pseudo/attr.ts +0 -92
  16. package/src/pseudo/built.ts +0 -19
  17. package/src/pseudo/confused.ts +0 -29
  18. package/src/pseudo/cve.ts +0 -93
  19. package/src/pseudo/cwe.ts +0 -97
  20. package/src/pseudo/debug.ts +0 -9
  21. package/src/pseudo/deprecated.ts +0 -9
  22. package/src/pseudo/dev.ts +0 -18
  23. package/src/pseudo/diff.ts +0 -90
  24. package/src/pseudo/dist.ts +0 -148
  25. package/src/pseudo/dynamic.ts +0 -9
  26. package/src/pseudo/empty.ts +0 -15
  27. package/src/pseudo/entropic.ts +0 -9
  28. package/src/pseudo/env.ts +0 -6
  29. package/src/pseudo/eval.ts +0 -9
  30. package/src/pseudo/fs.ts +0 -9
  31. package/src/pseudo/helpers.ts +0 -106
  32. package/src/pseudo/host.ts +0 -111
  33. package/src/pseudo/hostname.ts +0 -156
  34. package/src/pseudo/license.ts +0 -134
  35. package/src/pseudo/link.ts +0 -30
  36. package/src/pseudo/malware.ts +0 -41
  37. package/src/pseudo/minified.ts +0 -9
  38. package/src/pseudo/missing.ts +0 -16
  39. package/src/pseudo/native.ts +0 -9
  40. package/src/pseudo/network.ts +0 -9
  41. package/src/pseudo/obfuscated.ts +0 -9
  42. package/src/pseudo/optional.ts +0 -18
  43. package/src/pseudo/outdated.ts +0 -345
  44. package/src/pseudo/overridden.ts +0 -20
  45. package/src/pseudo/path.ts +0 -146
  46. package/src/pseudo/peer.ts +0 -18
  47. package/src/pseudo/prerelease.ts +0 -47
  48. package/src/pseudo/private.ts +0 -19
  49. package/src/pseudo/prod.ts +0 -18
  50. package/src/pseudo/published.ts +0 -250
  51. package/src/pseudo/registry.ts +0 -29
  52. package/src/pseudo/root.ts +0 -19
  53. package/src/pseudo/scanned.ts +0 -20
  54. package/src/pseudo/score.ts +0 -186
  55. package/src/pseudo/scripts.ts +0 -61
  56. package/src/pseudo/semver.ts +0 -320
  57. package/src/pseudo/severity.ts +0 -231
  58. package/src/pseudo/shell.ts +0 -9
  59. package/src/pseudo/shrinkwrap.ts +0 -9
  60. package/src/pseudo/skill.ts +0 -59
  61. package/src/pseudo/skills.ts +0 -29
  62. package/src/pseudo/spec.ts +0 -131
  63. package/src/pseudo/squat.ts +0 -225
  64. package/src/pseudo/suspicious.ts +0 -9
  65. package/src/pseudo/tracker.ts +0 -9
  66. package/src/pseudo/trivial.ts +0 -9
  67. package/src/pseudo/type.ts +0 -26
  68. package/src/pseudo/undesirable.ts +0 -9
  69. package/src/pseudo/unknown.ts +0 -9
  70. package/src/pseudo/unmaintained.ts +0 -9
  71. package/src/pseudo/unpopular.ts +0 -9
  72. package/src/pseudo/unstable.ts +0 -9
  73. package/src/pseudo/vuln.ts +0 -273
  74. package/src/pseudo/workspace.ts +0 -22
  75. package/src/pseudo.ts +0 -440
  76. package/src/types.ts +0 -206
  77. package/tap-snapshots/test/attribute.ts.test.cjs +0 -304
  78. package/tap-snapshots/test/combinator.ts.test.cjs +0 -333
  79. package/tap-snapshots/test/id.ts.test.cjs +0 -118
  80. package/tap-snapshots/test/parser.ts.test.cjs +0 -344
  81. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +0 -18
  82. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +0 -161
  83. package/tap-snapshots/test/pseudo/built.ts.test.cjs +0 -70
  84. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +0 -32
  85. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +0 -49
  86. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +0 -49
  87. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +0 -18
  88. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +0 -18
  89. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +0 -30
  90. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +0 -18
  91. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +0 -50
  92. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +0 -18
  93. package/tap-snapshots/test/pseudo/env.ts.test.cjs +0 -18
  94. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +0 -18
  95. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +0 -18
  96. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +0 -18
  97. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +0 -148
  98. package/tap-snapshots/test/pseudo/license.ts.test.cjs +0 -41
  99. package/tap-snapshots/test/pseudo/link.ts.test.cjs +0 -36
  100. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +0 -22
  101. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +0 -18
  102. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +0 -30
  103. package/tap-snapshots/test/pseudo/native.ts.test.cjs +0 -18
  104. package/tap-snapshots/test/pseudo/network.ts.test.cjs +0 -18
  105. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +0 -18
  106. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +0 -132
  107. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +0 -75
  108. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +0 -101
  109. package/tap-snapshots/test/pseudo/private.ts.test.cjs +0 -38
  110. package/tap-snapshots/test/pseudo/published.ts.test.cjs +0 -171
  111. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +0 -68
  112. package/tap-snapshots/test/pseudo/root.ts.test.cjs +0 -24
  113. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +0 -18
  114. package/tap-snapshots/test/pseudo/score.ts.test.cjs +0 -239
  115. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +0 -62
  116. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +0 -575
  117. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +0 -122
  118. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +0 -18
  119. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +0 -18
  120. package/tap-snapshots/test/pseudo/skills.ts.test.cjs +0 -19
  121. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +0 -148
  122. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +0 -129
  123. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +0 -18
  124. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +0 -18
  125. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +0 -18
  126. package/tap-snapshots/test/pseudo/type.ts.test.cjs +0 -51
  127. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +0 -18
  128. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +0 -18
  129. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +0 -18
  130. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +0 -18
  131. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +0 -18
  132. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +0 -208
  133. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +0 -20
  134. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +0 -19
  135. package/tap-snapshots/test/pseudo.ts.test.cjs +0 -1247
  136. package/test/attribute.ts +0 -273
  137. package/test/combinator.ts +0 -175
  138. package/test/error.ts +0 -60
  139. package/test/fixtures/graph.ts +0 -999
  140. package/test/fixtures/selector.ts +0 -103
  141. package/test/fixtures/types.ts +0 -7
  142. package/test/id.ts +0 -102
  143. package/test/index.ts +0 -1148
  144. package/test/parser.ts +0 -117
  145. package/test/pseudo/abandoned.ts +0 -98
  146. package/test/pseudo/attr.ts +0 -298
  147. package/test/pseudo/built.ts +0 -214
  148. package/test/pseudo/confused.ts +0 -160
  149. package/test/pseudo/cve.ts +0 -249
  150. package/test/pseudo/cwe.ts +0 -255
  151. package/test/pseudo/debug.ts +0 -98
  152. package/test/pseudo/deprecated.ts +0 -98
  153. package/test/pseudo/dev.ts +0 -61
  154. package/test/pseudo/diff.ts +0 -417
  155. package/test/pseudo/dist.ts +0 -215
  156. package/test/pseudo/dynamic.ts +0 -98
  157. package/test/pseudo/empty.ts +0 -108
  158. package/test/pseudo/entropic.ts +0 -101
  159. package/test/pseudo/env.ts +0 -98
  160. package/test/pseudo/eval.ts +0 -98
  161. package/test/pseudo/fs.ts +0 -98
  162. package/test/pseudo/helpers.ts +0 -370
  163. package/test/pseudo/host-context.ts +0 -276
  164. package/test/pseudo/hostname.ts +0 -314
  165. package/test/pseudo/license.ts +0 -265
  166. package/test/pseudo/link.ts +0 -94
  167. package/test/pseudo/malware.ts +0 -184
  168. package/test/pseudo/minified.ts +0 -98
  169. package/test/pseudo/missing.ts +0 -111
  170. package/test/pseudo/native.ts +0 -98
  171. package/test/pseudo/network.ts +0 -98
  172. package/test/pseudo/obfuscated.ts +0 -98
  173. package/test/pseudo/optional.ts +0 -73
  174. package/test/pseudo/outdated.ts +0 -461
  175. package/test/pseudo/overridden.ts +0 -317
  176. package/test/pseudo/path.ts +0 -680
  177. package/test/pseudo/peer.ts +0 -101
  178. package/test/pseudo/prerelease.ts +0 -279
  179. package/test/pseudo/private.ts +0 -108
  180. package/test/pseudo/prod.ts +0 -61
  181. package/test/pseudo/published.ts +0 -557
  182. package/test/pseudo/registry.ts +0 -122
  183. package/test/pseudo/root.ts +0 -66
  184. package/test/pseudo/scanned.ts +0 -144
  185. package/test/pseudo/score.ts +0 -591
  186. package/test/pseudo/scripts.ts +0 -324
  187. package/test/pseudo/semver.ts +0 -822
  188. package/test/pseudo/severity.ts +0 -342
  189. package/test/pseudo/shell.ts +0 -98
  190. package/test/pseudo/shrinkwrap.ts +0 -98
  191. package/test/pseudo/skill.ts +0 -189
  192. package/test/pseudo/skills.ts +0 -90
  193. package/test/pseudo/spec.ts +0 -525
  194. package/test/pseudo/squat.ts +0 -565
  195. package/test/pseudo/suspicious.ts +0 -98
  196. package/test/pseudo/tracker.ts +0 -98
  197. package/test/pseudo/trivial.ts +0 -98
  198. package/test/pseudo/type.ts +0 -105
  199. package/test/pseudo/undesirable.ts +0 -98
  200. package/test/pseudo/unknown.ts +0 -98
  201. package/test/pseudo/unmaintained.ts +0 -98
  202. package/test/pseudo/unpopular.ts +0 -98
  203. package/test/pseudo/unstable.ts +0 -98
  204. package/test/pseudo/vuln.ts +0 -625
  205. package/test/pseudo/vulnerable.ts +0 -137
  206. package/test/pseudo/workspace.ts +0 -111
  207. package/test/pseudo.ts +0 -584
  208. package/tsconfig.json +0 -3
  209. package/tsconfig.publish.json +0 -19
  210. package/tsconfig.publish.tsbuildinfo +0 -1
  211. package/typedoc.mjs +0 -2
@@ -1,231 +0,0 @@
1
- import { error } from '@vltpkg/error-cause'
2
- import {
3
- asPostcssNodeWithChildren,
4
- asStringNode,
5
- asTagNode,
6
- isStringNode,
7
- isTagNode,
8
- } from '@vltpkg/dss-parser'
9
- import {
10
- assertSecurityArchive,
11
- removeDanglingEdges,
12
- removeNode,
13
- removeQuotes,
14
- } from './helpers.ts'
15
- import type { ParserState } from '../types.ts'
16
- import type { PostcssNode } from '@vltpkg/dss-parser'
17
-
18
- export type SeverityKinds =
19
- | '0'
20
- | '1'
21
- | '2'
22
- | '3'
23
- | 'critical'
24
- | 'high'
25
- | 'medium'
26
- | 'low'
27
- | undefined
28
-
29
- export type SeverityAlertTypes =
30
- | 'criticalCVE'
31
- | 'cve'
32
- | 'potentialVulnerability'
33
- | 'mildCVE'
34
- | undefined
35
-
36
- export type SeverityComparator = '>' | '<' | '>=' | '<=' | undefined
37
-
38
- const kindsMap = new Map<SeverityKinds, SeverityAlertTypes>([
39
- ['critical', 'criticalCVE'],
40
- ['high', 'cve'],
41
- ['medium', 'potentialVulnerability'],
42
- ['low', 'mildCVE'],
43
- ['0', 'criticalCVE'],
44
- ['1', 'cve'],
45
- ['2', 'potentialVulnerability'],
46
- ['3', 'mildCVE'],
47
- ])
48
-
49
- // Map numerical values to their respective kinds for comparison operations
50
- const kindLevelMap = new Map<SeverityKinds, number>([
51
- ['critical', 0],
52
- ['high', 1],
53
- ['medium', 2],
54
- ['low', 3],
55
- ['0', 0],
56
- ['1', 1],
57
- ['2', 2],
58
- ['3', 3],
59
- ])
60
-
61
- const kinds = new Set(kindsMap.keys())
62
-
63
- export const isSeverityKind = (
64
- value?: string,
65
- ): value is SeverityKinds => kinds.has(value as SeverityKinds)
66
-
67
- export const asSeverityKind = (value?: string): SeverityKinds => {
68
- if (!isSeverityKind(value)) {
69
- throw error('Expected a valid severity kind', {
70
- found: value,
71
- validOptions: Array.from(kinds),
72
- })
73
- }
74
- return value
75
- }
76
-
77
- export const parseInternals = (
78
- nodes: PostcssNode[],
79
- ): {
80
- kind: SeverityKinds
81
- comparator: SeverityComparator
82
- } => {
83
- let kind: SeverityKinds
84
- let comparator: SeverityComparator
85
-
86
- if (nodes.length === 0) {
87
- throw error('Missing severity kind parameter')
88
- }
89
-
90
- let kindValue = ''
91
- if (isStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])) {
92
- kindValue = removeQuotes(
93
- asStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
94
- .value,
95
- )
96
- } else if (
97
- isTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
98
- ) {
99
- kindValue = asTagNode(
100
- asPostcssNodeWithChildren(nodes[0]).nodes[0],
101
- ).value
102
- }
103
-
104
- // Extract comparator if present
105
- if (kindValue.startsWith('>=')) {
106
- comparator = '>='
107
- kindValue = kindValue.substring(2)
108
- } else if (kindValue.startsWith('<=')) {
109
- comparator = '<='
110
- kindValue = kindValue.substring(2)
111
- } else if (kindValue.startsWith('>')) {
112
- comparator = '>'
113
- kindValue = kindValue.substring(1)
114
- } else if (kindValue.startsWith('<')) {
115
- comparator = '<'
116
- kindValue = kindValue.substring(1)
117
- }
118
-
119
- // Parse kind value
120
- if (kindValue) {
121
- if (isSeverityKind(kindValue)) {
122
- kind = kindValue
123
- } else {
124
- throw error(
125
- 'Expected a valid severity kind or number between 0-3',
126
- {
127
- found: kindValue,
128
- },
129
- )
130
- }
131
- }
132
-
133
- return { kind, comparator }
134
- }
135
-
136
- export const severity = async (state: ParserState) => {
137
- assertSecurityArchive(state, 'severity')
138
-
139
- let internals
140
- try {
141
- internals = parseInternals(
142
- asPostcssNodeWithChildren(state.current).nodes,
143
- )
144
- } catch (err) {
145
- throw error('Failed to parse :severity selector', { cause: err })
146
- }
147
-
148
- const { kind, comparator } = internals
149
-
150
- for (const node of state.partial.nodes) {
151
- const report = state.securityArchive.get(node.id)
152
- // Always exclude nodes that don't have security data or alerts
153
- if (!report?.alerts || report.alerts.length === 0) {
154
- removeNode(state, node)
155
- }
156
- }
157
-
158
- for (const node of state.partial.nodes) {
159
- const report = state.securityArchive.get(node.id)
160
- let exclude = true
161
-
162
- if (report) {
163
- if (comparator) {
164
- // retrieve the value to compare against
165
- const kindLevel = kindLevelMap.get(kind)
166
- // the kindLevel value has already been validated at this point
167
- // and thus can never return an undefined value but ts doesn't
168
- // know about that, so we have the extra check here
169
- /* c8 ignore next - impossible */
170
- if (kindLevel == null) break
171
-
172
- // Check each alert to find any that match our comparison criteria
173
- for (const alert of report.alerts) {
174
- // Get the numerical value of the alert type
175
- const alertType = alert.type
176
-
177
- // retrieve a key to the current alert level to be compared against
178
- const currentAlertLevelKey = [...kindsMap.entries()].find(
179
- ([_, alertValue]) => alertValue === alertType,
180
- )?.[0]
181
-
182
- // perform the comparison based on the user-provided kindLevel
183
- if (currentAlertLevelKey) {
184
- const currentAlertLevel = kindLevelMap.get(
185
- currentAlertLevelKey,
186
- )
187
- /* c8 ignore next - impossible but ts doesn't know */
188
- if (currentAlertLevel == null) continue
189
-
190
- switch (comparator) {
191
- case '>':
192
- if (currentAlertLevel > kindLevel) {
193
- exclude = false
194
- }
195
- break
196
- case '<':
197
- if (currentAlertLevel < kindLevel) {
198
- exclude = false
199
- }
200
- break
201
- case '>=':
202
- if (currentAlertLevel >= kindLevel) {
203
- exclude = false
204
- }
205
- break
206
- case '<=':
207
- if (currentAlertLevel <= kindLevel) {
208
- exclude = false
209
- }
210
- break
211
- }
212
- }
213
- }
214
- } else {
215
- // Original exact match behavior
216
- const alertName = kindsMap.get(kind)
217
- exclude = !report.alerts.some(
218
- alert => alert.type === alertName,
219
- )
220
- }
221
- }
222
-
223
- if (exclude) {
224
- removeNode(state, node)
225
- }
226
- }
227
-
228
- removeDanglingEdges(state)
229
-
230
- return state
231
- }
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **shellAccess** report alert.
5
- */
6
- export const shell = createSecuritySelectorFilter(
7
- 'shell',
8
- 'shellAccess',
9
- )
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **shrinkwrap** report alert.
5
- */
6
- export const shrinkwrap = createSecuritySelectorFilter(
7
- 'shrinkwrap',
8
- 'shrinkwrap',
9
- )
@@ -1,59 +0,0 @@
1
- import { asPseudoNode } from '@vltpkg/dss-parser'
2
- import { queryError } from '../error.ts'
3
- import { removeQuotes } from './helpers.ts'
4
- import type { ParserState } from '../types.ts'
5
-
6
- /**
7
- * `:skill(<pattern>, ...)`: picks agent skills of the packages its
8
- * selector matched. Never filters nodes: the walker stores the
9
- * patterns in the selector's `parts` entry. Opt-in only.
10
- */
11
- export const skill = async (state: ParserState) => {
12
- const curr = asPseudoNode(state.current)
13
- const sel = curr.parent
14
- const fail = (message: string) => queryError(message, state.current)
15
- if (
16
- sel?.parent?.type !== 'root' ||
17
- sel.nodes
18
- .slice(sel.index(curr) + 1)
19
- .some(n => n.type !== 'comment')
20
- ) {
21
- throw fail(':skill() must end a top-level selector')
22
- }
23
- if (!state.partSelectors?.has('skill')) {
24
- throw fail(
25
- ':skill() only applies to --allow-skills and vlt skills',
26
- )
27
- }
28
- if (!curr.nodes.length) throw fail('Missing skill name in :skill()')
29
- const patterns = curr.nodes.map(arg => {
30
- let pattern = ''
31
- for (const n of arg.nodes) {
32
- if (n.type === 'comment') continue
33
- // `a|b` is tag `b` in namespace `a`: never drop the `a`
34
- if (
35
- (n.type === 'tag' || n.type === 'universal') &&
36
- !String(n).includes('|')
37
- ) {
38
- pattern += n.value
39
- } else if (n.type === 'string') {
40
- if (n.value.startsWith("'")) {
41
- throw fail(
42
- 'Invalid skill name in :skill(), use double quotes',
43
- )
44
- }
45
- pattern += removeQuotes(n.value)
46
- } else {
47
- throw fail(
48
- n.type === 'combinator' ?
49
- 'Invalid skill name in :skill(), quote names with spaces'
50
- : 'Invalid skill name in :skill()',
51
- )
52
- }
53
- }
54
- if (!pattern) throw fail('Missing skill name in :skill()')
55
- return pattern
56
- })
57
- state.part = { name: 'skill', patterns }
58
- return state
59
- }
@@ -1,29 +0,0 @@
1
- import { asPseudoNode } from '@vltpkg/dss-parser'
2
- import { queryError } from '../error.ts'
3
- import { clear, removeDanglingEdges, removeNode } from './helpers.ts'
4
- import type { ParserState } from '../types.ts'
5
-
6
- /**
7
- * `:skills`: matches installed packages that ship agent skills, as
8
- * told by the `hasSkills` provider.
9
- */
10
- export const skills = async (state: ParserState) => {
11
- // `:skills(x)`: likely a `:skill(x)` typo
12
- if (asPseudoNode(state.current).nodes.length) {
13
- if (state.loose) return clear(state)
14
- throw queryError(':skills takes no arguments', state.current, {
15
- wanted: ':skill',
16
- })
17
- }
18
- if (!state.hasSkills) {
19
- throw queryError(
20
- 'The :skills selector is not supported here',
21
- state.current,
22
- )
23
- }
24
- for (const node of state.partial.nodes) {
25
- if (!(await state.hasSkills(node))) removeNode(state, node)
26
- }
27
- removeDanglingEdges(state)
28
- return state
29
- }
@@ -1,131 +0,0 @@
1
- import { error } from '@vltpkg/error-cause'
2
- import { asError } from '@vltpkg/types'
3
- import {
4
- asPostcssNodeWithChildren,
5
- asStringNode,
6
- asTagNode,
7
- isTagNode,
8
- } from '@vltpkg/dss-parser'
9
- import {
10
- removeEdge,
11
- removeUnlinkedNodes,
12
- removeQuotes,
13
- } from './helpers.ts'
14
- import type { ParserState } from '../types.ts'
15
- import type { PostcssNode } from '@vltpkg/dss-parser'
16
-
17
- export type SpecInternals = {
18
- specValue: string
19
- }
20
-
21
- export const parseInternals = (
22
- nodes: PostcssNode[],
23
- ): SpecInternals => {
24
- // tries to parse the first param as a string node, otherwise defaults
25
- // to reading all postcss nodes as just strings, since it just means
26
- // the value was defined as an unquoted string
27
- let specValue = ''
28
-
29
- if (nodes.length === 0) {
30
- throw new Error('No nodes provided to parseInternals')
31
- }
32
-
33
- const firstNode = asPostcssNodeWithChildren(nodes[0])
34
-
35
- if (firstNode.nodes.length === 0) {
36
- throw new Error('First node has no child nodes')
37
- }
38
-
39
- // Try to parse as a quoted string first (single string node)
40
- if (firstNode.nodes.length === 1) {
41
- const targetNode = firstNode.nodes[0]
42
- try {
43
- specValue = removeQuotes(asStringNode(targetNode).value)
44
- return { specValue }
45
- } catch (err) {
46
- if (
47
- asError(err).message === 'Mismatching query node' &&
48
- isTagNode(targetNode)
49
- /* c8 ignore start */
50
- ) {
51
- // Handle simple unquoted single-token values like "1"
52
- const tagNode = asTagNode(targetNode)
53
- specValue = tagNode.value
54
- return { specValue }
55
- /* c8 ignore stop */
56
- } else {
57
- throw err
58
- }
59
- }
60
- }
61
-
62
- // Handle unquoted complex values that get parsed into multiple nodes
63
- // This happens when unquoted values contain dots, like ^1.0.0 which becomes:
64
- // - Tag: "^1"
65
- // - ClassName: "0" (from .0)
66
- // - ClassName: "0" (from .0)
67
- // We need to reconstruct the original value by concatenating all nodes
68
- const parts: string[] = []
69
-
70
- for (const node of firstNode.nodes) {
71
- switch (node.type) {
72
- case 'tag':
73
- parts.push(asTagNode(node).value)
74
- break
75
- case 'class':
76
- // Class nodes represent .className in CSS, so we need to add the dot back
77
- parts.push('.' + node.value)
78
- break
79
- case 'id':
80
- // ID nodes represent #idName in CSS, so we need to add the hash back
81
- parts.push('#' + node.value)
82
- break
83
- case 'string':
84
- parts.push(removeQuotes(asStringNode(node).value))
85
- break
86
- default:
87
- // For other node types, try to get the value property or convert to string
88
- /* c8 ignore next */
89
- parts.push(node.value ?? String(node))
90
- break
91
- }
92
- }
93
-
94
- specValue = parts.join('')
95
- return { specValue }
96
- }
97
-
98
- /**
99
- * :spec Pseudo-Selector, matches edges where edge.spec.bareSpec equals the provided value.
100
- *
101
- * Examples:
102
- * - :spec("*") matches edges with a package specifier equal to "*"
103
- * - :spec(^1.0.0) matches edges with a package specifier equal to "^1.0.0"
104
- * - :spec("catalog:") matches edges with a package specifier equal to "catalog:"
105
- * - :spec("workspace:dev") matches edges with a package specifier equal to "workspace:dev"
106
- */
107
- export const spec = async (state: ParserState) => {
108
- let internals
109
- try {
110
- internals = parseInternals(
111
- asPostcssNodeWithChildren(state.current).nodes,
112
- )
113
- } catch (err) {
114
- throw error('Failed to parse :spec selector', {
115
- cause: err,
116
- })
117
- }
118
-
119
- const { specValue } = internals
120
-
121
- for (const edge of state.partial.edges) {
122
- if (edge.spec.bareSpec !== specValue) {
123
- removeEdge(state, edge)
124
- }
125
- }
126
-
127
- // Clean up unlinked nodes after removing edges
128
- removeUnlinkedNodes(state)
129
-
130
- return state
131
- }
@@ -1,225 +0,0 @@
1
- import { error } from '@vltpkg/error-cause'
2
- import { asError } from '@vltpkg/types'
3
- import {
4
- asPostcssNodeWithChildren,
5
- asStringNode,
6
- asTagNode,
7
- isStringNode,
8
- isTagNode,
9
- } from '@vltpkg/dss-parser'
10
- import {
11
- assertSecurityArchive,
12
- removeDanglingEdges,
13
- removeNode,
14
- removeQuotes,
15
- } from './helpers.ts'
16
- import type { ParserState } from '../types.ts'
17
- import type { PostcssNode } from '@vltpkg/dss-parser'
18
-
19
- export type SquatKinds = '0' | '2' | 'critical' | 'medium' | undefined
20
-
21
- export type SquatAlertTypes =
22
- 'didYouMean' | 'gptDidYouMean' | undefined
23
-
24
- export type SquatComparator = '>' | '<' | '>=' | '<=' | undefined
25
-
26
- const kindsMap = new Map<SquatKinds, SquatAlertTypes>([
27
- ['critical', 'didYouMean'],
28
- ['medium', 'gptDidYouMean'],
29
- ['0', 'didYouMean'],
30
- ['2', 'gptDidYouMean'],
31
- [undefined, undefined],
32
- ])
33
-
34
- // Map numerical values to their respective kinds for comparison operations
35
- const kindLevelMap = new Map<SquatKinds, number>([
36
- ['critical', 0],
37
- ['medium', 2],
38
- ['0', 0],
39
- ['2', 2],
40
- ])
41
-
42
- const kinds = new Set(kindsMap.keys())
43
-
44
- export const isSquatKind = (value?: string): value is SquatKinds =>
45
- kinds.has(value as SquatKinds)
46
-
47
- export const asSquatKind = (value?: string): SquatKinds => {
48
- if (!isSquatKind(value)) {
49
- throw error('Expected a valid squat kind', {
50
- found: value,
51
- validOptions: Array.from(kinds),
52
- })
53
- }
54
- return value
55
- }
56
-
57
- export const parseInternals = (
58
- nodes: PostcssNode[],
59
- ): {
60
- kind: SquatKinds
61
- comparator: SquatComparator
62
- } => {
63
- let kind: SquatKinds
64
- let comparator: SquatComparator
65
-
66
- let kindValue = ''
67
- if (isStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])) {
68
- kindValue = removeQuotes(
69
- asStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
70
- .value,
71
- )
72
- } else if (
73
- isTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
74
- ) {
75
- kindValue = asTagNode(
76
- asPostcssNodeWithChildren(nodes[0]).nodes[0],
77
- ).value
78
- }
79
-
80
- // Extract comparator if present
81
- if (kindValue.startsWith('>=')) {
82
- comparator = '>='
83
- kindValue = kindValue.substring(2)
84
- } else if (kindValue.startsWith('<=')) {
85
- comparator = '<='
86
- kindValue = kindValue.substring(2)
87
- } else if (kindValue.startsWith('>')) {
88
- comparator = '>'
89
- kindValue = kindValue.substring(1)
90
- } else if (kindValue.startsWith('<')) {
91
- comparator = '<'
92
- kindValue = kindValue.substring(1)
93
- }
94
-
95
- // Parse kind value
96
- if (kindValue) {
97
- if (isSquatKind(kindValue)) {
98
- kind = kindValue
99
- } else {
100
- throw error('Expected a valid squat kind for comparison', {
101
- found: kindValue,
102
- validOptions: Array.from(kinds),
103
- })
104
- }
105
- }
106
-
107
- return { kind, comparator }
108
- }
109
-
110
- export const squat = async (state: ParserState) => {
111
- assertSecurityArchive(state, 'squat')
112
-
113
- let internals
114
- try {
115
- internals = parseInternals(
116
- asPostcssNodeWithChildren(state.current).nodes,
117
- )
118
- } catch (err) {
119
- if (asError(err).message === 'Expected a query node') {
120
- // No parameters provided - pseudo state form: match ANY squat level
121
- internals = { kind: undefined, comparator: undefined }
122
- } else {
123
- throw error('Failed to parse :squat selector', { cause: err })
124
- }
125
- }
126
-
127
- const { kind, comparator } = internals
128
-
129
- // First pass: Remove nodes without security data
130
- for (const node of state.partial.nodes) {
131
- const report = state.securityArchive.get(node.id)
132
- // Always exclude nodes that don't have security data or alerts
133
- if (!report?.alerts || report.alerts.length === 0) {
134
- removeNode(state, node)
135
- }
136
- }
137
-
138
- // Second pass: Apply comparison filtering
139
- for (const node of state.partial.nodes) {
140
- const report = state.securityArchive.get(node.id)
141
-
142
- // Skip if report is undefined
143
- // (should never happen since we filtered above)
144
- /* c8 ignore next - impossible */
145
- if (!report) continue
146
-
147
- // At this point we know report exists and has alerts
148
- let exclude = true
149
-
150
- if (kind === undefined && comparator === undefined) {
151
- // Pseudo state form: match ANY squat level
152
- exclude = !report.alerts.some(alert =>
153
- [...kindsMap.values()].includes(
154
- alert.type as SquatAlertTypes,
155
- ),
156
- )
157
- } else if (comparator) {
158
- // Get the value to compare against
159
- const kindLevel = kindLevelMap.get(kind)
160
- /* c8 ignore next - impossible */
161
- if (kindLevel === undefined) break
162
-
163
- // For each alert, check if it matches the comparison criteria
164
- let matchesComparison = false
165
- for (const alert of report.alerts) {
166
- // Get the alert type
167
- const alertType = alert.type
168
-
169
- // Find the corresponding kind for this alert type
170
- const alertLevelKey = [...kindsMap.entries()].find(
171
- ([_, value]) => value === alertType,
172
- )?.[0]
173
-
174
- if (alertLevelKey) {
175
- // Get the numeric level for this alert
176
- const alertLevel = kindLevelMap.get(alertLevelKey)
177
- /* c8 ignore next - impossible */
178
- if (alertLevel === undefined) continue
179
-
180
- // Apply the comparison based on the comparator
181
- switch (comparator) {
182
- case '>':
183
- if (alertLevel > kindLevel) {
184
- matchesComparison = true
185
- }
186
- break
187
- case '<':
188
- if (alertLevel < kindLevel) {
189
- matchesComparison = true
190
- }
191
- break
192
- case '>=':
193
- if (alertLevel >= kindLevel) {
194
- matchesComparison = true
195
- }
196
- break
197
- case '<=':
198
- if (alertLevel <= kindLevel) {
199
- matchesComparison = true
200
- }
201
- break
202
- }
203
-
204
- // If we found a match, we can stop checking other alerts
205
- if (matchesComparison) break
206
- }
207
- }
208
-
209
- // Exclude the node if it doesn't match the comparison
210
- exclude = !matchesComparison
211
- } else {
212
- // Original exact match behavior
213
- const alertName = kindsMap.get(kind)
214
- exclude = !report.alerts.some(alert => alert.type === alertName)
215
- }
216
-
217
- if (exclude) {
218
- removeNode(state, node)
219
- }
220
- }
221
-
222
- removeDanglingEdges(state)
223
-
224
- return state
225
- }
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **suspiciousStarActivity** report alert.
5
- */
6
- export const suspicious = createSecuritySelectorFilter(
7
- 'suspicious',
8
- 'suspiciousStarActivity',
9
- )