@vltpkg/query 1.5.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 (210) hide show
  1. package/package.json +10 -12
  2. package/skills/dss-query/REFERENCE.md +0 -125
  3. package/skills/dss-query/SKILL.md +0 -190
  4. package/skills/dss-query/evals/README.md +0 -81
  5. package/skills/dss-query/evals/evals.json +0 -89
  6. package/skills/dss-query/evals/grade.mjs +0 -481
  7. package/src/attribute.ts +0 -190
  8. package/src/combinator.ts +0 -135
  9. package/src/error.ts +0 -78
  10. package/src/id.ts +0 -46
  11. package/src/index.ts +0 -670
  12. package/src/parser.ts +0 -122
  13. package/src/pseudo/abandoned.ts +0 -9
  14. package/src/pseudo/attr.ts +0 -92
  15. package/src/pseudo/built.ts +0 -19
  16. package/src/pseudo/confused.ts +0 -29
  17. package/src/pseudo/cve.ts +0 -93
  18. package/src/pseudo/cwe.ts +0 -97
  19. package/src/pseudo/debug.ts +0 -9
  20. package/src/pseudo/deprecated.ts +0 -9
  21. package/src/pseudo/dev.ts +0 -18
  22. package/src/pseudo/diff.ts +0 -90
  23. package/src/pseudo/dist.ts +0 -148
  24. package/src/pseudo/dynamic.ts +0 -9
  25. package/src/pseudo/empty.ts +0 -15
  26. package/src/pseudo/entropic.ts +0 -9
  27. package/src/pseudo/env.ts +0 -6
  28. package/src/pseudo/eval.ts +0 -9
  29. package/src/pseudo/fs.ts +0 -9
  30. package/src/pseudo/helpers.ts +0 -106
  31. package/src/pseudo/host.ts +0 -111
  32. package/src/pseudo/hostname.ts +0 -156
  33. package/src/pseudo/license.ts +0 -134
  34. package/src/pseudo/link.ts +0 -30
  35. package/src/pseudo/malware.ts +0 -41
  36. package/src/pseudo/minified.ts +0 -9
  37. package/src/pseudo/missing.ts +0 -16
  38. package/src/pseudo/native.ts +0 -9
  39. package/src/pseudo/network.ts +0 -9
  40. package/src/pseudo/obfuscated.ts +0 -9
  41. package/src/pseudo/optional.ts +0 -18
  42. package/src/pseudo/outdated.ts +0 -345
  43. package/src/pseudo/overridden.ts +0 -20
  44. package/src/pseudo/path.ts +0 -146
  45. package/src/pseudo/peer.ts +0 -18
  46. package/src/pseudo/prerelease.ts +0 -47
  47. package/src/pseudo/private.ts +0 -19
  48. package/src/pseudo/prod.ts +0 -18
  49. package/src/pseudo/published.ts +0 -250
  50. package/src/pseudo/registry.ts +0 -29
  51. package/src/pseudo/root.ts +0 -19
  52. package/src/pseudo/scanned.ts +0 -20
  53. package/src/pseudo/score.ts +0 -186
  54. package/src/pseudo/scripts.ts +0 -61
  55. package/src/pseudo/semver.ts +0 -320
  56. package/src/pseudo/severity.ts +0 -231
  57. package/src/pseudo/shell.ts +0 -9
  58. package/src/pseudo/shrinkwrap.ts +0 -9
  59. package/src/pseudo/skill.ts +0 -59
  60. package/src/pseudo/skills.ts +0 -29
  61. package/src/pseudo/spec.ts +0 -131
  62. package/src/pseudo/squat.ts +0 -225
  63. package/src/pseudo/suspicious.ts +0 -9
  64. package/src/pseudo/tracker.ts +0 -9
  65. package/src/pseudo/trivial.ts +0 -9
  66. package/src/pseudo/type.ts +0 -26
  67. package/src/pseudo/undesirable.ts +0 -9
  68. package/src/pseudo/unknown.ts +0 -9
  69. package/src/pseudo/unmaintained.ts +0 -9
  70. package/src/pseudo/unpopular.ts +0 -9
  71. package/src/pseudo/unstable.ts +0 -9
  72. package/src/pseudo/vuln.ts +0 -273
  73. package/src/pseudo/workspace.ts +0 -22
  74. package/src/pseudo.ts +0 -440
  75. package/src/types.ts +0 -206
  76. package/tap-snapshots/test/attribute.ts.test.cjs +0 -304
  77. package/tap-snapshots/test/combinator.ts.test.cjs +0 -333
  78. package/tap-snapshots/test/id.ts.test.cjs +0 -118
  79. package/tap-snapshots/test/parser.ts.test.cjs +0 -344
  80. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +0 -18
  81. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +0 -161
  82. package/tap-snapshots/test/pseudo/built.ts.test.cjs +0 -70
  83. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +0 -32
  84. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +0 -49
  85. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +0 -49
  86. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +0 -18
  87. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +0 -18
  88. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +0 -30
  89. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +0 -18
  90. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +0 -50
  91. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +0 -18
  92. package/tap-snapshots/test/pseudo/env.ts.test.cjs +0 -18
  93. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +0 -18
  94. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +0 -18
  95. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +0 -18
  96. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +0 -148
  97. package/tap-snapshots/test/pseudo/license.ts.test.cjs +0 -41
  98. package/tap-snapshots/test/pseudo/link.ts.test.cjs +0 -36
  99. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +0 -22
  100. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +0 -18
  101. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +0 -30
  102. package/tap-snapshots/test/pseudo/native.ts.test.cjs +0 -18
  103. package/tap-snapshots/test/pseudo/network.ts.test.cjs +0 -18
  104. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +0 -18
  105. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +0 -132
  106. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +0 -75
  107. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +0 -101
  108. package/tap-snapshots/test/pseudo/private.ts.test.cjs +0 -38
  109. package/tap-snapshots/test/pseudo/published.ts.test.cjs +0 -171
  110. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +0 -68
  111. package/tap-snapshots/test/pseudo/root.ts.test.cjs +0 -24
  112. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +0 -18
  113. package/tap-snapshots/test/pseudo/score.ts.test.cjs +0 -239
  114. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +0 -62
  115. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +0 -575
  116. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +0 -122
  117. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +0 -18
  118. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +0 -18
  119. package/tap-snapshots/test/pseudo/skills.ts.test.cjs +0 -19
  120. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +0 -148
  121. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +0 -129
  122. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +0 -18
  123. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +0 -18
  124. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +0 -18
  125. package/tap-snapshots/test/pseudo/type.ts.test.cjs +0 -51
  126. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +0 -18
  127. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +0 -18
  128. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +0 -18
  129. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +0 -18
  130. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +0 -18
  131. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +0 -208
  132. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +0 -20
  133. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +0 -19
  134. package/tap-snapshots/test/pseudo.ts.test.cjs +0 -1247
  135. package/test/attribute.ts +0 -273
  136. package/test/combinator.ts +0 -175
  137. package/test/error.ts +0 -60
  138. package/test/fixtures/graph.ts +0 -999
  139. package/test/fixtures/selector.ts +0 -103
  140. package/test/fixtures/types.ts +0 -7
  141. package/test/id.ts +0 -102
  142. package/test/index.ts +0 -1148
  143. package/test/parser.ts +0 -117
  144. package/test/pseudo/abandoned.ts +0 -98
  145. package/test/pseudo/attr.ts +0 -298
  146. package/test/pseudo/built.ts +0 -214
  147. package/test/pseudo/confused.ts +0 -160
  148. package/test/pseudo/cve.ts +0 -249
  149. package/test/pseudo/cwe.ts +0 -255
  150. package/test/pseudo/debug.ts +0 -98
  151. package/test/pseudo/deprecated.ts +0 -98
  152. package/test/pseudo/dev.ts +0 -61
  153. package/test/pseudo/diff.ts +0 -417
  154. package/test/pseudo/dist.ts +0 -215
  155. package/test/pseudo/dynamic.ts +0 -98
  156. package/test/pseudo/empty.ts +0 -108
  157. package/test/pseudo/entropic.ts +0 -101
  158. package/test/pseudo/env.ts +0 -98
  159. package/test/pseudo/eval.ts +0 -98
  160. package/test/pseudo/fs.ts +0 -98
  161. package/test/pseudo/helpers.ts +0 -370
  162. package/test/pseudo/host-context.ts +0 -276
  163. package/test/pseudo/hostname.ts +0 -314
  164. package/test/pseudo/license.ts +0 -265
  165. package/test/pseudo/link.ts +0 -94
  166. package/test/pseudo/malware.ts +0 -184
  167. package/test/pseudo/minified.ts +0 -98
  168. package/test/pseudo/missing.ts +0 -111
  169. package/test/pseudo/native.ts +0 -98
  170. package/test/pseudo/network.ts +0 -98
  171. package/test/pseudo/obfuscated.ts +0 -98
  172. package/test/pseudo/optional.ts +0 -73
  173. package/test/pseudo/outdated.ts +0 -461
  174. package/test/pseudo/overridden.ts +0 -317
  175. package/test/pseudo/path.ts +0 -680
  176. package/test/pseudo/peer.ts +0 -101
  177. package/test/pseudo/prerelease.ts +0 -279
  178. package/test/pseudo/private.ts +0 -108
  179. package/test/pseudo/prod.ts +0 -61
  180. package/test/pseudo/published.ts +0 -557
  181. package/test/pseudo/registry.ts +0 -122
  182. package/test/pseudo/root.ts +0 -66
  183. package/test/pseudo/scanned.ts +0 -144
  184. package/test/pseudo/score.ts +0 -591
  185. package/test/pseudo/scripts.ts +0 -324
  186. package/test/pseudo/semver.ts +0 -822
  187. package/test/pseudo/severity.ts +0 -342
  188. package/test/pseudo/shell.ts +0 -98
  189. package/test/pseudo/shrinkwrap.ts +0 -98
  190. package/test/pseudo/skill.ts +0 -189
  191. package/test/pseudo/skills.ts +0 -90
  192. package/test/pseudo/spec.ts +0 -525
  193. package/test/pseudo/squat.ts +0 -565
  194. package/test/pseudo/suspicious.ts +0 -98
  195. package/test/pseudo/tracker.ts +0 -98
  196. package/test/pseudo/trivial.ts +0 -98
  197. package/test/pseudo/type.ts +0 -105
  198. package/test/pseudo/undesirable.ts +0 -98
  199. package/test/pseudo/unknown.ts +0 -98
  200. package/test/pseudo/unmaintained.ts +0 -98
  201. package/test/pseudo/unpopular.ts +0 -98
  202. package/test/pseudo/unstable.ts +0 -98
  203. package/test/pseudo/vuln.ts +0 -625
  204. package/test/pseudo/vulnerable.ts +0 -137
  205. package/test/pseudo/workspace.ts +0 -111
  206. package/test/pseudo.ts +0 -584
  207. package/tsconfig.json +0 -3
  208. package/tsconfig.publish.json +0 -19
  209. package/tsconfig.publish.tsbuildinfo +0 -1
  210. 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
- )