@vltpkg/query 1.0.0-rc.8 → 1.0.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 (463) hide show
  1. package/dist/{esm/attribute.d.ts → attribute.d.ts} +0 -1
  2. package/dist/{esm/attribute.js → attribute.js} +0 -1
  3. package/dist/{esm/combinator.d.ts → combinator.d.ts} +0 -1
  4. package/dist/{esm/combinator.js → combinator.js} +0 -1
  5. package/dist/{esm/id.d.ts → id.d.ts} +0 -1
  6. package/dist/{esm/id.js → id.js} +0 -1
  7. package/dist/{esm/index.d.ts → index.d.ts} +3 -3
  8. package/dist/{esm/index.js → index.js} +14 -8
  9. package/dist/{esm/parser.d.ts → parser.d.ts} +0 -1
  10. package/dist/{esm/parser.js → parser.js} +2 -2
  11. package/dist/{esm/pseudo → pseudo}/abandoned.d.ts +0 -1
  12. package/dist/{esm/pseudo → pseudo}/abandoned.js +0 -1
  13. package/dist/{esm/pseudo → pseudo}/attr.d.ts +0 -1
  14. package/dist/{esm/pseudo → pseudo}/attr.js +0 -1
  15. package/dist/{esm/pseudo → pseudo}/built.d.ts +0 -1
  16. package/dist/{esm/pseudo → pseudo}/built.js +0 -1
  17. package/dist/{esm/pseudo → pseudo}/confused.d.ts +0 -1
  18. package/dist/{esm/pseudo → pseudo}/confused.js +0 -1
  19. package/dist/{esm/pseudo → pseudo}/cve.d.ts +6 -3
  20. package/dist/pseudo/cve.js +61 -0
  21. package/dist/{esm/pseudo → pseudo}/cwe.d.ts +6 -3
  22. package/dist/pseudo/cwe.js +61 -0
  23. package/dist/{esm/pseudo → pseudo}/debug.d.ts +0 -1
  24. package/dist/{esm/pseudo → pseudo}/debug.js +0 -1
  25. package/dist/{esm/pseudo → pseudo}/deprecated.d.ts +0 -1
  26. package/dist/{esm/pseudo → pseudo}/deprecated.js +0 -1
  27. package/dist/{esm/pseudo → pseudo}/dev.d.ts +0 -1
  28. package/dist/{esm/pseudo → pseudo}/dev.js +0 -1
  29. package/dist/pseudo/diff.d.ts +26 -0
  30. package/dist/pseudo/diff.js +75 -0
  31. package/dist/pseudo/dist.d.ts +22 -0
  32. package/dist/pseudo/dist.js +110 -0
  33. package/dist/{esm/pseudo → pseudo}/dynamic.d.ts +0 -1
  34. package/dist/{esm/pseudo → pseudo}/dynamic.js +0 -1
  35. package/dist/{esm/pseudo → pseudo}/empty.d.ts +0 -1
  36. package/dist/{esm/pseudo → pseudo}/empty.js +0 -1
  37. package/dist/{esm/pseudo → pseudo}/entropic.d.ts +0 -1
  38. package/dist/{esm/pseudo → pseudo}/entropic.js +0 -1
  39. package/dist/{esm/pseudo → pseudo}/env.d.ts +0 -1
  40. package/dist/{esm/pseudo → pseudo}/env.js +0 -1
  41. package/dist/{esm/pseudo → pseudo}/eval.d.ts +0 -1
  42. package/dist/{esm/pseudo → pseudo}/eval.js +0 -1
  43. package/dist/{esm/pseudo → pseudo}/fs.d.ts +0 -1
  44. package/dist/{esm/pseudo → pseudo}/fs.js +0 -1
  45. package/dist/{esm/pseudo → pseudo}/helpers.d.ts +0 -1
  46. package/dist/{esm/pseudo → pseudo}/helpers.js +1 -2
  47. package/dist/{esm/pseudo → pseudo}/host.d.ts +0 -1
  48. package/dist/{esm/pseudo → pseudo}/host.js +0 -1
  49. package/dist/pseudo/hostname.d.ts +11 -0
  50. package/dist/pseudo/hostname.js +140 -0
  51. package/dist/{esm/pseudo → pseudo}/license.d.ts +0 -1
  52. package/dist/{esm/pseudo → pseudo}/license.js +0 -1
  53. package/dist/{esm/pseudo → pseudo}/link.d.ts +0 -1
  54. package/dist/{esm/pseudo → pseudo}/link.js +0 -1
  55. package/dist/pseudo/malware.d.ts +10 -0
  56. package/dist/pseudo/malware.js +26 -0
  57. package/dist/{esm/pseudo → pseudo}/minified.d.ts +0 -1
  58. package/dist/{esm/pseudo → pseudo}/minified.js +0 -1
  59. package/dist/{esm/pseudo → pseudo}/missing.d.ts +0 -1
  60. package/dist/{esm/pseudo → pseudo}/missing.js +0 -1
  61. package/dist/{esm/pseudo → pseudo}/native.d.ts +0 -1
  62. package/dist/{esm/pseudo → pseudo}/native.js +0 -1
  63. package/dist/{esm/pseudo → pseudo}/network.d.ts +0 -1
  64. package/dist/{esm/pseudo → pseudo}/network.js +0 -1
  65. package/dist/{esm/pseudo → pseudo}/obfuscated.d.ts +0 -1
  66. package/dist/{esm/pseudo → pseudo}/obfuscated.js +0 -1
  67. package/dist/{esm/pseudo → pseudo}/optional.d.ts +0 -1
  68. package/dist/{esm/pseudo → pseudo}/optional.js +0 -1
  69. package/dist/{esm/pseudo → pseudo}/outdated.d.ts +0 -1
  70. package/dist/{esm/pseudo → pseudo}/outdated.js +0 -1
  71. package/dist/{esm/pseudo → pseudo}/overridden.d.ts +0 -1
  72. package/dist/{esm/pseudo → pseudo}/overridden.js +0 -1
  73. package/dist/{esm/pseudo → pseudo}/path.d.ts +0 -1
  74. package/dist/{esm/pseudo → pseudo}/path.js +1 -4
  75. package/dist/{esm/pseudo → pseudo}/peer.d.ts +0 -1
  76. package/dist/{esm/pseudo → pseudo}/peer.js +0 -1
  77. package/dist/{esm/pseudo → pseudo}/prerelease.d.ts +0 -1
  78. package/dist/{esm/pseudo → pseudo}/prerelease.js +0 -1
  79. package/dist/{esm/pseudo → pseudo}/private.d.ts +0 -1
  80. package/dist/{esm/pseudo → pseudo}/private.js +0 -1
  81. package/dist/{esm/pseudo → pseudo}/prod.d.ts +0 -1
  82. package/dist/{esm/pseudo → pseudo}/prod.js +0 -1
  83. package/dist/{esm/pseudo → pseudo}/published.d.ts +0 -1
  84. package/dist/{esm/pseudo → pseudo}/published.js +0 -1
  85. package/dist/pseudo/registry.d.ts +10 -0
  86. package/dist/pseudo/registry.js +24 -0
  87. package/dist/{esm/pseudo → pseudo}/root.d.ts +0 -1
  88. package/dist/{esm/pseudo → pseudo}/root.js +0 -1
  89. package/dist/{esm/pseudo → pseudo}/scanned.d.ts +0 -1
  90. package/dist/{esm/pseudo → pseudo}/scanned.js +0 -1
  91. package/dist/{esm/pseudo → pseudo}/score.d.ts +0 -1
  92. package/dist/{esm/pseudo → pseudo}/score.js +0 -1
  93. package/dist/{esm/pseudo → pseudo}/scripts.d.ts +0 -1
  94. package/dist/{esm/pseudo → pseudo}/scripts.js +1 -2
  95. package/dist/{esm/pseudo → pseudo}/semver.d.ts +3 -2
  96. package/dist/{esm/pseudo → pseudo}/semver.js +43 -7
  97. package/dist/{esm/pseudo → pseudo}/severity.d.ts +0 -1
  98. package/dist/{esm/pseudo → pseudo}/severity.js +0 -1
  99. package/dist/{esm/pseudo → pseudo}/shell.d.ts +0 -1
  100. package/dist/{esm/pseudo → pseudo}/shell.js +0 -1
  101. package/dist/{esm/pseudo → pseudo}/shrinkwrap.d.ts +0 -1
  102. package/dist/{esm/pseudo → pseudo}/shrinkwrap.js +0 -1
  103. package/dist/{esm/pseudo → pseudo}/spec.d.ts +0 -1
  104. package/dist/{esm/pseudo → pseudo}/spec.js +0 -1
  105. package/dist/{esm/pseudo → pseudo}/squat.d.ts +0 -1
  106. package/dist/{esm/pseudo → pseudo}/squat.js +0 -1
  107. package/dist/{esm/pseudo → pseudo}/suspicious.d.ts +0 -1
  108. package/dist/{esm/pseudo → pseudo}/suspicious.js +0 -1
  109. package/dist/{esm/pseudo → pseudo}/tracker.d.ts +0 -1
  110. package/dist/{esm/pseudo → pseudo}/tracker.js +0 -1
  111. package/dist/{esm/pseudo → pseudo}/trivial.d.ts +0 -1
  112. package/dist/{esm/pseudo → pseudo}/trivial.js +0 -1
  113. package/dist/{esm/pseudo → pseudo}/type.d.ts +0 -1
  114. package/dist/{esm/pseudo → pseudo}/type.js +0 -1
  115. package/dist/{esm/pseudo → pseudo}/undesirable.d.ts +0 -1
  116. package/dist/{esm/pseudo → pseudo}/undesirable.js +0 -1
  117. package/dist/{esm/pseudo → pseudo}/unknown.d.ts +0 -1
  118. package/dist/{esm/pseudo → pseudo}/unknown.js +0 -1
  119. package/dist/{esm/pseudo → pseudo}/unmaintained.d.ts +0 -1
  120. package/dist/{esm/pseudo → pseudo}/unmaintained.js +0 -1
  121. package/dist/{esm/pseudo → pseudo}/unpopular.d.ts +0 -1
  122. package/dist/{esm/pseudo → pseudo}/unpopular.js +0 -1
  123. package/dist/{esm/pseudo → pseudo}/unstable.d.ts +0 -1
  124. package/dist/{esm/pseudo → pseudo}/unstable.js +0 -1
  125. package/dist/pseudo/vuln.d.ts +22 -0
  126. package/dist/pseudo/vuln.js +220 -0
  127. package/dist/{esm/pseudo → pseudo}/workspace.d.ts +0 -1
  128. package/dist/{esm/pseudo → pseudo}/workspace.js +0 -1
  129. package/dist/{esm/pseudo.d.ts → pseudo.d.ts} +0 -1
  130. package/dist/{esm/pseudo.js → pseudo.js} +16 -1
  131. package/dist/{esm/types.d.ts → types.d.ts} +10 -3
  132. package/dist/types.js +1 -0
  133. package/package.json +46 -47
  134. package/skills/dss-query/REFERENCE.md +123 -0
  135. package/skills/dss-query/SKILL.md +190 -0
  136. package/skills/dss-query/evals/README.md +79 -0
  137. package/skills/dss-query/evals/evals.json +89 -0
  138. package/skills/dss-query/evals/grade.mjs +480 -0
  139. package/src/attribute.ts +186 -0
  140. package/src/combinator.ts +132 -0
  141. package/src/id.ts +46 -0
  142. package/src/index.ts +620 -0
  143. package/src/parser.ts +122 -0
  144. package/src/pseudo/abandoned.ts +9 -0
  145. package/src/pseudo/attr.ts +92 -0
  146. package/src/pseudo/built.ts +19 -0
  147. package/src/pseudo/confused.ts +29 -0
  148. package/src/pseudo/cve.ts +93 -0
  149. package/src/pseudo/cwe.ts +97 -0
  150. package/src/pseudo/debug.ts +9 -0
  151. package/src/pseudo/deprecated.ts +9 -0
  152. package/src/pseudo/dev.ts +18 -0
  153. package/src/pseudo/diff.ts +90 -0
  154. package/src/pseudo/dist.ts +144 -0
  155. package/src/pseudo/dynamic.ts +9 -0
  156. package/src/pseudo/empty.ts +15 -0
  157. package/src/pseudo/entropic.ts +9 -0
  158. package/src/pseudo/env.ts +6 -0
  159. package/src/pseudo/eval.ts +9 -0
  160. package/src/pseudo/fs.ts +9 -0
  161. package/src/pseudo/helpers.ts +106 -0
  162. package/src/pseudo/host.ts +111 -0
  163. package/src/pseudo/hostname.ts +156 -0
  164. package/src/pseudo/license.ts +134 -0
  165. package/src/pseudo/link.ts +30 -0
  166. package/src/pseudo/malware.ts +41 -0
  167. package/src/pseudo/minified.ts +9 -0
  168. package/src/pseudo/missing.ts +16 -0
  169. package/src/pseudo/native.ts +9 -0
  170. package/src/pseudo/network.ts +9 -0
  171. package/src/pseudo/obfuscated.ts +9 -0
  172. package/src/pseudo/optional.ts +18 -0
  173. package/src/pseudo/outdated.ts +305 -0
  174. package/src/pseudo/overridden.ts +20 -0
  175. package/src/pseudo/path.ts +146 -0
  176. package/src/pseudo/peer.ts +18 -0
  177. package/src/pseudo/prerelease.ts +47 -0
  178. package/src/pseudo/private.ts +19 -0
  179. package/src/pseudo/prod.ts +18 -0
  180. package/src/pseudo/published.ts +248 -0
  181. package/src/pseudo/registry.ts +29 -0
  182. package/src/pseudo/root.ts +19 -0
  183. package/src/pseudo/scanned.ts +20 -0
  184. package/src/pseudo/score.ts +186 -0
  185. package/src/pseudo/scripts.ts +54 -0
  186. package/src/pseudo/semver.ts +320 -0
  187. package/src/pseudo/severity.ts +231 -0
  188. package/src/pseudo/shell.ts +9 -0
  189. package/src/pseudo/shrinkwrap.ts +9 -0
  190. package/src/pseudo/spec.ts +131 -0
  191. package/src/pseudo/squat.ts +225 -0
  192. package/src/pseudo/suspicious.ts +9 -0
  193. package/src/pseudo/tracker.ts +9 -0
  194. package/src/pseudo/trivial.ts +9 -0
  195. package/src/pseudo/type.ts +26 -0
  196. package/src/pseudo/undesirable.ts +9 -0
  197. package/src/pseudo/unknown.ts +9 -0
  198. package/src/pseudo/unmaintained.ts +9 -0
  199. package/src/pseudo/unpopular.ts +9 -0
  200. package/src/pseudo/unstable.ts +9 -0
  201. package/src/pseudo/vuln.ts +273 -0
  202. package/src/pseudo/workspace.ts +22 -0
  203. package/src/pseudo.ts +413 -0
  204. package/src/types.ts +165 -0
  205. package/tap-snapshots/test/attribute.ts.test.cjs +304 -0
  206. package/tap-snapshots/test/combinator.ts.test.cjs +333 -0
  207. package/tap-snapshots/test/id.ts.test.cjs +118 -0
  208. package/tap-snapshots/test/parser.ts.test.cjs +344 -0
  209. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +18 -0
  210. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +161 -0
  211. package/tap-snapshots/test/pseudo/built.ts.test.cjs +70 -0
  212. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +32 -0
  213. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +49 -0
  214. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +49 -0
  215. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +18 -0
  216. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +18 -0
  217. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +30 -0
  218. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +18 -0
  219. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +50 -0
  220. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +18 -0
  221. package/tap-snapshots/test/pseudo/env.ts.test.cjs +18 -0
  222. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +18 -0
  223. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +18 -0
  224. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +18 -0
  225. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +148 -0
  226. package/tap-snapshots/test/pseudo/license.ts.test.cjs +41 -0
  227. package/tap-snapshots/test/pseudo/link.ts.test.cjs +36 -0
  228. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +22 -0
  229. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +18 -0
  230. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +30 -0
  231. package/tap-snapshots/test/pseudo/native.ts.test.cjs +18 -0
  232. package/tap-snapshots/test/pseudo/network.ts.test.cjs +18 -0
  233. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +18 -0
  234. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +130 -0
  235. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +75 -0
  236. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +101 -0
  237. package/tap-snapshots/test/pseudo/private.ts.test.cjs +38 -0
  238. package/tap-snapshots/test/pseudo/published.ts.test.cjs +171 -0
  239. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +68 -0
  240. package/tap-snapshots/test/pseudo/root.ts.test.cjs +24 -0
  241. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +18 -0
  242. package/tap-snapshots/test/pseudo/score.ts.test.cjs +239 -0
  243. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +61 -0
  244. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +575 -0
  245. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +95 -0
  246. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +18 -0
  247. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +18 -0
  248. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +148 -0
  249. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +129 -0
  250. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +18 -0
  251. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +18 -0
  252. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +18 -0
  253. package/tap-snapshots/test/pseudo/type.ts.test.cjs +51 -0
  254. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +18 -0
  255. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +18 -0
  256. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +18 -0
  257. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +18 -0
  258. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +18 -0
  259. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +208 -0
  260. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +20 -0
  261. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +19 -0
  262. package/tap-snapshots/test/pseudo.ts.test.cjs +1247 -0
  263. package/test/attribute.ts +266 -0
  264. package/test/combinator.ts +168 -0
  265. package/test/fixtures/graph.ts +999 -0
  266. package/test/fixtures/selector.ts +103 -0
  267. package/test/fixtures/types.ts +7 -0
  268. package/test/id.ts +102 -0
  269. package/test/index.ts +1000 -0
  270. package/test/parser.ts +117 -0
  271. package/test/pseudo/abandoned.ts +98 -0
  272. package/test/pseudo/attr.ts +298 -0
  273. package/test/pseudo/built.ts +214 -0
  274. package/test/pseudo/confused.ts +160 -0
  275. package/test/pseudo/cve.ts +249 -0
  276. package/test/pseudo/cwe.ts +255 -0
  277. package/test/pseudo/debug.ts +98 -0
  278. package/test/pseudo/deprecated.ts +98 -0
  279. package/test/pseudo/dev.ts +61 -0
  280. package/test/pseudo/diff.ts +417 -0
  281. package/test/pseudo/dist.ts +215 -0
  282. package/test/pseudo/dynamic.ts +98 -0
  283. package/test/pseudo/empty.ts +108 -0
  284. package/test/pseudo/entropic.ts +101 -0
  285. package/test/pseudo/env.ts +98 -0
  286. package/test/pseudo/eval.ts +98 -0
  287. package/test/pseudo/fs.ts +98 -0
  288. package/test/pseudo/helpers.ts +370 -0
  289. package/test/pseudo/host-context.ts +276 -0
  290. package/test/pseudo/hostname.ts +314 -0
  291. package/test/pseudo/license.ts +265 -0
  292. package/test/pseudo/link.ts +94 -0
  293. package/test/pseudo/malware.ts +184 -0
  294. package/test/pseudo/minified.ts +98 -0
  295. package/test/pseudo/missing.ts +111 -0
  296. package/test/pseudo/native.ts +98 -0
  297. package/test/pseudo/network.ts +98 -0
  298. package/test/pseudo/obfuscated.ts +98 -0
  299. package/test/pseudo/optional.ts +73 -0
  300. package/test/pseudo/outdated.ts +331 -0
  301. package/test/pseudo/overridden.ts +317 -0
  302. package/test/pseudo/path.ts +680 -0
  303. package/test/pseudo/peer.ts +101 -0
  304. package/test/pseudo/prerelease.ts +279 -0
  305. package/test/pseudo/private.ts +108 -0
  306. package/test/pseudo/prod.ts +61 -0
  307. package/test/pseudo/published.ts +557 -0
  308. package/test/pseudo/registry.ts +122 -0
  309. package/test/pseudo/root.ts +66 -0
  310. package/test/pseudo/scanned.ts +78 -0
  311. package/test/pseudo/score.ts +591 -0
  312. package/test/pseudo/scripts.ts +294 -0
  313. package/test/pseudo/semver.ts +822 -0
  314. package/test/pseudo/severity.ts +310 -0
  315. package/test/pseudo/shell.ts +98 -0
  316. package/test/pseudo/shrinkwrap.ts +98 -0
  317. package/test/pseudo/spec.ts +525 -0
  318. package/test/pseudo/squat.ts +565 -0
  319. package/test/pseudo/suspicious.ts +98 -0
  320. package/test/pseudo/tracker.ts +98 -0
  321. package/test/pseudo/trivial.ts +98 -0
  322. package/test/pseudo/type.ts +105 -0
  323. package/test/pseudo/undesirable.ts +98 -0
  324. package/test/pseudo/unknown.ts +98 -0
  325. package/test/pseudo/unmaintained.ts +98 -0
  326. package/test/pseudo/unpopular.ts +98 -0
  327. package/test/pseudo/unstable.ts +98 -0
  328. package/test/pseudo/vuln.ts +625 -0
  329. package/test/pseudo/vulnerable.ts +137 -0
  330. package/test/pseudo/workspace.ts +111 -0
  331. package/test/pseudo.ts +558 -0
  332. package/tsconfig.json +3 -0
  333. package/tsconfig.publish.json +19 -0
  334. package/tsconfig.publish.tsbuildinfo +1 -0
  335. package/typedoc.mjs +2 -0
  336. package/dist/esm/attribute.d.ts.map +0 -1
  337. package/dist/esm/attribute.js.map +0 -1
  338. package/dist/esm/combinator.d.ts.map +0 -1
  339. package/dist/esm/combinator.js.map +0 -1
  340. package/dist/esm/id.d.ts.map +0 -1
  341. package/dist/esm/id.js.map +0 -1
  342. package/dist/esm/index.d.ts.map +0 -1
  343. package/dist/esm/index.js.map +0 -1
  344. package/dist/esm/package.json +0 -3
  345. package/dist/esm/parser.d.ts.map +0 -1
  346. package/dist/esm/parser.js.map +0 -1
  347. package/dist/esm/pseudo/abandoned.d.ts.map +0 -1
  348. package/dist/esm/pseudo/abandoned.js.map +0 -1
  349. package/dist/esm/pseudo/attr.d.ts.map +0 -1
  350. package/dist/esm/pseudo/attr.js.map +0 -1
  351. package/dist/esm/pseudo/built.d.ts.map +0 -1
  352. package/dist/esm/pseudo/built.js.map +0 -1
  353. package/dist/esm/pseudo/confused.d.ts.map +0 -1
  354. package/dist/esm/pseudo/confused.js.map +0 -1
  355. package/dist/esm/pseudo/cve.d.ts.map +0 -1
  356. package/dist/esm/pseudo/cve.js +0 -44
  357. package/dist/esm/pseudo/cve.js.map +0 -1
  358. package/dist/esm/pseudo/cwe.d.ts.map +0 -1
  359. package/dist/esm/pseudo/cwe.js +0 -43
  360. package/dist/esm/pseudo/cwe.js.map +0 -1
  361. package/dist/esm/pseudo/debug.d.ts.map +0 -1
  362. package/dist/esm/pseudo/debug.js.map +0 -1
  363. package/dist/esm/pseudo/deprecated.d.ts.map +0 -1
  364. package/dist/esm/pseudo/deprecated.js.map +0 -1
  365. package/dist/esm/pseudo/dev.d.ts.map +0 -1
  366. package/dist/esm/pseudo/dev.js.map +0 -1
  367. package/dist/esm/pseudo/dynamic.d.ts.map +0 -1
  368. package/dist/esm/pseudo/dynamic.js.map +0 -1
  369. package/dist/esm/pseudo/empty.d.ts.map +0 -1
  370. package/dist/esm/pseudo/empty.js.map +0 -1
  371. package/dist/esm/pseudo/entropic.d.ts.map +0 -1
  372. package/dist/esm/pseudo/entropic.js.map +0 -1
  373. package/dist/esm/pseudo/env.d.ts.map +0 -1
  374. package/dist/esm/pseudo/env.js.map +0 -1
  375. package/dist/esm/pseudo/eval.d.ts.map +0 -1
  376. package/dist/esm/pseudo/eval.js.map +0 -1
  377. package/dist/esm/pseudo/fs.d.ts.map +0 -1
  378. package/dist/esm/pseudo/fs.js.map +0 -1
  379. package/dist/esm/pseudo/helpers.d.ts.map +0 -1
  380. package/dist/esm/pseudo/helpers.js.map +0 -1
  381. package/dist/esm/pseudo/host.d.ts.map +0 -1
  382. package/dist/esm/pseudo/host.js.map +0 -1
  383. package/dist/esm/pseudo/license.d.ts.map +0 -1
  384. package/dist/esm/pseudo/license.js.map +0 -1
  385. package/dist/esm/pseudo/link.d.ts.map +0 -1
  386. package/dist/esm/pseudo/link.js.map +0 -1
  387. package/dist/esm/pseudo/malware.d.ts +0 -24
  388. package/dist/esm/pseudo/malware.d.ts.map +0 -1
  389. package/dist/esm/pseudo/malware.js +0 -187
  390. package/dist/esm/pseudo/malware.js.map +0 -1
  391. package/dist/esm/pseudo/minified.d.ts.map +0 -1
  392. package/dist/esm/pseudo/minified.js.map +0 -1
  393. package/dist/esm/pseudo/missing.d.ts.map +0 -1
  394. package/dist/esm/pseudo/missing.js.map +0 -1
  395. package/dist/esm/pseudo/native.d.ts.map +0 -1
  396. package/dist/esm/pseudo/native.js.map +0 -1
  397. package/dist/esm/pseudo/network.d.ts.map +0 -1
  398. package/dist/esm/pseudo/network.js.map +0 -1
  399. package/dist/esm/pseudo/obfuscated.d.ts.map +0 -1
  400. package/dist/esm/pseudo/obfuscated.js.map +0 -1
  401. package/dist/esm/pseudo/optional.d.ts.map +0 -1
  402. package/dist/esm/pseudo/optional.js.map +0 -1
  403. package/dist/esm/pseudo/outdated.d.ts.map +0 -1
  404. package/dist/esm/pseudo/outdated.js.map +0 -1
  405. package/dist/esm/pseudo/overridden.d.ts.map +0 -1
  406. package/dist/esm/pseudo/overridden.js.map +0 -1
  407. package/dist/esm/pseudo/path.d.ts.map +0 -1
  408. package/dist/esm/pseudo/path.js.map +0 -1
  409. package/dist/esm/pseudo/peer.d.ts.map +0 -1
  410. package/dist/esm/pseudo/peer.js.map +0 -1
  411. package/dist/esm/pseudo/prerelease.d.ts.map +0 -1
  412. package/dist/esm/pseudo/prerelease.js.map +0 -1
  413. package/dist/esm/pseudo/private.d.ts.map +0 -1
  414. package/dist/esm/pseudo/private.js.map +0 -1
  415. package/dist/esm/pseudo/prod.d.ts.map +0 -1
  416. package/dist/esm/pseudo/prod.js.map +0 -1
  417. package/dist/esm/pseudo/published.d.ts.map +0 -1
  418. package/dist/esm/pseudo/published.js.map +0 -1
  419. package/dist/esm/pseudo/root.d.ts.map +0 -1
  420. package/dist/esm/pseudo/root.js.map +0 -1
  421. package/dist/esm/pseudo/scanned.d.ts.map +0 -1
  422. package/dist/esm/pseudo/scanned.js.map +0 -1
  423. package/dist/esm/pseudo/score.d.ts.map +0 -1
  424. package/dist/esm/pseudo/score.js.map +0 -1
  425. package/dist/esm/pseudo/scripts.d.ts.map +0 -1
  426. package/dist/esm/pseudo/scripts.js.map +0 -1
  427. package/dist/esm/pseudo/semver.d.ts.map +0 -1
  428. package/dist/esm/pseudo/semver.js.map +0 -1
  429. package/dist/esm/pseudo/severity.d.ts.map +0 -1
  430. package/dist/esm/pseudo/severity.js.map +0 -1
  431. package/dist/esm/pseudo/shell.d.ts.map +0 -1
  432. package/dist/esm/pseudo/shell.js.map +0 -1
  433. package/dist/esm/pseudo/shrinkwrap.d.ts.map +0 -1
  434. package/dist/esm/pseudo/shrinkwrap.js.map +0 -1
  435. package/dist/esm/pseudo/spec.d.ts.map +0 -1
  436. package/dist/esm/pseudo/spec.js.map +0 -1
  437. package/dist/esm/pseudo/squat.d.ts.map +0 -1
  438. package/dist/esm/pseudo/squat.js.map +0 -1
  439. package/dist/esm/pseudo/suspicious.d.ts.map +0 -1
  440. package/dist/esm/pseudo/suspicious.js.map +0 -1
  441. package/dist/esm/pseudo/tracker.d.ts.map +0 -1
  442. package/dist/esm/pseudo/tracker.js.map +0 -1
  443. package/dist/esm/pseudo/trivial.d.ts.map +0 -1
  444. package/dist/esm/pseudo/trivial.js.map +0 -1
  445. package/dist/esm/pseudo/type.d.ts.map +0 -1
  446. package/dist/esm/pseudo/type.js.map +0 -1
  447. package/dist/esm/pseudo/undesirable.d.ts.map +0 -1
  448. package/dist/esm/pseudo/undesirable.js.map +0 -1
  449. package/dist/esm/pseudo/unknown.d.ts.map +0 -1
  450. package/dist/esm/pseudo/unknown.js.map +0 -1
  451. package/dist/esm/pseudo/unmaintained.d.ts.map +0 -1
  452. package/dist/esm/pseudo/unmaintained.js.map +0 -1
  453. package/dist/esm/pseudo/unpopular.d.ts.map +0 -1
  454. package/dist/esm/pseudo/unpopular.js.map +0 -1
  455. package/dist/esm/pseudo/unstable.d.ts.map +0 -1
  456. package/dist/esm/pseudo/unstable.js.map +0 -1
  457. package/dist/esm/pseudo/workspace.d.ts.map +0 -1
  458. package/dist/esm/pseudo/workspace.js.map +0 -1
  459. package/dist/esm/pseudo.d.ts.map +0 -1
  460. package/dist/esm/pseudo.js.map +0 -1
  461. package/dist/esm/types.d.ts.map +0 -1
  462. package/dist/esm/types.js +0 -2
  463. package/dist/esm/types.js.map +0 -1
package/test/index.ts ADDED
@@ -0,0 +1,1000 @@
1
+ import t from 'tap'
2
+ import { Query, walk } from '../src/index.ts'
3
+ import {
4
+ getCycleGraph,
5
+ getSimpleGraph,
6
+ getSingleWorkspaceGraph,
7
+ } from './fixtures/graph.ts'
8
+ import { copyGraphSelectionState } from './fixtures/selector.ts'
9
+ import { joinDepIDTuple } from '@vltpkg/dep-id'
10
+ import {
11
+ asPackageReportData,
12
+ asSecurityArchiveLike,
13
+ } from '@vltpkg/security-archive'
14
+ import type {
15
+ ParsedSelectorToken,
16
+ ParserState,
17
+ QueryResponse,
18
+ } from '../src/types.ts'
19
+ import type { PostcssNode } from '@vltpkg/dss-parser'
20
+
21
+ type TestCase = [string, string[]]
22
+
23
+ // Create a mock search options for tests
24
+ const mockSearchOptions = {
25
+ signal: { throwIfAborted: () => {} } as AbortSignal,
26
+ scopeIDs: [joinDepIDTuple(['file', '.'])],
27
+ }
28
+
29
+ const testBrokenState = (): ParserState => {
30
+ const graph = getSimpleGraph()
31
+ const initial = {
32
+ nodes: new Set(graph.nodes.values()),
33
+ edges: new Set(graph.edges.values()),
34
+ }
35
+ const state: ParserState = {
36
+ cancellable: async () => {},
37
+ collect: {
38
+ nodes: new Set(),
39
+ edges: new Set(),
40
+ },
41
+ comment: '',
42
+ current: { type: 'bork' } as unknown as PostcssNode,
43
+ initial: copyGraphSelectionState(initial),
44
+ partial: copyGraphSelectionState(initial),
45
+ importers: new Set(graph.importers),
46
+ hostContexts: undefined,
47
+ walk,
48
+ retries: 0,
49
+ scopeIDs: mockSearchOptions.scopeIDs,
50
+ securityArchive: undefined,
51
+ signal: mockSearchOptions.signal,
52
+ specificity: { idCounter: 0, commonCounter: 0 },
53
+ }
54
+ return state
55
+ }
56
+
57
+ t.test('simple graph', async t => {
58
+ const graph = getSimpleGraph()
59
+ const queryToExpected = new Set<TestCase>([
60
+ ['', []], // should match no deps on missing query
61
+ ['*', ['my-project', 'a', 'b', 'c', 'd', 'e', 'f', '@x/y']], // universal
62
+ ['*', ['my-project', 'a', 'b', 'c', 'd', 'e', 'f', '@x/y']], // repeat, cache-hit
63
+ ['* >*', ['a', 'b', 'e', '@x/y', 'c', 'd', 'f']], // dependencies
64
+ [':root', ['my-project']], // select :root
65
+ [':root > *', ['a', 'b', 'e', '@x/y']], // direct deps of :root
66
+ [':root > :root', []], // :root pseudo-selector can't depend on itself
67
+ [':dev', ['b', '@x/y']], // retrieve deps of dev type
68
+ [':root > :dev', ['b', '@x/y']], // mixed with a combinator
69
+ [':root > :dev[name=b]', ['b']], // specific node
70
+ [':root > [name=b]:dev', ['b']], // specific node backwards
71
+ [':root > *[name=b]:dev', ['b']], // specific node backwards with universal
72
+ [':root > :dev[name=b] ~ *', ['a', 'e', '@x/y']], // retrieves its siblings
73
+ [':root > :optional', []], // no direct optional dep
74
+ [':root :optional', ['f']], // optional descendent found
75
+ [':root *', ['a', 'b', 'e', '@x/y', 'c', 'd', 'f']], // all descendents from root
76
+ ['[name=a]', ['a']], // select by name
77
+ [':root :has([name])', ['b', 'd']], // combined has example, filtering any descendent that has direct deps with a name
78
+ [':root > [name=a]', ['a']], // select children by name
79
+ [':root > [name=d] [name=b]', []], // no direct descendent with that name
80
+ [':root > [name=d] [name=e]', []], // descendent found by name
81
+ [':root [name=d] ~ [name=c]', ['c']], // fully qualified
82
+ [':root [name^=@x]', ['@x/y']], // attribute starts with value
83
+ ['/* do something */ :root [name^=@x]', ['@x/y']], // support comments
84
+ [':root > *{&[name=a]}', ['a']], // support nesting
85
+ [':root > * { &[name=a] }', ['a']], // support nesting with spaces
86
+ [':root > * { &[name=a], &[name=b] }', ['a', 'b']], // support multiple nesting selectors
87
+ ['[name=b], [name=c], [name=f]', ['b', 'c', 'f']], // select by name
88
+ ['[name=d], [name=d] > *', ['d', 'e', 'f']], // select a package and its dependencies
89
+ [
90
+ ':root > *, :prod, [name=a], :has(:dev, :optional)',
91
+ ['a', 'b', 'e', '@x/y', 'c', 'd', 'my-project'],
92
+ ],
93
+ ['#a', ['a']], // identifier
94
+ ['#a:v(1)', ['a']], // matches identifier + semver
95
+ ['#a:v(2)', []], // fails to match identifier + semver
96
+ [':path("*")', ['my-project', '@x/y']], // path selector for all path-based nodes
97
+ [':path(".")', ['my-project']], // path selector for root
98
+ [':path("**/a/**")', []], // should not match since 'a' is not workspace or file type
99
+ [':root, #a, :foo', ['my-project', 'a']], // should be loose on multiple selectors
100
+ ])
101
+
102
+ const query = new Query({
103
+ nodes: new Set(graph.nodes.values()),
104
+ edges: graph.edges,
105
+ importers: graph.importers,
106
+ securityArchive: undefined,
107
+ })
108
+ for (const [q, expected] of queryToExpected) {
109
+ t.strictSame(
110
+ (await query.search(q, mockSearchOptions)).nodes.map(
111
+ i => i.name,
112
+ ),
113
+ expected,
114
+ `query > "${q}"`,
115
+ )
116
+ }
117
+
118
+ await t.test('comments extraction', async t => {
119
+ const result = await query.search(
120
+ '/* comment one */ :root /* comment two */ > * /* comment three */',
121
+ mockSearchOptions,
122
+ )
123
+ t.strictSame(
124
+ result.comment,
125
+ 'comment one',
126
+ 'should extract the first comment from query',
127
+ )
128
+ })
129
+
130
+ await t.test('comments extraction with no comments', async t => {
131
+ const result = await query.search(':root > *', mockSearchOptions)
132
+ t.strictSame(
133
+ result.comment,
134
+ '',
135
+ 'should return empty string for query without comments',
136
+ )
137
+ })
138
+
139
+ await t.test('comments cache hit', async t => {
140
+ const q = '/* cached comment */ :root'
141
+ await query.search(q, mockSearchOptions) // First call to populate cache
142
+ const result = await query.search(q, mockSearchOptions) // Second call should hit cache
143
+ t.strictSame(
144
+ result.comment,
145
+ 'cached comment',
146
+ 'should return comment for cached query results',
147
+ )
148
+ })
149
+ })
150
+
151
+ t.test('workspace', async t => {
152
+ const graph = getSingleWorkspaceGraph()
153
+ const queryToExpected = new Map<string, string[]>([
154
+ ['', []], // should match no deps on missing query
155
+ ['*', ['ws', 'w']], // universal
156
+ [':root', ['ws']], // select :root
157
+ [':root > *', []], // direct deps of :root
158
+ [':root > :root', []], // :root can't depend on itself
159
+ [':project#w', ['w']], // select by project + workspace name
160
+ ['#w:project', ['w']], // should be interchangeable
161
+ ['/* do something */ [name^=w]', ['ws', 'w']], // support comments
162
+ ])
163
+ const query = new Query({
164
+ nodes: new Set(graph.nodes.values()),
165
+ edges: graph.edges,
166
+ importers: graph.importers,
167
+ securityArchive: undefined,
168
+ })
169
+ for (const [q, expected] of queryToExpected) {
170
+ t.strictSame(
171
+ (await query.search(q, mockSearchOptions)).nodes.map(
172
+ i => i.name,
173
+ ),
174
+ expected,
175
+ `query > "${q}"`,
176
+ )
177
+ }
178
+
179
+ await t.test('comments handling', async t => {
180
+ const result = await query.search(
181
+ '/* workspace comment */ :root',
182
+ mockSearchOptions,
183
+ )
184
+ t.strictSame(
185
+ result.comment,
186
+ 'workspace comment',
187
+ 'should extract comment from workspace query',
188
+ )
189
+ })
190
+ })
191
+
192
+ t.test('cycle', async t => {
193
+ const graph = getCycleGraph()
194
+ const queryToExpected = new Set<TestCase>([
195
+ ['', []], // should match no deps on missing query
196
+ ['*', ['cycle-project', 'a', 'b']], // universal
197
+ [':root', ['cycle-project']], // select :root
198
+ [':root > *', ['a']], // direct deps of :root
199
+ [':root > :root', []], // :root can depend on itself
200
+ ['/* do something */ [name^=a]', ['a']], // support comments
201
+ [':root > :prod > *', ['b']], // mixed selectors
202
+ ])
203
+ const query = new Query({
204
+ nodes: new Set(graph.nodes.values()),
205
+ edges: graph.edges,
206
+ importers: graph.importers,
207
+ securityArchive: undefined,
208
+ })
209
+ for (const [q, expected] of queryToExpected) {
210
+ t.strictSame(
211
+ (await query.search(q, mockSearchOptions)).nodes.map(
212
+ i => i.name,
213
+ ),
214
+ expected,
215
+ `query > "${q}"`,
216
+ )
217
+ }
218
+ })
219
+
220
+ t.test('insights', async t => {
221
+ const graph = getSimpleGraph()
222
+ const queryToExpected = new Set<TestCase>([
223
+ ['*', ['my-project', 'a', 'b', 'c', 'd', 'e', 'f', '@x/y']], // universal
224
+ ['*:severity(high)', ['e']], // universal with severity filter
225
+ ['*:cve(CVE-2023-1234)', ['e']], // match cve by id
226
+ ])
227
+ const query = new Query({
228
+ nodes: new Set(graph.nodes.values()),
229
+ edges: graph.edges,
230
+ importers: graph.importers,
231
+ securityArchive: asSecurityArchiveLike(
232
+ new Map([
233
+ [
234
+ joinDepIDTuple(['registry', '', 'e@1.0.0']),
235
+ asPackageReportData({
236
+ id: 'e@1.0.0',
237
+ author: [],
238
+ size: 0,
239
+ type: 'npm',
240
+ name: 'e',
241
+ version: '1.0.0',
242
+ license: 'MIT',
243
+ score: {
244
+ overall: 0.5,
245
+ security: 0.3,
246
+ maintenance: 0.7,
247
+ popularity: 0.6,
248
+ },
249
+ alerts: [
250
+ {
251
+ key: '12314320948130',
252
+ type: 'cve',
253
+ severity: 'high',
254
+ category: 'security',
255
+ props: {
256
+ cveId: 'CVE-2023-1234',
257
+ lastPublish: '2023-01-01',
258
+ cwes: [{ id: 'CWE-1234' }],
259
+ },
260
+ },
261
+ ],
262
+ }),
263
+ ],
264
+ ]),
265
+ ),
266
+ })
267
+ for (const [q, expected] of queryToExpected) {
268
+ const result = await query.search(q, mockSearchOptions)
269
+ t.strictSame(
270
+ result.nodes.map(i => i.name),
271
+ expected,
272
+ `query > "${q}"`,
273
+ )
274
+
275
+ // Verify score values for node 'e'
276
+ const nodeE = result.nodes.find(n => n.name === 'e')
277
+ if (nodeE) {
278
+ t.strictSame(
279
+ nodeE.insights.score,
280
+ {
281
+ overall: 0.5,
282
+ security: 0.3,
283
+ maintenance: 0.7,
284
+ popularity: 0.6,
285
+ },
286
+ 'node e should have correct score values',
287
+ )
288
+ }
289
+ }
290
+ })
291
+
292
+ t.test('bad selector type', async t => {
293
+ await t.rejects(
294
+ walk(testBrokenState()),
295
+ /Missing parser for query node: bork/,
296
+ 'should throw a parser error',
297
+ )
298
+ })
299
+
300
+ t.test('bad selector type [loose mode]', async t => {
301
+ await t.resolves(
302
+ walk({ ...testBrokenState(), loose: true }),
303
+ 'should resolve with no error',
304
+ )
305
+ })
306
+
307
+ t.test('trying to use tag selectors', async t => {
308
+ const graph = getSimpleGraph()
309
+ await t.rejects(
310
+ new Query({
311
+ nodes: new Set(graph.nodes.values()),
312
+ edges: graph.edges,
313
+ importers: graph.importers,
314
+ securityArchive: undefined,
315
+ }).search('foo', mockSearchOptions),
316
+ /Unsupported selector/,
317
+ 'should throw an unsupported selector error',
318
+ )
319
+ })
320
+
321
+ t.test('trying to use string selectors', async t => {
322
+ const graph = getSimpleGraph()
323
+ await t.rejects(
324
+ new Query({
325
+ nodes: new Set(graph.nodes.values()),
326
+ edges: graph.edges,
327
+ importers: graph.importers,
328
+ securityArchive: undefined,
329
+ }).search('"foo"', mockSearchOptions),
330
+ /Unsupported selector/,
331
+ 'should throw an unsupported selector error',
332
+ )
333
+ })
334
+
335
+ t.test('cancellable search', async t => {
336
+ const graph = getSingleWorkspaceGraph()
337
+ const query = new Query({
338
+ nodes: new Set(graph.nodes.values()),
339
+ edges: graph.edges,
340
+ importers: graph.importers,
341
+ securityArchive: undefined,
342
+ })
343
+ const ac = new AbortController()
344
+ const q = ':root > * > *'
345
+ await t.rejects(
346
+ new Promise((_, reject) => {
347
+ void query
348
+ .search(q, { signal: ac.signal })
349
+ .catch((err: unknown) => {
350
+ reject(err)
351
+ })
352
+ ac.abort(new Error('query aborted'))
353
+ // the set timeout bellow should never be called since
354
+ // the search should throw the abort error before
355
+ setTimeout(() => {
356
+ reject(new Error('ERR'))
357
+ }, 1000)
358
+ }),
359
+ /query aborted/,
360
+ 'should reject with abort error',
361
+ )
362
+ })
363
+
364
+ t.test('Query.hasSecuritySelectors', async t => {
365
+ t.ok(
366
+ Query.hasSecuritySelectors(':root > *:unmaintained'),
367
+ 'should return true',
368
+ )
369
+ t.ok(
370
+ Query.hasSecuritySelectors(':root > *:has(:unmaintained)'),
371
+ 'should return true',
372
+ )
373
+ t.ok(
374
+ Query.hasSecuritySelectors(':unmaintained'),
375
+ 'should return true',
376
+ )
377
+ t.ok(
378
+ Query.hasSecuritySelectors(':vuln'),
379
+ 'should return true for :vuln',
380
+ )
381
+ t.ok(
382
+ Query.hasSecuritySelectors(':vulnerable'),
383
+ 'should return true for :vulnerable',
384
+ )
385
+ t.notOk(Query.hasSecuritySelectors(':foo'), 'should return false')
386
+ t.notOk(Query.hasSecuritySelectors(':has'), 'should return false')
387
+ })
388
+
389
+ t.test('getQueryTokens', t => {
390
+ const normalizeParseOutput = (nodes: ParsedSelectorToken[]) => {
391
+ return nodes.map(node => {
392
+ return {
393
+ type: node.type,
394
+ token: node.token,
395
+ }
396
+ })
397
+ }
398
+
399
+ t.test('should getQueryTokens empty query', t => {
400
+ t.strictSame(normalizeParseOutput(Query.getQueryTokens('')), [])
401
+ t.end()
402
+ })
403
+
404
+ t.test('should getQueryTokens pseudo selector', t => {
405
+ t.strictSame(
406
+ normalizeParseOutput(Query.getQueryTokens(':root')),
407
+ [
408
+ {
409
+ type: 'pseudo',
410
+ token: ':root',
411
+ },
412
+ ],
413
+ )
414
+ t.end()
415
+ })
416
+
417
+ t.test('should getQueryTokens attribute selector', t => {
418
+ t.test('with value', t => {
419
+ t.strictSame(
420
+ normalizeParseOutput(Query.getQueryTokens('[name="react"]')),
421
+ [
422
+ {
423
+ type: 'attribute',
424
+ token: '[name="react"]',
425
+ },
426
+ ],
427
+ )
428
+ t.end()
429
+ })
430
+
431
+ t.test('with operator', t => {
432
+ t.strictSame(
433
+ normalizeParseOutput(Query.getQueryTokens('[name^="react"]')),
434
+ [
435
+ {
436
+ type: 'attribute',
437
+ token: '[name^="react"]',
438
+ },
439
+ ],
440
+ )
441
+ t.end()
442
+ })
443
+
444
+ t.test('without value', t => {
445
+ t.strictSame(
446
+ normalizeParseOutput(Query.getQueryTokens('[name]')),
447
+ [
448
+ {
449
+ type: 'attribute',
450
+ token: '[name]',
451
+ },
452
+ ],
453
+ )
454
+ t.end()
455
+ })
456
+ t.end()
457
+ })
458
+
459
+ t.test('should getQueryTokens class selector', t => {
460
+ t.strictSame(
461
+ normalizeParseOutput(Query.getQueryTokens('.container')),
462
+ [
463
+ {
464
+ type: 'tag',
465
+ token: '.container',
466
+ },
467
+ ],
468
+ )
469
+ t.end()
470
+ })
471
+
472
+ t.test('should getQueryTokens id selector', t => {
473
+ t.strictSame(
474
+ normalizeParseOutput(Query.getQueryTokens('#main')),
475
+ [
476
+ {
477
+ type: 'id',
478
+ token: '#main',
479
+ },
480
+ ],
481
+ )
482
+
483
+ t.test('should getQueryTokens scoped-name id selector', t => {
484
+ t.strictSame(
485
+ normalizeParseOutput(Query.getQueryTokens('#@scoped/name')),
486
+ [
487
+ {
488
+ type: 'id',
489
+ token: '#@scoped/name',
490
+ },
491
+ ],
492
+ )
493
+ t.end()
494
+ })
495
+
496
+ t.test(
497
+ 'should getQueryTokens dash-separated-scoped-name id selector',
498
+ t => {
499
+ t.strictSame(
500
+ normalizeParseOutput(
501
+ Query.getQueryTokens('#@scoped-org/name'),
502
+ ),
503
+ [
504
+ {
505
+ type: 'id',
506
+ token: '#@scoped-org/name',
507
+ },
508
+ ],
509
+ )
510
+ t.end()
511
+ },
512
+ )
513
+
514
+ t.test(
515
+ 'should getQueryTokens dot-separated-scoped-name id selector',
516
+ t => {
517
+ t.strictSame(
518
+ normalizeParseOutput(
519
+ Query.getQueryTokens('#@scoped.org/name'),
520
+ ),
521
+ [
522
+ {
523
+ type: 'id',
524
+ token: '#@scoped.org/name',
525
+ },
526
+ ],
527
+ )
528
+ t.end()
529
+ },
530
+ )
531
+ t.end()
532
+ })
533
+
534
+ t.test(
535
+ 'should getQueryTokens simple comma separated selector',
536
+ t => {
537
+ t.strictSame(
538
+ normalizeParseOutput(Query.getQueryTokens('#a, #b')),
539
+ [
540
+ {
541
+ type: 'id',
542
+ token: '#a',
543
+ },
544
+ {
545
+ type: 'selector',
546
+ token: ',',
547
+ },
548
+ {
549
+ type: 'id',
550
+ token: ' #b',
551
+ },
552
+ ],
553
+ )
554
+ t.end()
555
+ },
556
+ )
557
+
558
+ t.test('should getQueryTokens tags', t => {
559
+ t.strictSame(
560
+ normalizeParseOutput(Query.getQueryTokens('name=test')),
561
+ [
562
+ {
563
+ type: 'tag',
564
+ token: 'name=test',
565
+ },
566
+ ],
567
+ )
568
+ t.end()
569
+ })
570
+
571
+ t.test('should getQueryTokens strings', t => {
572
+ t.strictSame(
573
+ normalizeParseOutput(Query.getQueryTokens('name="test"')),
574
+ [
575
+ {
576
+ type: 'tag',
577
+ token: 'name=',
578
+ },
579
+ {
580
+ type: 'string',
581
+ token: '"test"',
582
+ },
583
+ ],
584
+ )
585
+ t.end()
586
+ })
587
+
588
+ t.test('should getQueryTokens combinator', t => {
589
+ t.test('non-whitespace', t => {
590
+ t.strictSame(normalizeParseOutput(Query.getQueryTokens('>')), [
591
+ {
592
+ type: 'combinator',
593
+ token: '>',
594
+ },
595
+ ])
596
+ t.end()
597
+ })
598
+
599
+ t.test('whitespace', t => {
600
+ t.strictSame(Query.getQueryTokens(' '), [])
601
+ t.end()
602
+ })
603
+ t.end()
604
+ })
605
+
606
+ t.test('should getQueryTokens complex selector', t => {
607
+ t.test('with nested selectors', t => {
608
+ t.strictSame(
609
+ normalizeParseOutput(
610
+ Query.getQueryTokens(':root > [name="react"] .container'),
611
+ ),
612
+ [
613
+ {
614
+ type: 'pseudo',
615
+ token: ':root',
616
+ },
617
+ {
618
+ type: 'combinator',
619
+ token: ' > ',
620
+ },
621
+ {
622
+ type: 'attribute',
623
+ token: '[name="react"]',
624
+ },
625
+ {
626
+ type: 'combinator',
627
+ token: ' ',
628
+ },
629
+ {
630
+ type: 'tag',
631
+ token: '.container',
632
+ },
633
+ ],
634
+ )
635
+ t.end()
636
+ })
637
+
638
+ t.test('with nested pseudo selectors', t => {
639
+ t.strictSame(
640
+ normalizeParseOutput(Query.getQueryTokens(':not(#react)')),
641
+ [
642
+ {
643
+ type: 'pseudo',
644
+ token: ':not(',
645
+ },
646
+ {
647
+ type: 'id',
648
+ token: '#react',
649
+ },
650
+ {
651
+ type: 'pseudo',
652
+ token: ')',
653
+ },
654
+ ],
655
+ )
656
+ t.test('with nested comma separated selectors', t => {
657
+ t.strictSame(
658
+ normalizeParseOutput(
659
+ Query.getQueryTokens(':not(#a, #b), :is(#c)'),
660
+ ),
661
+ [
662
+ {
663
+ type: 'pseudo',
664
+ token: ':not(',
665
+ },
666
+ {
667
+ type: 'id',
668
+ token: '#a',
669
+ },
670
+ {
671
+ type: 'selector',
672
+ token: ',',
673
+ },
674
+ {
675
+ type: 'id',
676
+ token: ' #b',
677
+ },
678
+ {
679
+ type: 'pseudo',
680
+ token: ')',
681
+ },
682
+ {
683
+ type: 'selector',
684
+ token: ',',
685
+ },
686
+ {
687
+ type: 'pseudo',
688
+ token: ' :is(',
689
+ },
690
+ {
691
+ type: 'id',
692
+ token: '#c',
693
+ },
694
+ {
695
+ type: 'pseudo',
696
+ token: ')',
697
+ },
698
+ ],
699
+ )
700
+ t.end()
701
+ })
702
+ t.end()
703
+ })
704
+
705
+ t.test('with malformed queries', t => {
706
+ t.test('should handle unclosed brackets', t => {
707
+ t.strictSame(
708
+ normalizeParseOutput(Query.getQueryTokens('[name="react"')),
709
+ [],
710
+ )
711
+ t.end()
712
+ })
713
+
714
+ t.test('should handle unclosed pseudo selectors', t => {
715
+ t.strictSame(
716
+ normalizeParseOutput(Query.getQueryTokens(':not(#react')),
717
+ [
718
+ {
719
+ type: 'pseudo',
720
+ token: ':not',
721
+ },
722
+ ],
723
+ )
724
+ t.end()
725
+ })
726
+ t.end()
727
+ })
728
+
729
+ t.test('with multiple attributes', t => {
730
+ t.strictSame(
731
+ normalizeParseOutput(
732
+ Query.getQueryTokens('[name="react"][version="18"]'),
733
+ ),
734
+ [
735
+ {
736
+ type: 'attribute',
737
+ token: '[name="react"]',
738
+ },
739
+ {
740
+ type: 'attribute',
741
+ token: '[version="18"]',
742
+ },
743
+ ],
744
+ )
745
+ t.end()
746
+ })
747
+ t.end()
748
+ })
749
+
750
+ t.end()
751
+ })
752
+
753
+ t.test(':scope with custom scopeIDs', async t => {
754
+ const graph = getSimpleGraph()
755
+ const query = new Query({
756
+ nodes: new Set(graph.nodes.values()),
757
+ edges: graph.edges,
758
+ importers: graph.importers,
759
+ securityArchive: undefined,
760
+ })
761
+ const customScopeID = joinDepIDTuple(['registry', '', 'a@1.0.0'])
762
+ t.strictSame(
763
+ (
764
+ await query.search(':scope', {
765
+ ...mockSearchOptions,
766
+ scopeIDs: [customScopeID],
767
+ })
768
+ ).nodes.map(n => n.name),
769
+ ['a'],
770
+ 'should select only the node specified by scopeIDs',
771
+ )
772
+ })
773
+
774
+ t.test('specificity calculation', async t => {
775
+ const graph = getSimpleGraph()
776
+ const query = new Query({
777
+ nodes: new Set(graph.nodes.values()),
778
+ edges: graph.edges,
779
+ importers: graph.importers,
780
+ securityArchive: undefined,
781
+ })
782
+
783
+ const specificityTestCases = [
784
+ {
785
+ query: ':root',
786
+ idCounter: 0,
787
+ commonCounter: 1,
788
+ description: 'single pseudo-element',
789
+ },
790
+ {
791
+ query: ':root > #b',
792
+ idCounter: 1,
793
+ commonCounter: 1,
794
+ description: 'child combinator with id',
795
+ },
796
+ {
797
+ query: ':root #b',
798
+ idCounter: 1,
799
+ commonCounter: 1,
800
+ description: 'descendant combinator with id',
801
+ },
802
+ {
803
+ query: ':root ~ #b',
804
+ idCounter: 1,
805
+ commonCounter: 1,
806
+ description: 'sibling combinator with id',
807
+ },
808
+ {
809
+ query: ':root > #b > #c',
810
+ idCounter: 2,
811
+ commonCounter: 1,
812
+ description: 'multiple combinators with ids',
813
+ },
814
+ {
815
+ query: ':root > :prod',
816
+ idCounter: 0,
817
+ commonCounter: 2,
818
+ description: 'only pseudo classes',
819
+ },
820
+ {
821
+ query: ':root > :prod:dev',
822
+ idCounter: 0,
823
+ commonCounter: 3,
824
+ description: 'multiple pseudo classes',
825
+ },
826
+ {
827
+ query: ':root > :prod:dev:optional',
828
+ idCounter: 0,
829
+ commonCounter: 4,
830
+ description: 'multiple pseudo classes',
831
+ },
832
+ {
833
+ query: ':root > #missing',
834
+ idCounter: 1,
835
+ commonCounter: 1,
836
+ description: 'missing id still counts',
837
+ },
838
+ {
839
+ query: ':root > [name=b]',
840
+ idCounter: 0,
841
+ commonCounter: 2,
842
+ description: 'attribute selector',
843
+ },
844
+ {
845
+ query: ':root > [name=b][version=2.0.0]',
846
+ idCounter: 0,
847
+ commonCounter: 3,
848
+ description: 'multiple attribute selectors',
849
+ },
850
+ {
851
+ query: ':root > :not(:prod)',
852
+ idCounter: 0,
853
+ commonCounter: 1,
854
+ description: ':not does not affect specificity',
855
+ },
856
+ {
857
+ query: ':root > :is(:prod, :dev)',
858
+ idCounter: 0,
859
+ commonCounter: 1,
860
+ description: ':is does not affect specificity',
861
+ },
862
+ {
863
+ query: ':root > :has(:prod)',
864
+ idCounter: 0,
865
+ commonCounter: 1,
866
+ description: ':has does not affect specificity',
867
+ },
868
+ {
869
+ query: '#b:prod',
870
+ idCounter: 1,
871
+ commonCounter: 1,
872
+ description: 'id with pseudo class',
873
+ },
874
+ {
875
+ query: '#b:prod[name=b]',
876
+ idCounter: 1,
877
+ commonCounter: 2,
878
+ description: 'id with pseudo class and attribute',
879
+ },
880
+ ]
881
+
882
+ for (const {
883
+ query: queryStr,
884
+ idCounter,
885
+ commonCounter,
886
+ description,
887
+ } of specificityTestCases) {
888
+ const result = await query.search(queryStr, mockSearchOptions)
889
+ t.strictSame(
890
+ {
891
+ idCounter: result.specificity.idCounter,
892
+ commonCounter: result.specificity.commonCounter,
893
+ },
894
+ { idCounter, commonCounter },
895
+ `specificity for "${queryStr}" - ${description}`,
896
+ )
897
+ }
898
+ })
899
+
900
+ t.test('specificitySort', async t => {
901
+ // Create test QueryResponse objects with different specificity values
902
+ const responses: QueryResponse[] = [
903
+ {
904
+ edges: [],
905
+ nodes: [],
906
+ importers: [],
907
+ comment: 'First response (id:0, common:1)',
908
+ specificity: { idCounter: 0, commonCounter: 1 },
909
+ },
910
+ {
911
+ edges: [],
912
+ nodes: [],
913
+ importers: [],
914
+ comment: 'Second response (id:2, common:0)',
915
+ specificity: { idCounter: 2, commonCounter: 0 },
916
+ },
917
+ {
918
+ edges: [],
919
+ nodes: [],
920
+ importers: [],
921
+ comment: 'Third response (id:1, common:3)',
922
+ specificity: { idCounter: 1, commonCounter: 3 },
923
+ },
924
+ {
925
+ edges: [],
926
+ nodes: [],
927
+ importers: [],
928
+ comment: 'Fourth response (id:1, common:2)',
929
+ specificity: { idCounter: 1, commonCounter: 2 },
930
+ },
931
+ {
932
+ edges: [],
933
+ nodes: [],
934
+ importers: [],
935
+ comment: 'Fifth response (id:0, common:0)',
936
+ specificity: { idCounter: 0, commonCounter: 0 },
937
+ },
938
+ ]
939
+
940
+ const sortedResponses = Query.specificitySort(responses)
941
+
942
+ // Check that the order is correct based on specificity rules
943
+ t.strictSame(
944
+ sortedResponses.map(r => r.comment),
945
+ [
946
+ 'Second response (id:2, common:0)', // Highest idCounter (2)
947
+ 'Third response (id:1, common:3)', // Next idCounter (1) with higher commonCounter (3)
948
+ 'Fourth response (id:1, common:2)', // Same idCounter (1) with lower commonCounter (2)
949
+ 'First response (id:0, common:1)', // Lowest idCounter (0) with higher commonCounter (1)
950
+ 'Fifth response (id:0, common:0)', // Lowest idCounter (0) with lowest commonCounter (0)
951
+ ],
952
+ 'should sort responses by specificity with higher values first',
953
+ )
954
+
955
+ // Test that the original array is not modified
956
+ t.notSame(
957
+ responses.map(r => r.comment),
958
+ sortedResponses.map(r => r.comment),
959
+ 'should not modify the original array',
960
+ )
961
+
962
+ // Test that the sort is stable (preserves original order for equal specificity)
963
+ const equalSpecificityResponses: QueryResponse[] = [
964
+ {
965
+ edges: [],
966
+ nodes: [],
967
+ importers: [],
968
+ comment: 'First equal response',
969
+ specificity: { idCounter: 1, commonCounter: 1 },
970
+ },
971
+ {
972
+ edges: [],
973
+ nodes: [],
974
+ importers: [],
975
+ comment: 'Second equal response',
976
+ specificity: { idCounter: 1, commonCounter: 1 },
977
+ },
978
+ {
979
+ edges: [],
980
+ nodes: [],
981
+ importers: [],
982
+ comment: 'Third equal response',
983
+ specificity: { idCounter: 1, commonCounter: 1 },
984
+ },
985
+ ]
986
+
987
+ const sortedEqualResponses = Query.specificitySort(
988
+ equalSpecificityResponses,
989
+ )
990
+
991
+ t.strictSame(
992
+ sortedEqualResponses.map(r => r.comment),
993
+ [
994
+ 'First equal response',
995
+ 'Second equal response',
996
+ 'Third equal response',
997
+ ],
998
+ 'should preserve original order for equal specificity values',
999
+ )
1000
+ })