@vltpkg/query 0.0.0-8 → 1.0.0-rc.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 (159) hide show
  1. package/README.md +38 -249
  2. package/dist/esm/attribute.d.ts +1 -1
  3. package/dist/esm/attribute.d.ts.map +1 -1
  4. package/dist/esm/attribute.js +5 -12
  5. package/dist/esm/attribute.js.map +1 -1
  6. package/dist/esm/combinator.d.ts.map +1 -1
  7. package/dist/esm/combinator.js +1 -1
  8. package/dist/esm/combinator.js.map +1 -1
  9. package/dist/esm/id.d.ts.map +1 -1
  10. package/dist/esm/id.js +23 -7
  11. package/dist/esm/id.js.map +1 -1
  12. package/dist/esm/index.d.ts +29 -7
  13. package/dist/esm/index.d.ts.map +1 -1
  14. package/dist/esm/index.js +247 -21
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/parser.d.ts +15 -0
  17. package/dist/esm/parser.d.ts.map +1 -0
  18. package/dist/esm/parser.js +93 -0
  19. package/dist/esm/parser.js.map +1 -0
  20. package/dist/esm/pseudo/attr.d.ts +2 -1
  21. package/dist/esm/pseudo/attr.d.ts.map +1 -1
  22. package/dist/esm/pseudo/attr.js +10 -2
  23. package/dist/esm/pseudo/attr.js.map +1 -1
  24. package/dist/esm/pseudo/built.d.ts +8 -0
  25. package/dist/esm/pseudo/built.d.ts.map +1 -0
  26. package/dist/esm/pseudo/built.js +16 -0
  27. package/dist/esm/pseudo/built.js.map +1 -0
  28. package/dist/esm/pseudo/confused.d.ts +4 -2
  29. package/dist/esm/pseudo/confused.d.ts.map +1 -1
  30. package/dist/esm/pseudo/confused.js +15 -2
  31. package/dist/esm/pseudo/confused.js.map +1 -1
  32. package/dist/esm/pseudo/cve.d.ts +2 -1
  33. package/dist/esm/pseudo/cve.d.ts.map +1 -1
  34. package/dist/esm/pseudo/cve.js +2 -2
  35. package/dist/esm/pseudo/cve.js.map +1 -1
  36. package/dist/esm/pseudo/cwe.d.ts +2 -1
  37. package/dist/esm/pseudo/cwe.d.ts.map +1 -1
  38. package/dist/esm/pseudo/cwe.js +2 -2
  39. package/dist/esm/pseudo/cwe.js.map +1 -1
  40. package/dist/esm/pseudo/dev.d.ts +6 -0
  41. package/dist/esm/pseudo/dev.d.ts.map +1 -0
  42. package/dist/esm/pseudo/dev.js +15 -0
  43. package/dist/esm/pseudo/dev.js.map +1 -0
  44. package/dist/esm/pseudo/empty.d.ts +7 -0
  45. package/dist/esm/pseudo/empty.d.ts.map +1 -0
  46. package/dist/esm/pseudo/empty.js +14 -0
  47. package/dist/esm/pseudo/empty.js.map +1 -0
  48. package/dist/esm/pseudo/helpers.d.ts +13 -1
  49. package/dist/esm/pseudo/helpers.d.ts.map +1 -1
  50. package/dist/esm/pseudo/helpers.js +27 -0
  51. package/dist/esm/pseudo/helpers.js.map +1 -1
  52. package/dist/esm/pseudo/host.d.ts +20 -0
  53. package/dist/esm/pseudo/host.d.ts.map +1 -0
  54. package/dist/esm/pseudo/host.js +80 -0
  55. package/dist/esm/pseudo/host.js.map +1 -0
  56. package/dist/esm/pseudo/license.d.ts +2 -1
  57. package/dist/esm/pseudo/license.d.ts.map +1 -1
  58. package/dist/esm/pseudo/license.js +19 -2
  59. package/dist/esm/pseudo/license.js.map +1 -1
  60. package/dist/esm/pseudo/link.d.ts +9 -0
  61. package/dist/esm/pseudo/link.d.ts.map +1 -0
  62. package/dist/esm/pseudo/link.js +25 -0
  63. package/dist/esm/pseudo/link.js.map +1 -0
  64. package/dist/esm/pseudo/malware.d.ts +13 -1
  65. package/dist/esm/pseudo/malware.d.ts.map +1 -1
  66. package/dist/esm/pseudo/malware.js +140 -10
  67. package/dist/esm/pseudo/malware.js.map +1 -1
  68. package/dist/esm/pseudo/missing.d.ts +8 -0
  69. package/dist/esm/pseudo/missing.d.ts.map +1 -0
  70. package/dist/esm/pseudo/missing.js +15 -0
  71. package/dist/esm/pseudo/missing.js.map +1 -0
  72. package/dist/esm/pseudo/optional.d.ts +6 -0
  73. package/dist/esm/pseudo/optional.d.ts.map +1 -0
  74. package/dist/esm/pseudo/optional.js +15 -0
  75. package/dist/esm/pseudo/optional.js.map +1 -0
  76. package/dist/esm/pseudo/outdated.d.ts +4 -4
  77. package/dist/esm/pseudo/outdated.d.ts.map +1 -1
  78. package/dist/esm/pseudo/outdated.js +44 -33
  79. package/dist/esm/pseudo/outdated.js.map +1 -1
  80. package/dist/esm/pseudo/overridden.d.ts +8 -0
  81. package/dist/esm/pseudo/overridden.d.ts.map +1 -0
  82. package/dist/esm/pseudo/overridden.js +17 -0
  83. package/dist/esm/pseudo/overridden.js.map +1 -0
  84. package/dist/esm/pseudo/path.d.ts +19 -0
  85. package/dist/esm/pseudo/path.d.ts.map +1 -0
  86. package/dist/esm/pseudo/path.js +113 -0
  87. package/dist/esm/pseudo/path.js.map +1 -0
  88. package/dist/esm/pseudo/peer.d.ts +6 -0
  89. package/dist/esm/pseudo/peer.d.ts.map +1 -0
  90. package/dist/esm/pseudo/peer.js +15 -0
  91. package/dist/esm/pseudo/peer.js.map +1 -0
  92. package/dist/esm/pseudo/prerelease.d.ts +18 -0
  93. package/dist/esm/pseudo/prerelease.d.ts.map +1 -0
  94. package/dist/esm/pseudo/prerelease.js +41 -0
  95. package/dist/esm/pseudo/prerelease.js.map +1 -0
  96. package/dist/esm/pseudo/private.d.ts +7 -0
  97. package/dist/esm/pseudo/private.d.ts.map +1 -0
  98. package/dist/esm/pseudo/private.js +16 -0
  99. package/dist/esm/pseudo/private.js.map +1 -0
  100. package/dist/esm/pseudo/prod.d.ts +6 -0
  101. package/dist/esm/pseudo/prod.d.ts.map +1 -0
  102. package/dist/esm/pseudo/prod.js +15 -0
  103. package/dist/esm/pseudo/prod.js.map +1 -0
  104. package/dist/esm/pseudo/published.d.ts +40 -0
  105. package/dist/esm/pseudo/published.d.ts.map +1 -0
  106. package/dist/esm/pseudo/published.js +180 -0
  107. package/dist/esm/pseudo/published.js.map +1 -0
  108. package/dist/esm/pseudo/root.d.ts +7 -0
  109. package/dist/esm/pseudo/root.d.ts.map +1 -0
  110. package/dist/esm/pseudo/root.js +18 -0
  111. package/dist/esm/pseudo/root.js.map +1 -0
  112. package/dist/esm/pseudo/scanned.d.ts +4 -2
  113. package/dist/esm/pseudo/scanned.d.ts.map +1 -1
  114. package/dist/esm/pseudo/scanned.js +10 -5
  115. package/dist/esm/pseudo/scanned.js.map +1 -1
  116. package/dist/esm/pseudo/score.d.ts +16 -0
  117. package/dist/esm/pseudo/score.d.ts.map +1 -0
  118. package/dist/esm/pseudo/score.js +133 -0
  119. package/dist/esm/pseudo/score.js.map +1 -0
  120. package/dist/esm/pseudo/scripts.d.ts +7 -4
  121. package/dist/esm/pseudo/scripts.d.ts.map +1 -1
  122. package/dist/esm/pseudo/scripts.js +41 -3
  123. package/dist/esm/pseudo/scripts.js.map +1 -1
  124. package/dist/esm/pseudo/semver.d.ts +2 -1
  125. package/dist/esm/pseudo/semver.d.ts.map +1 -1
  126. package/dist/esm/pseudo/semver.js +11 -24
  127. package/dist/esm/pseudo/semver.js.map +1 -1
  128. package/dist/esm/pseudo/severity.d.ts +4 -1
  129. package/dist/esm/pseudo/severity.d.ts.map +1 -1
  130. package/dist/esm/pseudo/severity.js +111 -8
  131. package/dist/esm/pseudo/severity.js.map +1 -1
  132. package/dist/esm/pseudo/spec.d.ts +17 -0
  133. package/dist/esm/pseudo/spec.d.ts.map +1 -0
  134. package/dist/esm/pseudo/spec.js +102 -0
  135. package/dist/esm/pseudo/spec.js.map +1 -0
  136. package/dist/esm/pseudo/squat.d.ts +4 -1
  137. package/dist/esm/pseudo/squat.d.ts.map +1 -1
  138. package/dist/esm/pseudo/squat.js +127 -9
  139. package/dist/esm/pseudo/squat.js.map +1 -1
  140. package/dist/esm/pseudo/type.d.ts +8 -0
  141. package/dist/esm/pseudo/type.d.ts.map +1 -0
  142. package/dist/esm/pseudo/type.js +22 -0
  143. package/dist/esm/pseudo/type.js.map +1 -0
  144. package/dist/esm/pseudo/workspace.d.ts +6 -0
  145. package/dist/esm/pseudo/workspace.d.ts.map +1 -0
  146. package/dist/esm/pseudo/workspace.js +20 -0
  147. package/dist/esm/pseudo/workspace.js.map +1 -0
  148. package/dist/esm/pseudo.d.ts.map +1 -1
  149. package/dist/esm/pseudo.js +81 -105
  150. package/dist/esm/pseudo.js.map +1 -1
  151. package/dist/esm/types.d.ts +97 -27
  152. package/dist/esm/types.d.ts.map +1 -1
  153. package/dist/esm/types.js +1 -106
  154. package/dist/esm/types.js.map +1 -1
  155. package/package.json +20 -16
  156. package/dist/esm/class.d.ts +0 -6
  157. package/dist/esm/class.d.ts.map +0 -1
  158. package/dist/esm/class.js +0 -131
  159. package/dist/esm/class.js.map +0 -1
package/dist/esm/index.js CHANGED
@@ -1,18 +1,31 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import postcssSelectorParser from 'postcss-selector-parser';
2
+ import { joinDepIDTuple } from '@vltpkg/dep-id/browser';
3
+ import { parse, isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, isPseudoNode, isIdentifierNode, isAttributeNode, } from '@vltpkg/dss-parser';
3
4
  import { attribute } from "./attribute.js";
4
- import { classFn } from "./class.js";
5
5
  import { combinator } from "./combinator.js";
6
6
  import { id } from "./id.js";
7
7
  import { pseudo } from "./pseudo.js";
8
- import { isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, } from "./types.js";
9
8
  export * from "./types.js";
10
9
  const noopFn = async (state) => state;
11
10
  const selectors = {
12
11
  attribute,
13
- class: classFn,
12
+ /* c8 ignore start */
13
+ class: async (state) => {
14
+ throw error('Unsupported selector', { found: state.current });
15
+ },
16
+ /* c8 ignore end */
14
17
  combinator,
15
- comment: noopFn,
18
+ comment: async (state) => {
19
+ if (state.current.value && !state.comment) {
20
+ const commentValue = state.current.value;
21
+ const cleanComment = commentValue
22
+ .replace(/^\/\*/, '')
23
+ .replace(/\*\/$/, '')
24
+ .trim();
25
+ state.comment = cleanComment;
26
+ }
27
+ return state;
28
+ },
16
29
  id,
17
30
  nesting: noopFn,
18
31
  pseudo,
@@ -82,6 +95,7 @@ const securitySelectors = new Set([
82
95
  ':abandoned',
83
96
  ':confused',
84
97
  ':cve',
98
+ ':cwe',
85
99
  ':debug',
86
100
  ':deprecated',
87
101
  ':dynamic',
@@ -96,7 +110,7 @@ const securitySelectors = new Set([
96
110
  ':network',
97
111
  ':obfuscated',
98
112
  ':scanned',
99
- ':scripts',
113
+ ':score',
100
114
  ':sev',
101
115
  ':severity',
102
116
  ':shell',
@@ -111,11 +125,26 @@ const securitySelectors = new Set([
111
125
  ':unpopular',
112
126
  ':unstable',
113
127
  ]);
128
+ const setMethodToJSON = (node) => {
129
+ const { toJSON } = node;
130
+ const insights = node.insights;
131
+ node.toJSON = () => ({
132
+ ...toJSON.call(node),
133
+ insights,
134
+ });
135
+ };
136
+ /**
137
+ * The Query class is used to search the graph for nodes and edges
138
+ * using the Dependency Selector Syntax (DSS).
139
+ */
114
140
  export class Query {
115
141
  #cache;
116
- #graph;
117
- #specOptions;
142
+ #edges;
143
+ #nodes;
144
+ #importers;
145
+ #retries;
118
146
  #securityArchive;
147
+ #hostContexts;
119
148
  /**
120
149
  * Helper method to determine if a given query string is using any of
121
150
  * the known security selectors. This is useful so that operations can
@@ -129,34 +158,161 @@ export class Query {
129
158
  }
130
159
  return false;
131
160
  }
132
- constructor({ graph, specOptions, securityArchive }) {
161
+ /**
162
+ * Sorts an array of QueryResponse objects by specificity. Objects with
163
+ * higher idCounter values come first, if idCounter values are equal,
164
+ * then objects with higher commonCounter values come first. Otherwise,
165
+ * the original order is preserved.
166
+ */
167
+ static specificitySort(responses) {
168
+ return [...responses].sort((a, b) => {
169
+ // First compare by idCounter (higher comes first)
170
+ if (a.specificity.idCounter !== b.specificity.idCounter) {
171
+ return b.specificity.idCounter - a.specificity.idCounter;
172
+ }
173
+ // If idCounter values are equal, compare by commonCounter
174
+ if (a.specificity.commonCounter !== b.specificity.commonCounter) {
175
+ return (b.specificity.commonCounter - a.specificity.commonCounter);
176
+ }
177
+ // If both counters are equal, preserve original order
178
+ return 0;
179
+ });
180
+ }
181
+ constructor({ edges, nodes, importers, retries, securityArchive, hostContexts, }) {
133
182
  this.#cache = new Map();
134
- this.#graph = graph;
135
- this.#specOptions = specOptions;
183
+ this.#edges = edges;
184
+ this.#nodes = nodes;
185
+ this.#importers = importers;
186
+ this.#retries = retries ?? 3;
136
187
  this.#securityArchive = securityArchive;
188
+ this.#hostContexts = hostContexts;
189
+ }
190
+ #getQueryResponseEdges(_edges) {
191
+ return Array.from(_edges);
192
+ }
193
+ #getQueryResponseNodes(_nodes) {
194
+ const nodes = Array.from(_nodes);
195
+ for (const node of nodes) {
196
+ const securityArchiveEntry = this.#securityArchive?.get(node.id);
197
+ // if a security archive entry is not found then the insights object
198
+ // should just be empty with scanned=false
199
+ if (!securityArchiveEntry) {
200
+ node.insights = {
201
+ scanned: false,
202
+ };
203
+ setMethodToJSON(node);
204
+ continue;
205
+ }
206
+ // if a security archive entry is found then we can populate the insights
207
+ node.insights = {
208
+ scanned: true,
209
+ score: securityArchiveEntry.score,
210
+ abandoned: securityArchiveEntry.alerts.some(i => i.type === 'missingAuthor'),
211
+ confused: securityArchiveEntry.alerts.some(i => i.type === 'manifestConfusion'),
212
+ cve: securityArchiveEntry.alerts
213
+ .map(i => i.props?.cveId)
214
+ .filter(i => i !== undefined),
215
+ cwe: Array.from(new Set(securityArchiveEntry.alerts
216
+ .filter(i => i.props?.cveId)
217
+ .flatMap(i => i.props?.cwes?.map(j => j.id)))),
218
+ debug: securityArchiveEntry.alerts.some(i => i.type === 'debugAccess'),
219
+ deprecated: securityArchiveEntry.alerts.some(i => i.type === 'deprecated'),
220
+ dynamic: securityArchiveEntry.alerts.some(i => i.type === 'dynamicRequire'),
221
+ entropic: securityArchiveEntry.alerts.some(i => i.type === 'highEntropyStrings'),
222
+ env: securityArchiveEntry.alerts.some(i => i.type === 'envVars'),
223
+ eval: securityArchiveEntry.alerts.some(i => i.type === 'usesEval'),
224
+ fs: securityArchiveEntry.alerts.some(i => i.type === 'filesystemAccess'),
225
+ license: {
226
+ unlicensed: securityArchiveEntry.alerts.some(i => i.type === 'explicitlyUnlicensedItem'),
227
+ misc: securityArchiveEntry.alerts.some(i => i.type === 'miscLicenseIssues'),
228
+ restricted: securityArchiveEntry.alerts.some(i => i.type === 'nonpermissiveLicense'),
229
+ ambiguous: securityArchiveEntry.alerts.some(i => i.type === 'ambiguousClassifier'),
230
+ copyleft: securityArchiveEntry.alerts.some(i => i.type === 'copyleftLicense'),
231
+ unknown: securityArchiveEntry.alerts.some(i => i.type === 'unidentifiedLicense'),
232
+ none: securityArchiveEntry.alerts.some(i => i.type === 'noLicenseFound'),
233
+ exception: securityArchiveEntry.alerts.some(i => i.type === 'licenseException'),
234
+ },
235
+ malware: {
236
+ low: securityArchiveEntry.alerts.some(i => i.type === 'gptAnomaly'),
237
+ medium: securityArchiveEntry.alerts.some(i => i.type === 'gptSecurity'),
238
+ high: securityArchiveEntry.alerts.some(i => i.type === 'gptMalware'),
239
+ critical: securityArchiveEntry.alerts.some(i => i.type === 'malware'),
240
+ },
241
+ minified: securityArchiveEntry.alerts.some(i => i.type === 'minifiedFile'),
242
+ native: securityArchiveEntry.alerts.some(i => i.type === 'hasNativeCode'),
243
+ network: securityArchiveEntry.alerts.some(i => i.type === 'networkAccess'),
244
+ obfuscated: securityArchiveEntry.alerts.some(i => i.type === 'obfuscatedFile'),
245
+ scripts: securityArchiveEntry.alerts.some(i => i.type === 'installScripts'),
246
+ severity: {
247
+ low: securityArchiveEntry.alerts.some(i => i.type === 'mildCVE'),
248
+ medium: securityArchiveEntry.alerts.some(i => i.type === 'potentialVulnerability'),
249
+ high: securityArchiveEntry.alerts.some(i => i.type === 'cve'),
250
+ critical: securityArchiveEntry.alerts.some(i => i.type === 'criticalCVE'),
251
+ },
252
+ shell: securityArchiveEntry.alerts.some(i => i.type === 'shellAccess'),
253
+ shrinkwrap: securityArchiveEntry.alerts.some(i => i.type === 'shrinkwrap'),
254
+ squat: {
255
+ medium: securityArchiveEntry.alerts.some(i => i.type === 'gptDidYouMean'),
256
+ critical: securityArchiveEntry.alerts.some(i => i.type === 'didYouMean'),
257
+ },
258
+ suspicious: securityArchiveEntry.alerts.some(i => i.type === 'suspiciousStarActivity'),
259
+ tracker: securityArchiveEntry.alerts.some(i => i.type === 'telemetry'),
260
+ trivial: securityArchiveEntry.alerts.some(i => i.type === 'trivialPackage'),
261
+ undesirable: securityArchiveEntry.alerts.some(i => i.type === 'troll'),
262
+ unknown: securityArchiveEntry.alerts.some(i => i.type === 'newAuthor'),
263
+ unmaintained: securityArchiveEntry.alerts.some(i => i.type === 'unmaintained'),
264
+ unpopular: securityArchiveEntry.alerts.some(i => i.type === 'unpopularPackage'),
265
+ unstable: securityArchiveEntry.alerts.some(i => i.type === 'unstableOwnership'),
266
+ };
267
+ setMethodToJSON(node);
268
+ }
269
+ return nodes;
137
270
  }
138
271
  /**
139
272
  * Search the graph for nodes and edges that match the given query.
140
273
  */
141
- async search(query, signal) {
274
+ async search(query, { signal, scopeIDs = [joinDepIDTuple(['file', '.'])], }) {
142
275
  if (!query)
143
- return { edges: [], nodes: [] };
276
+ return {
277
+ edges: [],
278
+ nodes: [],
279
+ importers: [],
280
+ comment: '',
281
+ specificity: { idCounter: 0, commonCounter: 0 },
282
+ };
144
283
  const cachedResult = this.#cache.get(query);
145
284
  if (cachedResult) {
146
285
  return cachedResult;
147
286
  }
148
- const nodes = new Set(Array.from(this.#graph.nodes.values()));
149
- const edges = new Set(Array.from(this.#graph.edges));
287
+ const nodes = this.#nodes;
288
+ const edges = this.#edges;
289
+ const importers = this.#importers;
290
+ // includes virtual workspace edges in the searched edges
291
+ for (const importer of importers) {
292
+ if (!importer.workspaces)
293
+ continue;
294
+ for (const edge of importer.workspaces.values()) {
295
+ edges.add(edge);
296
+ }
297
+ }
298
+ // parse the query string into AST
299
+ const current = parse(query);
300
+ // set loose mode for the entire parse in case there are multiple selectors
301
+ // so that using invalid pseudo selectors or other query language parser
302
+ // errors won't throw an error,
303
+ // e.g: `:root > *, #a, :foo` still returns results for `:root > ` and `#a`
304
+ // while :foo is ignored
305
+ const loose = asPostcssNodeWithChildren(current).nodes.length > 1;
150
306
  // builds initial state and walks over it,
151
307
  // retrieving the collected result
152
- const { collect } = await walk({
308
+ const { collect, comment, importers: stateResultImporters, specificity, } = await walk({
153
309
  cancellable: async () => {
154
310
  await new Promise(resolve => {
155
311
  setTimeout(resolve, 0);
156
312
  });
157
- signal?.throwIfAborted();
313
+ signal.throwIfAborted();
158
314
  },
159
- current: postcssSelectorParser().astSync(query),
315
+ current,
160
316
  initial: {
161
317
  nodes: new Set(nodes),
162
318
  edges: new Set(edges),
@@ -165,18 +321,88 @@ export class Query {
165
321
  nodes: new Set(),
166
322
  edges: new Set(),
167
323
  },
324
+ comment: '',
325
+ loose,
326
+ importers,
168
327
  partial: { nodes, edges },
328
+ retries: this.#retries,
169
329
  signal,
170
330
  securityArchive: this.#securityArchive,
171
- specOptions: this.#specOptions,
331
+ scopeIDs,
172
332
  walk,
333
+ specificity: { idCounter: 0, commonCounter: 0 },
334
+ hostContexts: this.#hostContexts,
173
335
  });
174
336
  const res = {
175
- edges: Array.from(collect.edges),
176
- nodes: Array.from(collect.nodes),
337
+ edges: this.#getQueryResponseEdges(collect.edges),
338
+ nodes: this.#getQueryResponseNodes(collect.nodes),
339
+ importers: this.#getQueryResponseNodes(stateResultImporters),
340
+ comment,
341
+ specificity,
177
342
  };
178
343
  this.#cache.set(query, res);
179
344
  return res;
180
345
  }
346
+ /**
347
+ * Parses a query string in order to retrieve an array of tokens.
348
+ */
349
+ static getQueryTokens(query) {
350
+ if (!query)
351
+ return [];
352
+ const tokens = [];
353
+ const ast = (q) => {
354
+ try {
355
+ return parse(q);
356
+ }
357
+ catch (_e) {
358
+ return ast(q.slice(0, -1));
359
+ }
360
+ };
361
+ const processNode = (node) => {
362
+ for (const key of selectorsMap.keys()) {
363
+ if (node.type === key && node.type !== 'root') {
364
+ let token = `${node.spaces.before}${node.value}${node.spaces.after}`;
365
+ if (isIdentifierNode(node)) {
366
+ token = `${node.spaces.before}#${node.value}${node.spaces.after}`;
367
+ }
368
+ else if (isSelectorNode(node)) {
369
+ token = `${node.spaces.before},${node.spaces.after}`;
370
+ }
371
+ else if (isAttributeNode(node)) {
372
+ token = String(node.source?.start?.column &&
373
+ node.source.end?.column &&
374
+ `${node.spaces.before}${query.slice(node.source.start.column - 1, node.source.end.column)}${node.spaces.after}`);
375
+ }
376
+ if (isPostcssNodeWithChildren(node) &&
377
+ isPseudoNode(node) &&
378
+ node.nodes.length) {
379
+ token = String(token.split('(')[0]);
380
+ token += '(';
381
+ }
382
+ if (!isSelectorNode(node) ||
383
+ node.parent?.nodes.indexOf(node) !== 0) {
384
+ tokens.push({
385
+ ...node,
386
+ token,
387
+ });
388
+ }
389
+ }
390
+ }
391
+ if (isPostcssNodeWithChildren(node)) {
392
+ for (const child of node.nodes) {
393
+ processNode(child);
394
+ }
395
+ if (isPseudoNode(node) && node.nodes.length) {
396
+ tokens.push({
397
+ ...node,
398
+ token: ')' + node.spaces.after,
399
+ type: 'pseudo',
400
+ });
401
+ }
402
+ }
403
+ };
404
+ processNode(ast(query));
405
+ return tokens;
406
+ }
181
407
  }
182
408
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport type { EdgeLike, GraphLike, NodeLike } from '@vltpkg/graph'\nimport type { SpecOptions } from '@vltpkg/spec/browser'\nimport type { SecurityArchiveLike } from '@vltpkg/security-archive'\nimport postcssSelectorParser from 'postcss-selector-parser'\nimport { attribute } from './attribute.ts'\nimport { classFn } from './class.ts'\nimport { combinator } from './combinator.ts'\nimport { id } from './id.ts'\nimport { pseudo } from './pseudo.ts'\nimport {\n isPostcssNodeWithChildren,\n asPostcssNodeWithChildren,\n isSelectorNode,\n} from './types.ts'\nimport type {\n PostcssNodeWithChildren,\n ParserState,\n ParserFn,\n QueryResponse,\n} from './types.ts'\n\nexport * from './types.ts'\n\nconst noopFn = async (state: ParserState) => state\n\nconst selectors = {\n attribute,\n class: classFn,\n combinator,\n comment: noopFn,\n id,\n nesting: noopFn,\n pseudo,\n root: noopFn,\n selector: async (state: ParserState) => {\n state.partial.nodes = new Set(state.initial.nodes)\n state.partial.edges = new Set(state.initial.edges)\n return state\n },\n string: async (state: ParserState) => {\n throw error('Unsupported selector', { found: state.current })\n },\n tag: async (state: ParserState) => {\n if (state.current.value !== '{' && state.current.value !== '}') {\n throw error('Unsupported selector', { found: state.current })\n }\n return state\n },\n universal: noopFn,\n}\nconst selectorsMap = new Map<string, ParserFn>(\n Object.entries(selectors),\n)\n\nexport const walk = async (\n state: ParserState,\n): Promise<ParserState> => {\n await state.cancellable()\n\n const parserFn = selectorsMap.get(state.current.type)\n\n if (!parserFn) {\n if (state.loose) {\n return state\n }\n\n throw error(\n `Missing parser for query node: ${state.current.type}`,\n {\n found: state.current,\n },\n )\n }\n state = await parserFn(state)\n\n // pseudo selectors handle their own sub selectors\n if (\n isPostcssNodeWithChildren(state.current) &&\n state.current.type !== 'pseudo'\n ) {\n const node: PostcssNodeWithChildren = asPostcssNodeWithChildren(\n state.current,\n )\n\n if (node.nodes.length) {\n for (let i = 0; i < node.nodes.length; i++) {\n const current = node.nodes[i]\n /* c8 ignore next -- impossible but TS doesn't know that */\n if (!current) continue\n\n const childState: ParserState = {\n ...state,\n current,\n next: node.nodes[i + 1],\n prev: node.nodes[i - 1],\n }\n state = await walk(childState)\n }\n }\n\n if (isSelectorNode(node)) {\n for (const edge of state.partial.edges) {\n state.collect.edges.add(edge)\n }\n for (const node of state.partial.nodes) {\n state.collect.nodes.add(node)\n }\n }\n }\n return state\n}\n\nexport type QueryOptions = {\n graph: GraphLike\n specOptions: SpecOptions\n securityArchive: SecurityArchiveLike | undefined\n}\n\n// A list of known security selectors that rely on\n// data from the security-archive in order to work\nconst securitySelectors = new Set([\n ':abandoned',\n ':confused',\n ':cve',\n ':debug',\n ':deprecated',\n ':dynamic',\n ':entropic',\n ':env',\n ':eval',\n ':fs',\n ':license',\n ':malware',\n ':minified',\n ':native',\n ':network',\n ':obfuscated',\n ':scanned',\n ':scripts',\n ':sev',\n ':severity',\n ':shell',\n ':shrinkwrap',\n ':squat',\n ':suspicious',\n ':tracker',\n ':trivial',\n ':undesirable',\n ':unknown',\n ':unmaintained',\n ':unpopular',\n ':unstable',\n])\n\nexport class Query {\n #cache: Map<string, QueryResponse>\n #graph: GraphLike\n #specOptions: SpecOptions\n #securityArchive: SecurityArchiveLike | undefined\n\n /**\n * Helper method to determine if a given query string is using any of\n * the known security selectors. This is useful so that operations can\n * skip hydrating the security archive if it's not needed.\n */\n static hasSecuritySelectors(query: string): boolean {\n for (const selector of securitySelectors) {\n if (query.includes(selector)) {\n return true\n }\n }\n return false\n }\n\n constructor({ graph, specOptions, securityArchive }: QueryOptions) {\n this.#cache = new Map()\n this.#graph = graph\n this.#specOptions = specOptions\n this.#securityArchive = securityArchive\n }\n\n /**\n * Search the graph for nodes and edges that match the given query.\n */\n async search(\n query: string,\n signal?: AbortSignal,\n ): Promise<QueryResponse> {\n if (!query) return { edges: [], nodes: [] }\n\n const cachedResult = this.#cache.get(query)\n if (cachedResult) {\n return cachedResult\n }\n\n const nodes = new Set<NodeLike>(\n Array.from(this.#graph.nodes.values()),\n )\n const edges = new Set<EdgeLike>(Array.from(this.#graph.edges))\n\n // builds initial state and walks over it,\n // retrieving the collected result\n const { collect } = await walk({\n cancellable: async () => {\n await new Promise(resolve => {\n setTimeout(resolve, 0)\n })\n signal?.throwIfAborted()\n },\n current: postcssSelectorParser().astSync(query),\n initial: {\n nodes: new Set(nodes),\n edges: new Set(edges),\n },\n collect: {\n nodes: new Set<NodeLike>(),\n edges: new Set<EdgeLike>(),\n },\n partial: { nodes, edges },\n signal,\n securityArchive: this.#securityArchive,\n specOptions: this.#specOptions,\n walk,\n })\n\n const res: QueryResponse = {\n edges: Array.from(collect.edges),\n nodes: Array.from(collect.nodes),\n }\n this.#cache.set(query, res)\n return res\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { joinDepIDTuple } from '@vltpkg/dep-id/browser'\nimport {\n parse,\n isPostcssNodeWithChildren,\n asPostcssNodeWithChildren,\n isSelectorNode,\n isPseudoNode,\n isIdentifierNode,\n isAttributeNode,\n} from '@vltpkg/dss-parser'\nimport { attribute } from './attribute.ts'\nimport { combinator } from './combinator.ts'\nimport { id } from './id.ts'\nimport { pseudo } from './pseudo.ts'\nimport type { EdgeLike, NodeLike } from '@vltpkg/types'\nimport type { SecurityArchiveLike } from '@vltpkg/security-archive'\nimport type {\n PostcssNode,\n PostcssNodeWithChildren,\n} from '@vltpkg/dss-parser'\nimport type {\n HostContextsMap,\n ParsedSelectorToken,\n ParserState,\n ParserFn,\n QueryResponse,\n QueryResponseNode,\n QueryResponseEdge,\n} from './types.ts'\nimport type { DepID } from '@vltpkg/dep-id'\n\nexport * from './types.ts'\n\nexport type SearchOptions = {\n signal: AbortSignal\n scopeIDs?: DepID[]\n}\n\nconst noopFn = async (state: ParserState) => state\n\nconst selectors = {\n attribute,\n /* c8 ignore start */\n class: async (state: ParserState) => {\n throw error('Unsupported selector', { found: state.current })\n },\n /* c8 ignore end */\n combinator,\n comment: async (state: ParserState) => {\n if (state.current.value && !state.comment) {\n const commentValue = state.current.value\n const cleanComment = commentValue\n .replace(/^\\/\\*/, '')\n .replace(/\\*\\/$/, '')\n .trim()\n state.comment = cleanComment\n }\n return state\n },\n id,\n nesting: noopFn,\n pseudo,\n root: noopFn,\n selector: async (state: ParserState) => {\n state.partial.nodes = new Set(state.initial.nodes)\n state.partial.edges = new Set(state.initial.edges)\n return state\n },\n string: async (state: ParserState) => {\n throw error('Unsupported selector', { found: state.current })\n },\n tag: async (state: ParserState) => {\n if (state.current.value !== '{' && state.current.value !== '}') {\n throw error('Unsupported selector', { found: state.current })\n }\n return state\n },\n universal: noopFn,\n}\nconst selectorsMap = new Map<string, ParserFn>(\n Object.entries(selectors),\n)\n\nexport const walk = async (\n state: ParserState,\n): Promise<ParserState> => {\n await state.cancellable()\n\n const parserFn = selectorsMap.get(state.current.type)\n\n if (!parserFn) {\n if (state.loose) {\n return state\n }\n\n throw error(\n `Missing parser for query node: ${state.current.type}`,\n {\n found: state.current,\n },\n )\n }\n state = await parserFn(state)\n\n // pseudo selectors handle their own sub selectors\n if (\n isPostcssNodeWithChildren(state.current) &&\n state.current.type !== 'pseudo'\n ) {\n const node: PostcssNodeWithChildren = asPostcssNodeWithChildren(\n state.current,\n )\n\n if (node.nodes.length) {\n for (let i = 0; i < node.nodes.length; i++) {\n const current = node.nodes[i]\n /* c8 ignore next -- impossible but TS doesn't know that */\n if (!current) continue\n\n const childState: ParserState = {\n ...state,\n current,\n next: node.nodes[i + 1],\n prev: node.nodes[i - 1],\n }\n state = await walk(childState)\n }\n }\n\n if (isSelectorNode(node)) {\n for (const edge of state.partial.edges) {\n state.collect.edges.add(edge)\n }\n for (const node of state.partial.nodes) {\n state.collect.nodes.add(node)\n }\n }\n }\n return state\n}\n\nexport type QueryOptions = {\n edges: Set<EdgeLike>\n nodes: Set<NodeLike>\n importers: Set<NodeLike>\n retries?: number\n securityArchive: SecurityArchiveLike | undefined\n hostContexts?: HostContextsMap\n}\n\n// A list of known security selectors that rely on\n// data from the security-archive in order to work\nconst securitySelectors = new Set([\n ':abandoned',\n ':confused',\n ':cve',\n ':cwe',\n ':debug',\n ':deprecated',\n ':dynamic',\n ':entropic',\n ':env',\n ':eval',\n ':fs',\n ':license',\n ':malware',\n ':minified',\n ':native',\n ':network',\n ':obfuscated',\n ':scanned',\n ':score',\n ':sev',\n ':severity',\n ':shell',\n ':shrinkwrap',\n ':squat',\n ':suspicious',\n ':tracker',\n ':trivial',\n ':undesirable',\n ':unknown',\n ':unmaintained',\n ':unpopular',\n ':unstable',\n])\n\nconst setMethodToJSON = (node: QueryResponseNode) => {\n const { toJSON } = node\n const insights = node.insights\n node.toJSON = () => ({\n ...toJSON.call(node),\n insights,\n })\n}\n\n/**\n * The Query class is used to search the graph for nodes and edges\n * using the Dependency Selector Syntax (DSS).\n */\nexport class Query {\n #cache: Map<string, QueryResponse>\n #edges: Set<EdgeLike>\n #nodes: Set<NodeLike>\n #importers: Set<NodeLike>\n #retries: number\n #securityArchive: SecurityArchiveLike | undefined\n #hostContexts: HostContextsMap | undefined\n\n /**\n * Helper method to determine if a given query string is using any of\n * the known security selectors. This is useful so that operations can\n * skip hydrating the security archive if it's not needed.\n */\n static hasSecuritySelectors(query: string): boolean {\n for (const selector of securitySelectors) {\n if (query.includes(selector)) {\n return true\n }\n }\n return false\n }\n\n /**\n * Sorts an array of QueryResponse objects by specificity. Objects with\n * higher idCounter values come first, if idCounter values are equal,\n * then objects with higher commonCounter values come first. Otherwise,\n * the original order is preserved.\n */\n static specificitySort(\n responses: QueryResponse[],\n ): QueryResponse[] {\n return [...responses].sort((a, b) => {\n // First compare by idCounter (higher comes first)\n if (a.specificity.idCounter !== b.specificity.idCounter) {\n return b.specificity.idCounter - a.specificity.idCounter\n }\n\n // If idCounter values are equal, compare by commonCounter\n if (\n a.specificity.commonCounter !== b.specificity.commonCounter\n ) {\n return (\n b.specificity.commonCounter - a.specificity.commonCounter\n )\n }\n\n // If both counters are equal, preserve original order\n return 0\n })\n }\n\n constructor({\n edges,\n nodes,\n importers,\n retries,\n securityArchive,\n hostContexts,\n }: QueryOptions) {\n this.#cache = new Map()\n this.#edges = edges\n this.#nodes = nodes\n this.#importers = importers\n this.#retries = retries ?? 3\n this.#securityArchive = securityArchive\n this.#hostContexts = hostContexts\n }\n\n #getQueryResponseEdges(_edges: Set<EdgeLike>): QueryResponseEdge[] {\n return Array.from(_edges) as QueryResponseEdge[]\n }\n\n #getQueryResponseNodes(_nodes: Set<NodeLike>): QueryResponseNode[] {\n const nodes = Array.from(_nodes) as QueryResponseNode[]\n for (const node of nodes) {\n const securityArchiveEntry = this.#securityArchive?.get(node.id)\n\n // if a security archive entry is not found then the insights object\n // should just be empty with scanned=false\n if (!securityArchiveEntry) {\n node.insights = {\n scanned: false,\n }\n\n setMethodToJSON(node)\n continue\n }\n\n // if a security archive entry is found then we can populate the insights\n node.insights = {\n scanned: true,\n score: securityArchiveEntry.score,\n abandoned: securityArchiveEntry.alerts.some(\n i => i.type === 'missingAuthor',\n ),\n confused: securityArchiveEntry.alerts.some(\n i => i.type === 'manifestConfusion',\n ),\n cve: securityArchiveEntry.alerts\n .map(i => i.props?.cveId)\n .filter(i => i !== undefined),\n cwe: Array.from(\n new Set(\n securityArchiveEntry.alerts\n .filter(i => i.props?.cveId)\n .flatMap(i => i.props?.cwes?.map(j => j.id)),\n ),\n ) as `CWE-${string}`[],\n debug: securityArchiveEntry.alerts.some(\n i => i.type === 'debugAccess',\n ),\n deprecated: securityArchiveEntry.alerts.some(\n i => i.type === 'deprecated',\n ),\n dynamic: securityArchiveEntry.alerts.some(\n i => i.type === 'dynamicRequire',\n ),\n entropic: securityArchiveEntry.alerts.some(\n i => i.type === 'highEntropyStrings',\n ),\n env: securityArchiveEntry.alerts.some(\n i => i.type === 'envVars',\n ),\n eval: securityArchiveEntry.alerts.some(\n i => i.type === 'usesEval',\n ),\n fs: securityArchiveEntry.alerts.some(\n i => i.type === 'filesystemAccess',\n ),\n license: {\n unlicensed: securityArchiveEntry.alerts.some(\n i => i.type === 'explicitlyUnlicensedItem',\n ),\n misc: securityArchiveEntry.alerts.some(\n i => i.type === 'miscLicenseIssues',\n ),\n restricted: securityArchiveEntry.alerts.some(\n i => i.type === 'nonpermissiveLicense',\n ),\n ambiguous: securityArchiveEntry.alerts.some(\n i => i.type === 'ambiguousClassifier',\n ),\n copyleft: securityArchiveEntry.alerts.some(\n i => i.type === 'copyleftLicense',\n ),\n unknown: securityArchiveEntry.alerts.some(\n i => i.type === 'unidentifiedLicense',\n ),\n none: securityArchiveEntry.alerts.some(\n i => i.type === 'noLicenseFound',\n ),\n exception: securityArchiveEntry.alerts.some(\n i => i.type === 'licenseException',\n ),\n },\n malware: {\n low: securityArchiveEntry.alerts.some(\n i => i.type === 'gptAnomaly',\n ),\n medium: securityArchiveEntry.alerts.some(\n i => i.type === 'gptSecurity',\n ),\n high: securityArchiveEntry.alerts.some(\n i => i.type === 'gptMalware',\n ),\n critical: securityArchiveEntry.alerts.some(\n i => i.type === 'malware',\n ),\n },\n minified: securityArchiveEntry.alerts.some(\n i => i.type === 'minifiedFile',\n ),\n native: securityArchiveEntry.alerts.some(\n i => i.type === 'hasNativeCode',\n ),\n network: securityArchiveEntry.alerts.some(\n i => i.type === 'networkAccess',\n ),\n obfuscated: securityArchiveEntry.alerts.some(\n i => i.type === 'obfuscatedFile',\n ),\n scripts: securityArchiveEntry.alerts.some(\n i => i.type === 'installScripts',\n ),\n severity: {\n low: securityArchiveEntry.alerts.some(\n i => i.type === 'mildCVE',\n ),\n medium: securityArchiveEntry.alerts.some(\n i => i.type === 'potentialVulnerability',\n ),\n high: securityArchiveEntry.alerts.some(\n i => i.type === 'cve',\n ),\n critical: securityArchiveEntry.alerts.some(\n i => i.type === 'criticalCVE',\n ),\n },\n shell: securityArchiveEntry.alerts.some(\n i => i.type === 'shellAccess',\n ),\n shrinkwrap: securityArchiveEntry.alerts.some(\n i => i.type === 'shrinkwrap',\n ),\n squat: {\n medium: securityArchiveEntry.alerts.some(\n i => i.type === 'gptDidYouMean',\n ),\n critical: securityArchiveEntry.alerts.some(\n i => i.type === 'didYouMean',\n ),\n },\n suspicious: securityArchiveEntry.alerts.some(\n i => i.type === 'suspiciousStarActivity',\n ),\n tracker: securityArchiveEntry.alerts.some(\n i => i.type === 'telemetry',\n ),\n trivial: securityArchiveEntry.alerts.some(\n i => i.type === 'trivialPackage',\n ),\n undesirable: securityArchiveEntry.alerts.some(\n i => i.type === 'troll',\n ),\n unknown: securityArchiveEntry.alerts.some(\n i => i.type === 'newAuthor',\n ),\n unmaintained: securityArchiveEntry.alerts.some(\n i => i.type === 'unmaintained',\n ),\n unpopular: securityArchiveEntry.alerts.some(\n i => i.type === 'unpopularPackage',\n ),\n unstable: securityArchiveEntry.alerts.some(\n i => i.type === 'unstableOwnership',\n ),\n }\n\n setMethodToJSON(node)\n }\n return nodes\n }\n\n /**\n * Search the graph for nodes and edges that match the given query.\n */\n async search(\n query: string,\n {\n signal,\n scopeIDs = [joinDepIDTuple(['file', '.'])],\n }: SearchOptions,\n ): Promise<QueryResponse> {\n if (!query)\n return {\n edges: [],\n nodes: [],\n importers: [],\n comment: '',\n specificity: { idCounter: 0, commonCounter: 0 },\n }\n\n const cachedResult = this.#cache.get(query)\n if (cachedResult) {\n return cachedResult\n }\n\n const nodes = this.#nodes\n const edges = this.#edges\n const importers = this.#importers\n\n // includes virtual workspace edges in the searched edges\n for (const importer of importers) {\n if (!importer.workspaces) continue\n for (const edge of importer.workspaces.values()) {\n edges.add(edge)\n }\n }\n\n // parse the query string into AST\n const current = parse(query)\n // set loose mode for the entire parse in case there are multiple selectors\n // so that using invalid pseudo selectors or other query language parser\n // errors won't throw an error,\n // e.g: `:root > *, #a, :foo` still returns results for `:root > ` and `#a`\n // while :foo is ignored\n const loose = asPostcssNodeWithChildren(current).nodes.length > 1\n // builds initial state and walks over it,\n // retrieving the collected result\n const {\n collect,\n comment,\n importers: stateResultImporters,\n specificity,\n } = await walk({\n cancellable: async () => {\n await new Promise(resolve => {\n setTimeout(resolve, 0)\n })\n signal.throwIfAborted()\n },\n current,\n initial: {\n nodes: new Set(nodes),\n edges: new Set(edges),\n },\n collect: {\n nodes: new Set<NodeLike>(),\n edges: new Set<EdgeLike>(),\n },\n comment: '',\n loose,\n importers,\n partial: { nodes, edges },\n retries: this.#retries,\n signal,\n securityArchive: this.#securityArchive,\n scopeIDs,\n walk,\n specificity: { idCounter: 0, commonCounter: 0 },\n hostContexts: this.#hostContexts,\n })\n\n const res: QueryResponse = {\n edges: this.#getQueryResponseEdges(collect.edges),\n nodes: this.#getQueryResponseNodes(collect.nodes),\n importers: this.#getQueryResponseNodes(stateResultImporters),\n comment,\n specificity,\n }\n this.#cache.set(query, res)\n return res\n }\n\n /**\n * Parses a query string in order to retrieve an array of tokens.\n */\n static getQueryTokens(query: string): ParsedSelectorToken[] {\n if (!query) return []\n\n const tokens: ParsedSelectorToken[] = []\n\n const ast = (q: string) => {\n try {\n return parse(q)\n } catch (_e) {\n return ast(q.slice(0, -1))\n }\n }\n\n const processNode = (node: PostcssNode) => {\n for (const key of selectorsMap.keys()) {\n if (node.type === key && node.type !== 'root') {\n let token = `${node.spaces.before}${node.value}${node.spaces.after}`\n\n if (isIdentifierNode(node)) {\n token = `${node.spaces.before}#${node.value}${node.spaces.after}`\n } else if (isSelectorNode(node)) {\n token = `${node.spaces.before},${node.spaces.after}`\n } else if (isAttributeNode(node)) {\n token = String(\n node.source?.start?.column &&\n node.source.end?.column &&\n `${node.spaces.before}${query.slice(node.source.start.column - 1, node.source.end.column)}${node.spaces.after}`,\n )\n }\n\n if (\n isPostcssNodeWithChildren(node) &&\n isPseudoNode(node) &&\n node.nodes.length\n ) {\n token = String(token.split('(')[0])\n token += '('\n }\n\n if (\n !isSelectorNode(node) ||\n node.parent?.nodes.indexOf(node) !== 0\n ) {\n tokens.push({\n ...node,\n token,\n } as ParsedSelectorToken)\n }\n }\n }\n if (isPostcssNodeWithChildren(node)) {\n for (const child of node.nodes) {\n processNode(child)\n }\n if (isPseudoNode(node) && node.nodes.length) {\n tokens.push({\n ...node,\n token: ')' + node.spaces.after,\n type: 'pseudo',\n } as ParsedSelectorToken)\n }\n }\n }\n\n processNode(ast(query))\n return tokens\n }\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { Root } from 'postcss-selector-parser';
2
+ /**
3
+ * Escapes forward slashes in specific patterns matching @scoped/name paths
4
+ * This will allow usage of unescaped forward slashes necessary for scoped
5
+ * package names in the id selector.
6
+ */
7
+ export declare const escapeScopedNamesSlashes: (query: string) => string;
8
+ export declare const escapeDots: (query: string) => string;
9
+ export declare const unescapeDots: (query: string) => string;
10
+ /**
11
+ * Parses a CSS selector string into an AST
12
+ * Handles escaping of forward slashes in specific patterns
13
+ */
14
+ export declare const parse: (query: string) => Root;
15
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAG3D;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,UAAW,MAAM,KAAG,MAItD,CAAA;AAEH,eAAO,MAAM,UAAU,UAAW,MAAM,KAAG,MACb,CAAA;AAE9B,eAAO,MAAM,YAAY,UAAW,MAAM,KAAG,MACf,CAAA;AAiB9B;;;GAGG;AACH,eAAO,MAAM,KAAK,UAAW,MAAM,KAAG,IA0ErC,CAAA"}
@@ -0,0 +1,93 @@
1
+ import postcssSelectorParser from 'postcss-selector-parser';
2
+ import { asSelectorNode, isCombinatorNode, isPseudoNode, isTagNode, } from '@vltpkg/dss-parser';
3
+ /**
4
+ * Escapes forward slashes in specific patterns matching @scoped/name paths
5
+ * This will allow usage of unescaped forward slashes necessary for scoped
6
+ * package names in the id selector.
7
+ */
8
+ export const escapeScopedNamesSlashes = (query) => query.replace(/(#@(\w|-|\.)+)\//gm, (_, scope) => `${scope}\\/`);
9
+ export const escapeDots = (query) => query.replaceAll('.', '\\.');
10
+ export const unescapeDots = (query) => query.replaceAll('\\.', '.');
11
+ const pseudoCleanUpNeeded = new Set([
12
+ ':published',
13
+ ':score',
14
+ ':malware',
15
+ ':severity',
16
+ ':sev',
17
+ ':squat',
18
+ ':semver',
19
+ ':v',
20
+ ':path',
21
+ ]);
22
+ const hasParamsToEscape = (node) => pseudoCleanUpNeeded.has(node.value);
23
+ /**
24
+ * Parses a CSS selector string into an AST
25
+ * Handles escaping of forward slashes in specific patterns
26
+ */
27
+ export const parse = (query) => {
28
+ const escapedQuery = escapeDots(escapeScopedNamesSlashes(query));
29
+ const transformAst = (root) => {
30
+ root.walk((node) => {
31
+ // clean up the escaped dots
32
+ if (node.value && typeof node.value === 'string') {
33
+ node.value = unescapeDots(node.value);
34
+ }
35
+ if (isPseudoNode(node) && hasParamsToEscape(node)) {
36
+ // these are pseudo nodes that should only take strings as
37
+ // parameters, so in this preparse step we clean up anything
38
+ // that was recognized as a postcss node and transform that
39
+ // into something that can be most likely parsed as a string
40
+ for (const n of node.nodes) {
41
+ // the parameters have a selector node that wraps them up
42
+ const selector = asSelectorNode(n);
43
+ selector.nodes.forEach((currentNode, index, arr) => {
44
+ // get the next node, we'll update it later
45
+ const nextNode = arr[index + 1];
46
+ // if the current node is a combinator node, we'll need to
47
+ // escape it, we do so by removing the node entirely and
48
+ // updating the contents of the next node with its value
49
+ if (isCombinatorNode(currentNode) &&
50
+ isTagNode(nextNode)) {
51
+ nextNode.value = `${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}${nextNode.value}`;
52
+ // make sure to also update the source position
53
+ // references, those are used by the syntax highlighter
54
+ if (nextNode.source?.start?.line &&
55
+ currentNode.source?.start?.line) {
56
+ nextNode.source.start.line =
57
+ currentNode.source.start.line;
58
+ }
59
+ if (nextNode.source?.start?.column &&
60
+ currentNode.source?.start?.column) {
61
+ nextNode.source.start.column =
62
+ currentNode.source.start.column;
63
+ }
64
+ // removes the current node from the selector node
65
+ arr.splice(index, 1);
66
+ }
67
+ });
68
+ // after removing combinator nodes, if we end up with multiple
69
+ // tags in the selector node, we need to smush them together
70
+ selector.nodes.reduce((acc, currentNode) => {
71
+ if (currentNode === acc)
72
+ return acc;
73
+ acc.value = `${acc.value}${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}`;
74
+ // make sure to also update the source position refs
75
+ if (currentNode.source?.end?.line &&
76
+ acc.source?.end?.line) {
77
+ acc.source.end.line = currentNode.source.end.line;
78
+ }
79
+ if (currentNode.source?.end?.column &&
80
+ acc.source?.end?.column) {
81
+ acc.source.end.column = currentNode.source.end.column;
82
+ }
83
+ return acc;
84
+ }, selector.first);
85
+ // the selector wrapper node should have a single node
86
+ selector.nodes.length = 1;
87
+ }
88
+ }
89
+ });
90
+ };
91
+ return postcssSelectorParser(transformAst).astSync(escapedQuery);
92
+ };
93
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"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","sourcesContent":["import postcssSelectorParser from 'postcss-selector-parser'\nimport {\n asSelectorNode,\n isCombinatorNode,\n isPseudoNode,\n isTagNode,\n} from '@vltpkg/dss-parser'\nimport type { Pseudo, Root } from 'postcss-selector-parser'\nimport type { PostcssNode } from '@vltpkg/dss-parser'\n\n/**\n * Escapes forward slashes in specific patterns matching @scoped/name paths\n * This will allow usage of unescaped forward slashes necessary for scoped\n * package names in the id selector.\n */\nexport const escapeScopedNamesSlashes = (query: string): string =>\n query.replace(\n /(#@(\\w|-|\\.)+)\\//gm,\n (_, scope: string) => `${scope}\\\\/`,\n )\n\nexport const escapeDots = (query: string): string =>\n query.replaceAll('.', '\\\\.')\n\nexport const unescapeDots = (query: string): string =>\n query.replaceAll('\\\\.', '.')\n\nconst pseudoCleanUpNeeded = new Set([\n ':published',\n ':score',\n ':malware',\n ':severity',\n ':sev',\n ':squat',\n ':semver',\n ':v',\n ':path',\n])\n\nconst hasParamsToEscape = (node: Pseudo) =>\n pseudoCleanUpNeeded.has(node.value)\n\n/**\n * Parses a CSS selector string into an AST\n * Handles escaping of forward slashes in specific patterns\n */\nexport const parse = (query: string): Root => {\n const escapedQuery = escapeDots(escapeScopedNamesSlashes(query))\n const transformAst = (root: Root) => {\n root.walk((node: PostcssNode) => {\n // clean up the escaped dots\n if (node.value && typeof node.value === 'string') {\n node.value = unescapeDots(node.value)\n }\n if (isPseudoNode(node) && hasParamsToEscape(node)) {\n // these are pseudo nodes that should only take strings as\n // parameters, so in this preparse step we clean up anything\n // that was recognized as a postcss node and transform that\n // into something that can be most likely parsed as a string\n for (const n of node.nodes) {\n // the parameters have a selector node that wraps them up\n const selector = asSelectorNode(n)\n selector.nodes.forEach((currentNode, index, arr) => {\n // get the next node, we'll update it later\n const nextNode = arr[index + 1]\n // if the current node is a combinator node, we'll need to\n // escape it, we do so by removing the node entirely and\n // updating the contents of the next node with its value\n if (\n isCombinatorNode(currentNode) &&\n isTagNode(nextNode)\n ) {\n nextNode.value = `${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}${nextNode.value}`\n // make sure to also update the source position\n // references, those are used by the syntax highlighter\n if (\n nextNode.source?.start?.line &&\n currentNode.source?.start?.line\n ) {\n nextNode.source.start.line =\n currentNode.source.start.line\n }\n if (\n nextNode.source?.start?.column &&\n currentNode.source?.start?.column\n ) {\n nextNode.source.start.column =\n currentNode.source.start.column\n }\n // removes the current node from the selector node\n arr.splice(index, 1)\n }\n })\n // after removing combinator nodes, if we end up with multiple\n // tags in the selector node, we need to smush them together\n selector.nodes.reduce((acc, currentNode) => {\n if (currentNode === acc) return acc\n acc.value = `${acc.value}${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}`\n // make sure to also update the source position refs\n if (\n currentNode.source?.end?.line &&\n acc.source?.end?.line\n ) {\n acc.source.end.line = currentNode.source.end.line\n }\n if (\n currentNode.source?.end?.column &&\n acc.source?.end?.column\n ) {\n acc.source.end.column = currentNode.source.end.column\n }\n return acc\n }, selector.first)\n // the selector wrapper node should have a single node\n selector.nodes.length = 1\n }\n }\n })\n }\n return postcssSelectorParser(transformAst).astSync(escapedQuery)\n}\n"]}
@@ -1,4 +1,5 @@
1
- import type { ParserState, PostcssNode } from '../types.ts';
1
+ import type { ParserState } from '../types.ts';
2
+ import type { PostcssNode } from '@vltpkg/dss-parser';
2
3
  export type AttrInternals = {
3
4
  attribute: string;
4
5
  insensitive: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"attr.d.ts","sourceRoot":"","sources":["../../../src/pseudo/attr.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAM3D,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,UAClB,WAAW,EAAE,KACnB,aAsBF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,UAAiB,WAAW,yBA8B5C,CAAA"}
1
+ {"version":3,"file":"attr.d.ts","sourceRoot":"","sources":["../../../src/pseudo/attr.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,UAClB,WAAW,EAAE,KACnB,aA0BF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,UAAiB,WAAW,yBA8B5C,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import { asAttributeNode, asPostcssNodeWithChildren, asTagNode, } from "../types.js";
2
+ import { asAttributeNode, asPostcssNodeWithChildren, asStringNode, asTagNode, isStringNode, } from '@vltpkg/dss-parser';
3
3
  import { attributeSelectorsMap, filterAttributes, } from "../attribute.js";
4
+ import { removeQuotes } from "./helpers.js";
4
5
  /**
5
6
  * Parses the internal / nested selectors of a `:attr` selector.
6
7
  */
@@ -10,7 +11,14 @@ export const parseInternals = (nodes) => {
10
11
  // all preppending selectors are naming nested properties
11
12
  const properties = [];
12
13
  for (const selector of nodes) {
13
- properties.push(asTagNode(asPostcssNodeWithChildren(selector).nodes[0]).value);
14
+ const selectorNode = asPostcssNodeWithChildren(selector).nodes[0];
15
+ // Handle both quoted string and tag nodes
16
+ if (isStringNode(selectorNode)) {
17
+ properties.push(removeQuotes(asStringNode(selectorNode).value));
18
+ }
19
+ else {
20
+ properties.push(asTagNode(selectorNode).value);
21
+ }
14
22
  }
15
23
  // include the attribute selector as the last part of the property lookup
16
24
  properties.push(attributeSelector.attribute);