@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
@@ -1,134 +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 LicenseKinds =
20
- | 'unlicensed'
21
- | 'misc'
22
- | 'restricted'
23
- | 'ambiguous'
24
- | 'copyleft'
25
- | 'unknown'
26
- | 'none'
27
- | 'exception'
28
- | undefined
29
-
30
- export type LicenseAlertTypes =
31
- | 'explicitlyUnlicensedItem'
32
- | 'miscLicenseIssues'
33
- | 'nonpermissiveLicense'
34
- | 'ambiguousClassifier'
35
- | 'copyleftLicense'
36
- | 'unidentifiedLicense'
37
- | 'noLicenseFound'
38
- | 'licenseException'
39
- | undefined
40
-
41
- const kindsMap = new Map<LicenseKinds, LicenseAlertTypes>([
42
- ['unlicensed', 'explicitlyUnlicensedItem'],
43
- ['misc', 'miscLicenseIssues'],
44
- ['restricted', 'nonpermissiveLicense'],
45
- ['ambiguous', 'ambiguousClassifier'],
46
- ['copyleft', 'copyleftLicense'],
47
- ['unknown', 'unidentifiedLicense'],
48
- ['none', 'noLicenseFound'],
49
- ['exception', 'licenseException'],
50
- [undefined, undefined],
51
- ])
52
- const kinds = new Set(kindsMap.keys())
53
-
54
- export const isLicenseKind = (
55
- value?: string,
56
- ): value is LicenseKinds => kinds.has(value as LicenseKinds)
57
-
58
- export const asLicenseKind = (value?: string): LicenseKinds => {
59
- if (!isLicenseKind(value)) {
60
- throw error('Expected a valid license kind', {
61
- found: value,
62
- validOptions: Array.from(kinds),
63
- })
64
- }
65
- return value
66
- }
67
-
68
- export const parseInternals = (
69
- nodes: PostcssNode[],
70
- ): { kind: LicenseKinds } => {
71
- let kind: LicenseKinds
72
-
73
- if (isStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])) {
74
- kind = asLicenseKind(
75
- removeQuotes(
76
- asStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
77
- .value,
78
- ),
79
- )
80
- } else if (
81
- isTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
82
- ) {
83
- kind = asLicenseKind(
84
- asTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0]).value,
85
- )
86
- }
87
-
88
- return { kind }
89
- }
90
-
91
- export const license = async (state: ParserState) => {
92
- assertSecurityArchive(state, 'license')
93
-
94
- let internals
95
- try {
96
- internals = parseInternals(
97
- asPostcssNodeWithChildren(state.current).nodes,
98
- )
99
- } catch (err) {
100
- if (asError(err).message === 'Expected a query node') {
101
- // No parameters provided - pseudo state form: match ANY license defined (not 'none')
102
- for (const node of state.partial.nodes) {
103
- const report = state.securityArchive.get(node.id)
104
- // Exclude if no report or if it has 'noLicenseFound' alert
105
- const exclude =
106
- !report?.alerts ||
107
- report.alerts.some(alert => alert.type === 'noLicenseFound')
108
- if (exclude) {
109
- removeNode(state, node)
110
- }
111
- }
112
- removeDanglingEdges(state)
113
- return state
114
- } else {
115
- throw error('Failed to parse :license selector', { cause: err })
116
- }
117
- }
118
-
119
- const { kind } = internals
120
- const alertName = kindsMap.get(kind)
121
- for (const node of state.partial.nodes) {
122
- const report = state.securityArchive.get(node.id)
123
- const exclude = !report?.alerts.some(
124
- alert => alert.type === alertName,
125
- )
126
- if (exclude) {
127
- removeNode(state, node)
128
- }
129
- }
130
-
131
- removeDanglingEdges(state)
132
-
133
- return state
134
- }
@@ -1,30 +0,0 @@
1
- import { splitDepID } from '@vltpkg/dep-id/browser'
2
- import type { ParserState } from '../types.ts'
3
- import { removeNode } from './helpers.ts'
4
-
5
- /**
6
- * :link Pseudo-Selector, matches only nodes that are file links.
7
- *
8
- * It filters out any node that is not of type 'file' or nodes of 'file'
9
- * type that ends with 'tar.gz' since these are local tarballs.
10
- */
11
- export const link = async (state: ParserState) => {
12
- for (const node of state.partial.nodes) {
13
- const [type, path] = splitDepID(node.id)
14
- if (type !== 'file' || path.endsWith('tar.gz') || path === '.') {
15
- removeNode(state, node)
16
- }
17
- }
18
-
19
- for (const edge of state.partial.edges) {
20
- if (
21
- !edge.spec.file ||
22
- edge.spec.file.endsWith('tar.gz') ||
23
- edge.spec.file === '.'
24
- ) {
25
- state.partial.edges.delete(edge)
26
- }
27
- }
28
-
29
- return state
30
- }
@@ -1,41 +0,0 @@
1
- import { error } from '@vltpkg/error-cause'
2
- import { asPostcssNodeWithChildren } from '@vltpkg/dss-parser'
3
- import {
4
- assertSecurityArchive,
5
- removeDanglingEdges,
6
- removeNode,
7
- } from './helpers.ts'
8
- import type { ParserState } from '../types.ts'
9
-
10
- const malwareAlertTypes = new Set(['malware', 'gptMalware'])
11
-
12
- /**
13
- * :malware Pseudo-Selector, matches nodes with any malware-related alert.
14
- *
15
- * This is a binary selector — no parameters. A node matches if it has
16
- * at least one alert whose type is `malware` or `gptMalware`.
17
- */
18
- export const malware = async (state: ParserState) => {
19
- assertSecurityArchive(state, 'malware')
20
-
21
- const currentNode = asPostcssNodeWithChildren(state.current)
22
- if (currentNode.nodes.length > 0) {
23
- throw error(
24
- ':malware selector does not accept parameters. Use :vuln(<severity>) for severity-based filtering.',
25
- )
26
- }
27
-
28
- for (const node of state.partial.nodes) {
29
- const report = state.securityArchive.get(node.id)
30
- const hasMalware = report?.alerts.some(alert =>
31
- malwareAlertTypes.has(alert.type),
32
- )
33
- if (!hasMalware) {
34
- removeNode(state, node)
35
- }
36
- }
37
-
38
- removeDanglingEdges(state)
39
-
40
- return state
41
- }
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **minifiedFile** report alert.
5
- */
6
- export const minified = createSecuritySelectorFilter(
7
- 'minified',
8
- 'minifiedFile',
9
- )
@@ -1,16 +0,0 @@
1
- import type { ParserState } from '../types.ts'
2
-
3
- /**
4
- * :missing Pseudo-Selector, matches only edges that are not linked to any node.
5
- * It filters out any edges that have a 'to' property, keeping only dangling edges
6
- * and clears all nodes from the result.
7
- */
8
- export const missing = async (state: ParserState) => {
9
- for (const edge of state.partial.edges) {
10
- if (edge.to) {
11
- state.partial.edges.delete(edge)
12
- }
13
- }
14
- state.partial.nodes.clear()
15
- return state
16
- }
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **hasNativeCode** report alert.
5
- */
6
- export const nativeParser = createSecuritySelectorFilter(
7
- 'native',
8
- 'hasNativeCode',
9
- )
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have a **networkAccess** report alert.
5
- */
6
- export const network = createSecuritySelectorFilter(
7
- 'network',
8
- 'networkAccess',
9
- )
@@ -1,9 +0,0 @@
1
- import { createSecuritySelectorFilter } from './helpers.ts'
2
-
3
- /**
4
- * Filters out any node that does not have an **obfuscatedFile** report alert.
5
- */
6
- export const obfuscated = createSecuritySelectorFilter(
7
- 'obfuscated',
8
- 'obfuscatedFile',
9
- )
@@ -1,18 +0,0 @@
1
- import type { ParserState } from '../types.ts'
2
- import { removeEdge, removeUnlinkedNodes } from './helpers.ts'
3
-
4
- /**
5
- * :optional Pseudo-Selector will only match optional dependencies.
6
- */
7
- export const optional = async (state: ParserState) => {
8
- // filter edges that aren't marked as optional
9
- for (const edge of state.partial.edges) {
10
- if (!edge.optional) {
11
- removeEdge(state, edge)
12
- }
13
- }
14
-
15
- removeUnlinkedNodes(state)
16
-
17
- return state
18
- }
@@ -1,345 +0,0 @@
1
- import pRetry, { AbortError } from 'p-retry'
2
- import { hydrate, splitDepID } from '@vltpkg/dep-id/browser'
3
- import { error } from '@vltpkg/error-cause'
4
- import { userAgentHeaders } from '@vltpkg/user-agent'
5
- import { asError } from '@vltpkg/types'
6
- import {
7
- compare,
8
- gt,
9
- major,
10
- minor,
11
- patch,
12
- satisfies,
13
- } from '@vltpkg/semver'
14
- import {
15
- asPostcssNodeWithChildren,
16
- asStringNode,
17
- asTagNode,
18
- isStringNode,
19
- isTagNode,
20
- } from '@vltpkg/dss-parser'
21
- import { removeNode, removeQuotes } from './helpers.ts'
22
- import type { NodeLike, Packument } from '@vltpkg/types'
23
- import type { GetAuthHeader, ParserState } from '../types.ts'
24
- import type { PostcssNode } from '@vltpkg/dss-parser'
25
-
26
- /**
27
- * The possible values accepted by the :outdated() pseudo selector.
28
- */
29
- export type OutdatedKinds =
30
- 'any' | 'major' | 'minor' | 'patch' | 'in-range' | 'out-of-range'
31
-
32
- /**
33
- * Result of the internal parsing of the :outdated() pseudo selector.
34
- */
35
- export type OutdatedInternals = {
36
- kind: OutdatedKinds
37
- }
38
-
39
- /**
40
- * Extracts a semver type from a version string.
41
- */
42
- export type SemverTypeExtraction = (
43
- version: string,
44
- ) => number | undefined
45
-
46
- const kinds = new Set<OutdatedKinds>([
47
- 'any',
48
- 'major',
49
- 'minor',
50
- 'patch',
51
- 'in-range',
52
- 'out-of-range',
53
- ])
54
-
55
- /**
56
- * Checks if a string is a valid {@link OutdatedKinds}.
57
- */
58
- export const isOutdatedKind = (
59
- value: string,
60
- ): value is OutdatedKinds => kinds.has(value as OutdatedKinds)
61
-
62
- /**
63
- * Asserts that a string is a valid {@link OutdatedKinds}.
64
- */
65
- export const asOutdatedKind = (value: string): OutdatedKinds => {
66
- if (!isOutdatedKind(value)) {
67
- throw error('Expected a valid outdated kind', {
68
- found: value,
69
- validOptions: Array.from(kinds),
70
- })
71
- }
72
- return value
73
- }
74
-
75
- /**
76
- * Fetches the available versions of a package from the npm registry.
77
- */
78
- export const retrieveRemoteVersions = async (
79
- node: NodeLike,
80
- signal?: AbortSignal,
81
- getAuthHeader?: GetAuthHeader,
82
- ): Promise<string[]> => {
83
- const spec = hydrate(node.id, String(node.name), node.options)
84
- if (!spec.registry || !node.name) {
85
- return []
86
- }
87
-
88
- // resolve against the registry as a base so that any path prefix
89
- // (e.g: https://registry.vlt.io/vltpkg/npm/) is preserved
90
- const base =
91
- spec.registry.endsWith('/') ? spec.registry : `${spec.registry}/`
92
- const url = new URL(node.name, base)
93
-
94
- const headers: Record<string, string> = {
95
- Accept: 'application/vnd.npm.install-v1+json',
96
- ...userAgentHeaders,
97
- }
98
- const auth = await getAuthHeader?.(String(url))
99
- if (auth) {
100
- headers.authorization = auth
101
- }
102
-
103
- // Corgi is safe here: raw fetch (never the RegistryClient disk cache),
104
- // and only versions keys are read.
105
- const response = await fetch(String(url), {
106
- headers,
107
- signal,
108
- })
109
- // on missing valid auth or API, it should abort the retry logic
110
- if (response.status === 404) {
111
- throw new AbortError('Missing API')
112
- }
113
- if (!response.ok) {
114
- throw error('Failed to fetch packument', {
115
- name: node.name,
116
- spec,
117
- response,
118
- })
119
- }
120
- const packument = (await response.json()) as Packument
121
- return Object.keys(packument.versions).sort(compare)
122
- }
123
-
124
- /**
125
- * Retrieves what kind of check the :outdated selector should perform.
126
- */
127
- export const parseInternals = (
128
- nodes: PostcssNode[],
129
- ): OutdatedInternals => {
130
- let kind: OutdatedKinds = 'any'
131
-
132
- if (isStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])) {
133
- kind = asOutdatedKind(
134
- removeQuotes(
135
- asStringNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
136
- .value,
137
- ),
138
- )
139
- } else if (
140
- isTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0])
141
- ) {
142
- kind = asOutdatedKind(
143
- asTagNode(asPostcssNodeWithChildren(nodes[0]).nodes[0]).value,
144
- )
145
- }
146
-
147
- return { kind }
148
- }
149
-
150
- /**
151
- * Filter nodes by queueing up for removal those that are not outdated.
152
- */
153
- export const queueNode = async (
154
- state: ParserState,
155
- node: NodeLike,
156
- kind: OutdatedKinds,
157
- onError?: (node: NodeLike, err: unknown) => void,
158
- ): Promise<NodeLike | undefined> => {
159
- if (!node.name || !node.version) {
160
- return node
161
- }
162
-
163
- const nodeVersion: string = node.version
164
- let versions: string[]
165
- try {
166
- versions = await pRetry(
167
- () =>
168
- retrieveRemoteVersions(
169
- node,
170
- state.signal,
171
- state.getAuthHeader,
172
- ),
173
- {
174
- retries: state.retries,
175
- signal: state.signal,
176
- },
177
- )
178
- } catch (err) {
179
- if (onError) {
180
- onError(node, err)
181
- } else {
182
- // eslint-disable-next-line no-console
183
- console.warn(
184
- error('Could not retrieve registry versions', {
185
- name: node.name,
186
- cause: err,
187
- }),
188
- )
189
- }
190
- versions = []
191
- }
192
-
193
- const greaterVersions = versions.filter((version: string) =>
194
- gt(version, nodeVersion),
195
- )
196
-
197
- // if there are no greater versions, then the node is not outdated
198
- if (!greaterVersions.length) {
199
- return node
200
- }
201
-
202
- const checkKind = new Map<OutdatedKinds, SemverTypeExtraction>([
203
- ['major', major],
204
- ['minor', minor],
205
- ['patch', patch],
206
- ])
207
-
208
- switch (kind) {
209
- case 'any':
210
- return
211
- case 'major':
212
- case 'minor':
213
- case 'patch': {
214
- return (
215
- greaterVersions.some((version: string) => {
216
- const va = checkKind.get(kind)?.(version)
217
- const vb = checkKind.get(kind)?.(nodeVersion)
218
- /* c8 ignore next - impossible but typescript doesn't know */
219
- if (va === undefined || vb === undefined) return false
220
- return va > vb
221
- })
222
- ) ?
223
- undefined
224
- : node
225
- }
226
- // the node should be part of the result as long as it has at least
227
- // one parent node that has a spec definition that satisfies one
228
- // of the available remove versions
229
- case 'in-range': {
230
- for (const edge of node.edgesIn) {
231
- // if the edge is not part of the partial results, skip it
232
- /* c8 ignore next */
233
- if (!state.partial.edges.has(edge)) continue
234
-
235
- if (
236
- greaterVersions.some(
237
- version =>
238
- edge.spec.final.range &&
239
- satisfies(version, edge.spec.final.range),
240
- )
241
- ) {
242
- return
243
- }
244
- }
245
- return node
246
- }
247
- // the node is part of the result as long as none of its parents has
248
- // a spec definition that satisfies one of the available remote versions
249
- case 'out-of-range': {
250
- for (const edge of node.edgesIn) {
251
- // if the edge is not part of the partial results, skip it
252
- /* c8 ignore next */
253
- if (!state.partial.edges.has(edge)) continue
254
-
255
- if (
256
- greaterVersions.some(
257
- version =>
258
- edge.spec.final.range &&
259
- satisfies(version, edge.spec.final.range),
260
- )
261
- ) {
262
- return node
263
- }
264
- }
265
- return
266
- }
267
- }
268
- }
269
-
270
- /**
271
- * Filters out nodes that are not outdated.
272
- *
273
- * The :outdated() pseudo selector supports one `type` argument,
274
- * possible values are the following:
275
- *
276
- * - `any`: Selects all nodes that have a greater version available.
277
- * - `major`: Selects all nodes that have a greater major version available.
278
- * - `minor`: Selects all nodes that have a greater minor version available.
279
- * - `patch`: Selects all nodes that have a greater patch version available.
280
- * - `in-range`: Selects all nodes that have a parent node with a spec definition
281
- * that satisfies one of the available remote versions.
282
- * - `out-of-range`: Selects all nodes that have a parent node with a spec definition
283
- * that does not satisfy any of the available remote versions.
284
- */
285
- export const outdated = async (state: ParserState) => {
286
- let internals
287
- try {
288
- internals = parseInternals(
289
- asPostcssNodeWithChildren(state.current).nodes,
290
- )
291
- } catch (err) {
292
- if (asError(err).message === 'Expected a query node') {
293
- internals = { kind: 'any' } satisfies OutdatedInternals
294
- } else {
295
- throw error('Failed to parse :outdated selector', {
296
- cause: err,
297
- })
298
- }
299
- }
300
-
301
- const { kind } = internals
302
- const queue = []
303
- const failures: { node: NodeLike; err: unknown }[] = []
304
-
305
- for (const node of state.partial.nodes) {
306
- // filter out nodes that are always ignored by the outdated selector
307
- if (
308
- node.mainImporter ||
309
- node.manifest?.private ||
310
- splitDepID(node.id)[0] !== 'registry'
311
- ) {
312
- removeNode(state, node)
313
- continue
314
- }
315
-
316
- // fetchs outdated info and performs checks to define
317
- // whether or not a node should be filtered out
318
- queue.push(
319
- queueNode(state, node, kind, (node, err) =>
320
- failures.push({ node, err }),
321
- ),
322
- )
323
- }
324
-
325
- // nodes queued for removal are then finally removed
326
- const removeNodeQueue = await Promise.all(queue)
327
- for (const node of removeNodeQueue) {
328
- if (node) {
329
- removeNode(state, node)
330
- }
331
- }
332
-
333
- // collapse per-node failures into a single warning
334
- if (failures.length) {
335
- // eslint-disable-next-line no-console
336
- console.warn(
337
- error('Could not retrieve registry versions', {
338
- found: failures.map(({ node }) => String(node.name)).sort(),
339
- cause: failures[0]?.err,
340
- }),
341
- )
342
- }
343
-
344
- return state
345
- }
@@ -1,20 +0,0 @@
1
- import type { ParserState } from '../types.ts'
2
- import { removeEdge, removeUnlinkedNodes } from './helpers.ts'
3
-
4
- /**
5
- * :overridden Pseudo-Selector, matches only edges that have a truthy overridden property in their spec.
6
- * It filters out any edges that don't have edge.spec.overridden set to a truthy value
7
- * and removes any unlinked nodes from the result.
8
- */
9
- export const overridden = async (state: ParserState) => {
10
- // filter edges that don't have a truthy overridden property
11
- for (const edge of state.partial.edges) {
12
- if (!edge.spec.overridden) {
13
- removeEdge(state, edge)
14
- }
15
- }
16
-
17
- removeUnlinkedNodes(state)
18
-
19
- return state
20
- }