@vltpkg/query 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -2
- package/dist/index.js +23 -4
- package/dist/pseudo/skill.d.ts +7 -0
- package/dist/pseudo/skill.js +52 -0
- package/dist/pseudo/skills.d.ts +6 -0
- package/dist/pseudo/skills.js +26 -0
- package/dist/pseudo.js +7 -0
- package/dist/types.d.ts +29 -1
- package/package.json +10 -12
- package/skills/dss-query/REFERENCE.md +0 -123
- package/skills/dss-query/SKILL.md +0 -190
- package/skills/dss-query/evals/README.md +0 -81
- package/skills/dss-query/evals/evals.json +0 -89
- package/skills/dss-query/evals/grade.mjs +0 -481
- package/src/attribute.ts +0 -190
- package/src/combinator.ts +0 -135
- package/src/error.ts +0 -78
- package/src/id.ts +0 -46
- package/src/index.ts +0 -640
- package/src/parser.ts +0 -122
- package/src/pseudo/abandoned.ts +0 -9
- package/src/pseudo/attr.ts +0 -92
- package/src/pseudo/built.ts +0 -19
- package/src/pseudo/confused.ts +0 -29
- package/src/pseudo/cve.ts +0 -93
- package/src/pseudo/cwe.ts +0 -97
- package/src/pseudo/debug.ts +0 -9
- package/src/pseudo/deprecated.ts +0 -9
- package/src/pseudo/dev.ts +0 -18
- package/src/pseudo/diff.ts +0 -90
- package/src/pseudo/dist.ts +0 -148
- package/src/pseudo/dynamic.ts +0 -9
- package/src/pseudo/empty.ts +0 -15
- package/src/pseudo/entropic.ts +0 -9
- package/src/pseudo/env.ts +0 -6
- package/src/pseudo/eval.ts +0 -9
- package/src/pseudo/fs.ts +0 -9
- package/src/pseudo/helpers.ts +0 -106
- package/src/pseudo/host.ts +0 -111
- package/src/pseudo/hostname.ts +0 -156
- package/src/pseudo/license.ts +0 -134
- package/src/pseudo/link.ts +0 -30
- package/src/pseudo/malware.ts +0 -41
- package/src/pseudo/minified.ts +0 -9
- package/src/pseudo/missing.ts +0 -16
- package/src/pseudo/native.ts +0 -9
- package/src/pseudo/network.ts +0 -9
- package/src/pseudo/obfuscated.ts +0 -9
- package/src/pseudo/optional.ts +0 -18
- package/src/pseudo/outdated.ts +0 -345
- package/src/pseudo/overridden.ts +0 -20
- package/src/pseudo/path.ts +0 -146
- package/src/pseudo/peer.ts +0 -18
- package/src/pseudo/prerelease.ts +0 -47
- package/src/pseudo/private.ts +0 -19
- package/src/pseudo/prod.ts +0 -18
- package/src/pseudo/published.ts +0 -250
- package/src/pseudo/registry.ts +0 -29
- package/src/pseudo/root.ts +0 -19
- package/src/pseudo/scanned.ts +0 -20
- package/src/pseudo/score.ts +0 -186
- package/src/pseudo/scripts.ts +0 -61
- package/src/pseudo/semver.ts +0 -320
- package/src/pseudo/severity.ts +0 -231
- package/src/pseudo/shell.ts +0 -9
- package/src/pseudo/shrinkwrap.ts +0 -9
- package/src/pseudo/spec.ts +0 -131
- package/src/pseudo/squat.ts +0 -225
- package/src/pseudo/suspicious.ts +0 -9
- package/src/pseudo/tracker.ts +0 -9
- package/src/pseudo/trivial.ts +0 -9
- package/src/pseudo/type.ts +0 -26
- package/src/pseudo/undesirable.ts +0 -9
- package/src/pseudo/unknown.ts +0 -9
- package/src/pseudo/unmaintained.ts +0 -9
- package/src/pseudo/unpopular.ts +0 -9
- package/src/pseudo/unstable.ts +0 -9
- package/src/pseudo/vuln.ts +0 -273
- package/src/pseudo/workspace.ts +0 -22
- package/src/pseudo.ts +0 -433
- package/src/types.ts +0 -176
- package/tap-snapshots/test/attribute.ts.test.cjs +0 -304
- package/tap-snapshots/test/combinator.ts.test.cjs +0 -333
- package/tap-snapshots/test/id.ts.test.cjs +0 -118
- package/tap-snapshots/test/parser.ts.test.cjs +0 -344
- package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/attr.ts.test.cjs +0 -161
- package/tap-snapshots/test/pseudo/built.ts.test.cjs +0 -70
- package/tap-snapshots/test/pseudo/confused.ts.test.cjs +0 -32
- package/tap-snapshots/test/pseudo/cve.ts.test.cjs +0 -49
- package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +0 -49
- package/tap-snapshots/test/pseudo/debug.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/dist.ts.test.cjs +0 -30
- package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/empty.ts.test.cjs +0 -50
- package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/env.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/eval.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/fs.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +0 -148
- package/tap-snapshots/test/pseudo/license.ts.test.cjs +0 -41
- package/tap-snapshots/test/pseudo/link.ts.test.cjs +0 -36
- package/tap-snapshots/test/pseudo/malware.ts.test.cjs +0 -22
- package/tap-snapshots/test/pseudo/minified.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/missing.ts.test.cjs +0 -30
- package/tap-snapshots/test/pseudo/native.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/network.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +0 -132
- package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +0 -75
- package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +0 -101
- package/tap-snapshots/test/pseudo/private.ts.test.cjs +0 -38
- package/tap-snapshots/test/pseudo/published.ts.test.cjs +0 -171
- package/tap-snapshots/test/pseudo/registry.ts.test.cjs +0 -68
- package/tap-snapshots/test/pseudo/root.ts.test.cjs +0 -24
- package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/score.ts.test.cjs +0 -239
- package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +0 -62
- package/tap-snapshots/test/pseudo/semver.ts.test.cjs +0 -575
- package/tap-snapshots/test/pseudo/severity.ts.test.cjs +0 -122
- package/tap-snapshots/test/pseudo/shell.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/spec.ts.test.cjs +0 -148
- package/tap-snapshots/test/pseudo/squat.ts.test.cjs +0 -129
- package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/type.ts.test.cjs +0 -51
- package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +0 -18
- package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +0 -208
- package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +0 -20
- package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +0 -19
- package/tap-snapshots/test/pseudo.ts.test.cjs +0 -1247
- package/test/attribute.ts +0 -273
- package/test/combinator.ts +0 -175
- package/test/error.ts +0 -60
- package/test/fixtures/graph.ts +0 -999
- package/test/fixtures/selector.ts +0 -103
- package/test/fixtures/types.ts +0 -7
- package/test/id.ts +0 -102
- package/test/index.ts +0 -1049
- package/test/parser.ts +0 -117
- package/test/pseudo/abandoned.ts +0 -98
- package/test/pseudo/attr.ts +0 -298
- package/test/pseudo/built.ts +0 -214
- package/test/pseudo/confused.ts +0 -160
- package/test/pseudo/cve.ts +0 -249
- package/test/pseudo/cwe.ts +0 -255
- package/test/pseudo/debug.ts +0 -98
- package/test/pseudo/deprecated.ts +0 -98
- package/test/pseudo/dev.ts +0 -61
- package/test/pseudo/diff.ts +0 -417
- package/test/pseudo/dist.ts +0 -215
- package/test/pseudo/dynamic.ts +0 -98
- package/test/pseudo/empty.ts +0 -108
- package/test/pseudo/entropic.ts +0 -101
- package/test/pseudo/env.ts +0 -98
- package/test/pseudo/eval.ts +0 -98
- package/test/pseudo/fs.ts +0 -98
- package/test/pseudo/helpers.ts +0 -370
- package/test/pseudo/host-context.ts +0 -276
- package/test/pseudo/hostname.ts +0 -314
- package/test/pseudo/license.ts +0 -265
- package/test/pseudo/link.ts +0 -94
- package/test/pseudo/malware.ts +0 -184
- package/test/pseudo/minified.ts +0 -98
- package/test/pseudo/missing.ts +0 -111
- package/test/pseudo/native.ts +0 -98
- package/test/pseudo/network.ts +0 -98
- package/test/pseudo/obfuscated.ts +0 -98
- package/test/pseudo/optional.ts +0 -73
- package/test/pseudo/outdated.ts +0 -461
- package/test/pseudo/overridden.ts +0 -317
- package/test/pseudo/path.ts +0 -680
- package/test/pseudo/peer.ts +0 -101
- package/test/pseudo/prerelease.ts +0 -279
- package/test/pseudo/private.ts +0 -108
- package/test/pseudo/prod.ts +0 -61
- package/test/pseudo/published.ts +0 -557
- package/test/pseudo/registry.ts +0 -122
- package/test/pseudo/root.ts +0 -66
- package/test/pseudo/scanned.ts +0 -144
- package/test/pseudo/score.ts +0 -591
- package/test/pseudo/scripts.ts +0 -324
- package/test/pseudo/semver.ts +0 -822
- package/test/pseudo/severity.ts +0 -342
- package/test/pseudo/shell.ts +0 -98
- package/test/pseudo/shrinkwrap.ts +0 -98
- package/test/pseudo/spec.ts +0 -525
- package/test/pseudo/squat.ts +0 -565
- package/test/pseudo/suspicious.ts +0 -98
- package/test/pseudo/tracker.ts +0 -98
- package/test/pseudo/trivial.ts +0 -98
- package/test/pseudo/type.ts +0 -105
- package/test/pseudo/undesirable.ts +0 -98
- package/test/pseudo/unknown.ts +0 -98
- package/test/pseudo/unmaintained.ts +0 -98
- package/test/pseudo/unpopular.ts +0 -98
- package/test/pseudo/unstable.ts +0 -98
- package/test/pseudo/vuln.ts +0 -625
- package/test/pseudo/vulnerable.ts +0 -137
- package/test/pseudo/workspace.ts +0 -111
- package/test/pseudo.ts +0 -584
- package/tsconfig.json +0 -3
- package/tsconfig.publish.json +0 -19
- package/tsconfig.publish.tsbuildinfo +0 -1
- package/typedoc.mjs +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EdgeLike, NodeLike } from '@vltpkg/types';
|
|
2
2
|
import type { SecurityArchiveLike } from '@vltpkg/security-archive';
|
|
3
|
-
import type {
|
|
3
|
+
import type { PartPseudoName } from '@vltpkg/dss-parser';
|
|
4
|
+
import type { DiffFilesProvider, GetAuthHeader, HasSkills, HostContextsMap, ParsedSelectorToken, ParserState, QueryResponse } from './types.ts';
|
|
4
5
|
import type { DepID } from '@vltpkg/dep-id';
|
|
5
6
|
export * from './types.ts';
|
|
6
7
|
export type SearchOptions = {
|
|
@@ -17,6 +18,10 @@ export type QueryOptions = {
|
|
|
17
18
|
hostContexts?: HostContextsMap;
|
|
18
19
|
diffFiles?: DiffFilesProvider;
|
|
19
20
|
getAuthHeader?: GetAuthHeader;
|
|
21
|
+
/** for `:skills`; unset: `:skills` throws */
|
|
22
|
+
hasSkills?: HasSkills;
|
|
23
|
+
/** part selectors to allow, e.g. `['skill']`; others throw */
|
|
24
|
+
partSelectors?: readonly PartPseudoName[];
|
|
20
25
|
};
|
|
21
26
|
/**
|
|
22
27
|
* The Query class is used to search the graph for nodes and edges
|
|
@@ -37,7 +42,7 @@ export declare class Query {
|
|
|
37
42
|
* the original order is preserved.
|
|
38
43
|
*/
|
|
39
44
|
static specificitySort(responses: QueryResponse[]): QueryResponse[];
|
|
40
|
-
constructor({ edges, nodes, importers, retries, securityArchive, hostContexts, diffFiles, getAuthHeader, }: QueryOptions);
|
|
45
|
+
constructor({ edges, nodes, importers, retries, securityArchive, hostContexts, diffFiles, getAuthHeader, hasSkills, partSelectors, }: QueryOptions);
|
|
41
46
|
/**
|
|
42
47
|
* Search the graph for nodes and edges that match the given query.
|
|
43
48
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { joinDepIDTuple } from '@vltpkg/dep-id/browser';
|
|
2
|
-
import { parse, isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, isPseudoNode, isIdentifierNode, isAttributeNode, } from '@vltpkg/dss-parser';
|
|
2
|
+
import { parse, partPseudoNames, isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, isPseudoNode, isIdentifierNode, isAttributeNode, } from '@vltpkg/dss-parser';
|
|
3
3
|
import { attribute } from "./attribute.js";
|
|
4
4
|
import { combinator } from "./combinator.js";
|
|
5
5
|
import { id } from "./id.js";
|
|
@@ -7,6 +7,7 @@ import { pseudo, pseudoSelectorNames } from "./pseudo.js";
|
|
|
7
7
|
import { queryError, selectorText } from "./error.js";
|
|
8
8
|
export * from "./types.js";
|
|
9
9
|
const noopFn = async (state) => state;
|
|
10
|
+
const partPseudos = new Set(partPseudoNames);
|
|
10
11
|
/**
|
|
11
12
|
* `.dev` and a bare `dev` are the two ways a css habit shows up in a
|
|
12
13
|
* query. Neither is valid DSS, but the intent is usually a pseudo-class
|
|
@@ -16,7 +17,8 @@ const unsupportedName = (state) => {
|
|
|
16
17
|
const text = selectorText(state.current);
|
|
17
18
|
const name = text.replace(/^[.#]/, '');
|
|
18
19
|
return queryError('Unsupported selector', state.current, {
|
|
19
|
-
wanted: pseudoSelectorNames.has(name)
|
|
20
|
+
wanted: pseudoSelectorNames.has(name) && !partPseudos.has(name) ?
|
|
21
|
+
`:${name}`
|
|
20
22
|
: name ? `#${name}`
|
|
21
23
|
: undefined,
|
|
22
24
|
});
|
|
@@ -97,6 +99,13 @@ export const walk = async (state) => {
|
|
|
97
99
|
for (const node of state.partial.nodes) {
|
|
98
100
|
state.collect.nodes.add(node);
|
|
99
101
|
}
|
|
102
|
+
if (state.parts && node.parent?.type === 'root') {
|
|
103
|
+
state.parts.push({
|
|
104
|
+
...state.part,
|
|
105
|
+
nodes: [...state.partial.nodes],
|
|
106
|
+
});
|
|
107
|
+
delete state.part;
|
|
108
|
+
}
|
|
100
109
|
}
|
|
101
110
|
}
|
|
102
111
|
return state;
|
|
@@ -155,12 +164,14 @@ export class Query {
|
|
|
155
164
|
#cache;
|
|
156
165
|
#diffFiles;
|
|
157
166
|
#getAuthHeader;
|
|
167
|
+
#hasSkills;
|
|
158
168
|
#edges;
|
|
159
169
|
#nodes;
|
|
160
170
|
#importers;
|
|
161
171
|
#retries;
|
|
162
172
|
#securityArchive;
|
|
163
173
|
#hostContexts;
|
|
174
|
+
#partSelectors;
|
|
164
175
|
/**
|
|
165
176
|
* Helper method to determine if a given query string is using any of
|
|
166
177
|
* the known security selectors. This is useful so that operations can
|
|
@@ -194,10 +205,12 @@ export class Query {
|
|
|
194
205
|
return 0;
|
|
195
206
|
});
|
|
196
207
|
}
|
|
197
|
-
constructor({ edges, nodes, importers, retries, securityArchive, hostContexts, diffFiles, getAuthHeader, }) {
|
|
208
|
+
constructor({ edges, nodes, importers, retries, securityArchive, hostContexts, diffFiles, getAuthHeader, hasSkills, partSelectors, }) {
|
|
209
|
+
this.#partSelectors = new Set(partSelectors);
|
|
198
210
|
this.#cache = new Map();
|
|
199
211
|
this.#diffFiles = diffFiles;
|
|
200
212
|
this.#getAuthHeader = getAuthHeader;
|
|
213
|
+
this.#hasSkills = hasSkills;
|
|
201
214
|
this.#edges = edges;
|
|
202
215
|
this.#nodes = nodes;
|
|
203
216
|
this.#importers = importers;
|
|
@@ -325,7 +338,7 @@ export class Query {
|
|
|
325
338
|
const loose = asPostcssNodeWithChildren(current).nodes.length > 1;
|
|
326
339
|
// builds initial state and walks over it,
|
|
327
340
|
// retrieving the collected result
|
|
328
|
-
const { collect, comment, importers: stateResultImporters, specificity, } = await walk({
|
|
341
|
+
const { collect, comment, importers: stateResultImporters, parts, specificity, } = await walk({
|
|
329
342
|
cancellable: async () => {
|
|
330
343
|
await new Promise(resolve => {
|
|
331
344
|
setTimeout(resolve, 0);
|
|
@@ -344,9 +357,13 @@ export class Query {
|
|
|
344
357
|
comment: '',
|
|
345
358
|
diffFiles: this.#diffFiles,
|
|
346
359
|
getAuthHeader: this.#getAuthHeader,
|
|
360
|
+
hasSkills: this.#hasSkills,
|
|
347
361
|
loose,
|
|
348
362
|
importers,
|
|
349
363
|
partial: { nodes, edges },
|
|
364
|
+
...(this.#partSelectors.size ?
|
|
365
|
+
{ parts: [], partSelectors: this.#partSelectors }
|
|
366
|
+
: undefined),
|
|
350
367
|
retries: this.#retries,
|
|
351
368
|
signal,
|
|
352
369
|
securityArchive: this.#securityArchive,
|
|
@@ -361,6 +378,8 @@ export class Query {
|
|
|
361
378
|
importers: this.#getQueryResponseNodes(stateResultImporters),
|
|
362
379
|
comment,
|
|
363
380
|
specificity,
|
|
381
|
+
// part nodes are a subset of `nodes`, already hydrated above
|
|
382
|
+
...(parts ? { parts: parts } : undefined),
|
|
364
383
|
};
|
|
365
384
|
this.#cache.set(query, res);
|
|
366
385
|
return res;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ParserState } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* `:skill(<pattern>, ...)`: picks agent skills of the packages its
|
|
4
|
+
* selector matched. Never filters nodes: the walker stores the
|
|
5
|
+
* patterns in the selector's `parts` entry. Opt-in only.
|
|
6
|
+
*/
|
|
7
|
+
export declare const skill: (state: ParserState) => Promise<ParserState>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { asPseudoNode } from '@vltpkg/dss-parser';
|
|
2
|
+
import { queryError } from "../error.js";
|
|
3
|
+
import { removeQuotes } from "./helpers.js";
|
|
4
|
+
/**
|
|
5
|
+
* `:skill(<pattern>, ...)`: picks agent skills of the packages its
|
|
6
|
+
* selector matched. Never filters nodes: the walker stores the
|
|
7
|
+
* patterns in the selector's `parts` entry. Opt-in only.
|
|
8
|
+
*/
|
|
9
|
+
export const skill = async (state) => {
|
|
10
|
+
const curr = asPseudoNode(state.current);
|
|
11
|
+
const sel = curr.parent;
|
|
12
|
+
const fail = (message) => queryError(message, state.current);
|
|
13
|
+
if (sel?.parent?.type !== 'root' ||
|
|
14
|
+
sel.nodes
|
|
15
|
+
.slice(sel.index(curr) + 1)
|
|
16
|
+
.some(n => n.type !== 'comment')) {
|
|
17
|
+
throw fail(':skill() must end a top-level selector');
|
|
18
|
+
}
|
|
19
|
+
if (!state.partSelectors?.has('skill')) {
|
|
20
|
+
throw fail(':skill() only applies to --allow-skills and vlt skills');
|
|
21
|
+
}
|
|
22
|
+
if (!curr.nodes.length)
|
|
23
|
+
throw fail('Missing skill name in :skill()');
|
|
24
|
+
const patterns = curr.nodes.map(arg => {
|
|
25
|
+
let pattern = '';
|
|
26
|
+
for (const n of arg.nodes) {
|
|
27
|
+
if (n.type === 'comment')
|
|
28
|
+
continue;
|
|
29
|
+
// `a|b` is tag `b` in namespace `a`: never drop the `a`
|
|
30
|
+
if ((n.type === 'tag' || n.type === 'universal') &&
|
|
31
|
+
!String(n).includes('|')) {
|
|
32
|
+
pattern += n.value;
|
|
33
|
+
}
|
|
34
|
+
else if (n.type === 'string') {
|
|
35
|
+
if (n.value.startsWith("'")) {
|
|
36
|
+
throw fail('Invalid skill name in :skill(), use double quotes');
|
|
37
|
+
}
|
|
38
|
+
pattern += removeQuotes(n.value);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
throw fail(n.type === 'combinator' ?
|
|
42
|
+
'Invalid skill name in :skill(), quote names with spaces'
|
|
43
|
+
: 'Invalid skill name in :skill()');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!pattern)
|
|
47
|
+
throw fail('Missing skill name in :skill()');
|
|
48
|
+
return pattern;
|
|
49
|
+
});
|
|
50
|
+
state.part = { name: 'skill', patterns };
|
|
51
|
+
return state;
|
|
52
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { asPseudoNode } from '@vltpkg/dss-parser';
|
|
2
|
+
import { queryError } from "../error.js";
|
|
3
|
+
import { clear, removeDanglingEdges, removeNode } from "./helpers.js";
|
|
4
|
+
/**
|
|
5
|
+
* `:skills`: matches installed packages that ship agent skills, as
|
|
6
|
+
* told by the `hasSkills` provider.
|
|
7
|
+
*/
|
|
8
|
+
export const skills = async (state) => {
|
|
9
|
+
// `:skills(x)`: likely a `:skill(x)` typo
|
|
10
|
+
if (asPseudoNode(state.current).nodes.length) {
|
|
11
|
+
if (state.loose)
|
|
12
|
+
return clear(state);
|
|
13
|
+
throw queryError(':skills takes no arguments', state.current, {
|
|
14
|
+
wanted: ':skill',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (!state.hasSkills) {
|
|
18
|
+
throw queryError('The :skills selector is not supported here', state.current);
|
|
19
|
+
}
|
|
20
|
+
for (const node of state.partial.nodes) {
|
|
21
|
+
if (!(await state.hasSkills(node)))
|
|
22
|
+
removeNode(state, node);
|
|
23
|
+
}
|
|
24
|
+
removeDanglingEdges(state);
|
|
25
|
+
return state;
|
|
26
|
+
};
|
package/dist/pseudo.js
CHANGED
|
@@ -49,6 +49,8 @@ import { semverParser as semver } from "./pseudo/semver.js";
|
|
|
49
49
|
import { severity } from "./pseudo/severity.js";
|
|
50
50
|
import { spec } from "./pseudo/spec.js";
|
|
51
51
|
import { shrinkwrap } from "./pseudo/shrinkwrap.js";
|
|
52
|
+
import { skill } from "./pseudo/skill.js";
|
|
53
|
+
import { skills } from "./pseudo/skills.js";
|
|
52
54
|
import { squat } from "./pseudo/squat.js";
|
|
53
55
|
import { suspicious } from "./pseudo/suspicious.js";
|
|
54
56
|
import { tracker } from "./pseudo/tracker.js";
|
|
@@ -88,6 +90,7 @@ const has = async (state) => {
|
|
|
88
90
|
nodes: new Set(state.partial.nodes),
|
|
89
91
|
},
|
|
90
92
|
diffFiles: state.diffFiles,
|
|
93
|
+
hasSkills: state.hasSkills,
|
|
91
94
|
loose: state.loose,
|
|
92
95
|
hostContexts: state.hostContexts,
|
|
93
96
|
importers: state.importers,
|
|
@@ -164,6 +167,7 @@ const is = async (state) => {
|
|
|
164
167
|
},
|
|
165
168
|
current: node,
|
|
166
169
|
diffFiles: state.diffFiles,
|
|
170
|
+
hasSkills: state.hasSkills,
|
|
167
171
|
initial: state.initial,
|
|
168
172
|
loose: true,
|
|
169
173
|
partial: {
|
|
@@ -210,6 +214,7 @@ const not = async (state) => {
|
|
|
210
214
|
},
|
|
211
215
|
current: node,
|
|
212
216
|
diffFiles: state.diffFiles,
|
|
217
|
+
hasSkills: state.hasSkills,
|
|
213
218
|
initial: state.initial,
|
|
214
219
|
loose: state.loose,
|
|
215
220
|
partial: {
|
|
@@ -331,6 +336,8 @@ const pseudoSelectors = new Map(Object.entries({
|
|
|
331
336
|
severity,
|
|
332
337
|
shell,
|
|
333
338
|
shrinkwrap,
|
|
339
|
+
skill,
|
|
340
|
+
skills,
|
|
334
341
|
squat,
|
|
335
342
|
suspicious,
|
|
336
343
|
tracker,
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { EdgeLike, NodeLike } from '@vltpkg/types';
|
|
2
2
|
import type { SecurityArchiveLike, PackageScore } from '@vltpkg/security-archive';
|
|
3
3
|
import type { DepID } from '@vltpkg/dep-id';
|
|
4
|
-
import type { PostcssNode } from '@vltpkg/dss-parser';
|
|
4
|
+
import type { PartPseudoName, PostcssNode } from '@vltpkg/dss-parser';
|
|
5
5
|
export type HostContextsMapResult = {
|
|
6
6
|
initialEdges: EdgeLike[];
|
|
7
7
|
initialNodes: NodeLike[];
|
|
@@ -31,6 +31,22 @@ export type DiffFilesProvider = (commitish: string) => Set<string>;
|
|
|
31
31
|
* keychain / registry-client dependency.
|
|
32
32
|
*/
|
|
33
33
|
export type GetAuthHeader = (url: string) => Promise<string | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Whether an installed package ships agent skills; for `:skills`.
|
|
36
|
+
* Keeps fs out of this package.
|
|
37
|
+
*/
|
|
38
|
+
export type HasSkills = (node: NodeLike) => Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* One top-level selector of a query and the nodes it matched. `name`
|
|
41
|
+
* and `patterns` are set when it ends in a part selector, e.g.
|
|
42
|
+
* `#a:skill(x, y*)`.
|
|
43
|
+
*/
|
|
44
|
+
export type QueryPart<N = QueryResponseNode> = {
|
|
45
|
+
name?: PartPseudoName;
|
|
46
|
+
/** as typed, `*` = glob; for matching only, never paths */
|
|
47
|
+
patterns?: string[];
|
|
48
|
+
nodes: N[];
|
|
49
|
+
};
|
|
34
50
|
export type ParserState = {
|
|
35
51
|
cancellable: () => Promise<void>;
|
|
36
52
|
collect: GraphSelectionState;
|
|
@@ -38,6 +54,7 @@ export type ParserState = {
|
|
|
38
54
|
current: PostcssNode;
|
|
39
55
|
diffFiles?: DiffFilesProvider;
|
|
40
56
|
getAuthHeader?: GetAuthHeader;
|
|
57
|
+
hasSkills?: HasSkills;
|
|
41
58
|
hostContexts?: HostContextsMap;
|
|
42
59
|
importers: Set<NodeLike>;
|
|
43
60
|
initial: GraphSelectionState;
|
|
@@ -48,6 +65,12 @@ export type ParserState = {
|
|
|
48
65
|
signal: AbortSignal;
|
|
49
66
|
walk: ParserFn;
|
|
50
67
|
partial: GraphSelectionState;
|
|
68
|
+
/** set by `:skill()`, read and cleared by `walk()` */
|
|
69
|
+
part?: Pick<QueryPart, 'name' | 'patterns'>;
|
|
70
|
+
/** one entry per top-level selector, only when opted in */
|
|
71
|
+
parts?: QueryPart<NodeLike>[];
|
|
72
|
+
/** part selectors this consumer allows */
|
|
73
|
+
partSelectors?: ReadonlySet<PartPseudoName>;
|
|
51
74
|
retries: number;
|
|
52
75
|
securityArchive: SecurityArchiveLike | undefined;
|
|
53
76
|
scopeIDs?: DepID[];
|
|
@@ -59,6 +82,11 @@ export type QueryResponse = {
|
|
|
59
82
|
importers: QueryResponseNode[];
|
|
60
83
|
comment: string;
|
|
61
84
|
specificity: Specificity;
|
|
85
|
+
/**
|
|
86
|
+
* one entry per top-level selector, only with `partSelectors` and
|
|
87
|
+
* a non-empty query
|
|
88
|
+
*/
|
|
89
|
+
parts?: QueryPart[];
|
|
62
90
|
};
|
|
63
91
|
export type QueryResponseEdge = Omit<EdgeLike, 'from' | 'to'> & {
|
|
64
92
|
from: QueryResponseNode;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/query",
|
|
3
3
|
"description": "Query syntax parser that retrieves items from a graph",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/dep-id": "1.
|
|
17
|
-
"@vltpkg/dss-parser": "1.
|
|
18
|
-
"@vltpkg/error-cause": "1.
|
|
19
|
-
"@vltpkg/security-archive": "1.
|
|
20
|
-
"@vltpkg/semver": "1.
|
|
21
|
-
"@vltpkg/types": "1.
|
|
22
|
-
"@vltpkg/user-agent": "1.
|
|
16
|
+
"@vltpkg/dep-id": "1.6.0",
|
|
17
|
+
"@vltpkg/dss-parser": "1.6.0",
|
|
18
|
+
"@vltpkg/error-cause": "1.6.0",
|
|
19
|
+
"@vltpkg/security-archive": "1.6.0",
|
|
20
|
+
"@vltpkg/semver": "1.6.0",
|
|
21
|
+
"@vltpkg/types": "1.6.0",
|
|
22
|
+
"@vltpkg/user-agent": "1.6.0",
|
|
23
23
|
"minimatch": "^10.1.1",
|
|
24
24
|
"p-retry": "^7.1.1",
|
|
25
25
|
"postcss-selector-parser": "^7.1.1"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@eslint/js": "^9.39.1",
|
|
29
29
|
"@types/node": "^22.19.2",
|
|
30
|
-
"@vltpkg/spec": "1.
|
|
30
|
+
"@vltpkg/spec": "1.6.0",
|
|
31
31
|
"eslint": "^9.39.1",
|
|
32
32
|
"prettier": "^3.7.4",
|
|
33
33
|
"tap": "^21.8.0",
|
|
@@ -65,9 +65,7 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"files": [
|
|
68
|
-
"dist"
|
|
69
|
-
"skills",
|
|
70
|
-
"!skills/dss-query/evals"
|
|
68
|
+
"dist"
|
|
71
69
|
],
|
|
72
70
|
"bugs": [
|
|
73
71
|
{
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# DSS Reference
|
|
2
|
-
|
|
3
|
-
Compiled from https://docs.vlt.io/cli/selectors/ (source:
|
|
4
|
-
`www/docs/src/content/docs/cli/selectors/`). When in doubt, check
|
|
5
|
-
those docs — they are canonical.
|
|
6
|
-
|
|
7
|
-
## Attribute selectors
|
|
8
|
-
|
|
9
|
-
Match against `package.json` fields.
|
|
10
|
-
|
|
11
|
-
| Selector | Meaning |
|
|
12
|
-
| ---------------- | ------------------------------------------------ |
|
|
13
|
-
| `[attr]` | has the property |
|
|
14
|
-
| `[attr=value]` | equals |
|
|
15
|
-
| `[attr^=value]` | starts with |
|
|
16
|
-
| `[attr$=value]` | ends with |
|
|
17
|
-
| `[attr*=value]` | contains |
|
|
18
|
-
| `[attr~=value]` | whitespace-separated list contains |
|
|
19
|
-
| `[attr\|=value]` | equals value or starts with `value-` |
|
|
20
|
-
| `[attr=value i]` | case-insensitive (`s` = case-sensitive, default) |
|
|
21
|
-
|
|
22
|
-
Nested fields (e.g. `engines.node`) need `:attr()`:
|
|
23
|
-
`:attr(engines, [node])`,
|
|
24
|
-
`:attr(peerDependenciesMeta, foo, [optional=true])`.
|
|
25
|
-
|
|
26
|
-
`#foo` is shorthand for `[name=foo]`.
|
|
27
|
-
|
|
28
|
-
## Combinators
|
|
29
|
-
|
|
30
|
-
| Combinator | Meaning |
|
|
31
|
-
| ---------- | -------------------------------------------------------------------- |
|
|
32
|
-
| `A > B` | B is a **direct** dependency of A (chain for depth: `:root > * > *`) |
|
|
33
|
-
| `A B` | B is a direct **or transitive** dependency of A |
|
|
34
|
-
| `A ~ B` | B shares a parent with A (sibling) |
|
|
35
|
-
|
|
36
|
-
## Pseudo-states (no arguments)
|
|
37
|
-
|
|
38
|
-
Graph structure:
|
|
39
|
-
|
|
40
|
-
| Selector | Matches |
|
|
41
|
-
| ------------ | --------------------------------------- |
|
|
42
|
-
| `:root` | top-level package.json node |
|
|
43
|
-
| `:project` | root + all workspaces ("your code") |
|
|
44
|
-
| `:workspace` | workspaces from vlt.json |
|
|
45
|
-
| `:scope` | current selector scope (with `--scope`) |
|
|
46
|
-
|
|
47
|
-
Dependency type:
|
|
48
|
-
|
|
49
|
-
| Selector | Matches |
|
|
50
|
-
| ---------------------------------------- | ------------------------------------------------------ |
|
|
51
|
-
| `:prod` / `:dev` / `:optional` / `:peer` | by dependency type |
|
|
52
|
-
| `:missing` | declared but not installed (**edges only, not nodes**) |
|
|
53
|
-
| `:overridden` | has an override applied |
|
|
54
|
-
|
|
55
|
-
Package properties:
|
|
56
|
-
|
|
57
|
-
| Selector | Matches |
|
|
58
|
-
| ------------- | -------------------------------------------- |
|
|
59
|
-
| `:private` | `"private": true` |
|
|
60
|
-
| `:empty` | no dependencies |
|
|
61
|
-
| `:link` | linked packages |
|
|
62
|
-
| `:prerelease` | version has prerelease part (`1.0.0-beta.1`) |
|
|
63
|
-
| `:built` | built during reify |
|
|
64
|
-
| `:scanned` | has Socket security metadata |
|
|
65
|
-
|
|
66
|
-
## Pseudo-classes (take arguments)
|
|
67
|
-
|
|
68
|
-
| Selector | Meaning | Example |
|
|
69
|
-
| ------------------- | --------------------------------------- | ---------------------------------------------- |
|
|
70
|
-
| `:attr(...)` | nested package.json property | `:attr(engines, [node])` |
|
|
71
|
-
| `:dist(tag)` | registry dist-tag | `:dist(latest)` |
|
|
72
|
-
| `:has(sel)` | has matching descendant | `:has(:peer[name=react])` |
|
|
73
|
-
| `:host(name)` | switch graph context to another project | `:host(local) :malware` |
|
|
74
|
-
| `:is(a, b)` | any of (forgiving list) | `:is([name=a], [name=b])` |
|
|
75
|
-
| `:not(sel)` | negation | `:not([license=MIT])` |
|
|
76
|
-
| `:outdated(kind?)` | newer version exists | `:outdated(major)` |
|
|
77
|
-
| `:published(range)` | by publish date | `:published(">2024")` |
|
|
78
|
-
| `:semver(range)` | semver comparison on installed version | `:semver(^1.0.0)` |
|
|
79
|
-
| `:spec(spec)` | by declared specifier (edge) | `:spec(^1.0.0)` |
|
|
80
|
-
| `:path(glob)` | workspace/file packages by path | `:path("packages/**")` |
|
|
81
|
-
| `:type(kind)` | package type | `:type(git)`, `:type(registry)`, `:type(file)` |
|
|
82
|
-
| `:diff(ref)` | files changed vs git ref | `:diff(main)` |
|
|
83
|
-
| `:hostname(host)` | upstream hostname | `:hostname(github.com)` |
|
|
84
|
-
| `:registry(name)` | configured registry name | `:registry(npm)` |
|
|
85
|
-
|
|
86
|
-
## Security insights (Socket-powered, network call)
|
|
87
|
-
|
|
88
|
-
Severity args accept names or numbers (`critical`/`0`, `high`/`1`,
|
|
89
|
-
`medium`/`2`, `low`/`3`) and comparators: `:severity(">=medium")`.
|
|
90
|
-
|
|
91
|
-
Threats: `:malware` (binary, no params), `:squat(sev?)`,
|
|
92
|
-
`:suspicious`, `:confused`.
|
|
93
|
-
|
|
94
|
-
Vulnerabilities: `:vuln(sev?)` (alias `:vulnerable`),
|
|
95
|
-
`:cve(CVE-2023-1234)`, `:cve(*)`, `:cwe(CWE-79)`, `:severity(level)`.
|
|
96
|
-
`:vuln` without params matches severity ≥ medium; `:vuln(critical)`
|
|
97
|
-
exact-matches; `:vuln(">=high")` uses comparators. Also matches alerts
|
|
98
|
-
carrying a `cveId` prop.
|
|
99
|
-
|
|
100
|
-
Licensing: `:license(type)` — types: `unlicensed`, `misc`,
|
|
101
|
-
`restricted`, `ambiguous`, `copyleft`, `unknown`, `none`, `exception`.
|
|
102
|
-
|
|
103
|
-
Code behavior: `:eval`, `:network`, `:fs`, `:env`, `:shell`,
|
|
104
|
-
`:scripts` (install scripts), `:debug`, `:dynamic`.
|
|
105
|
-
|
|
106
|
-
Obfuscation: `:obfuscated`, `:minified`, `:entropic`, `:native`,
|
|
107
|
-
`:shrinkwrap`.
|
|
108
|
-
|
|
109
|
-
Health: `:deprecated`, `:unmaintained` (5+ years stale), `:unpopular`,
|
|
110
|
-
`:trivial` (<10 LOC), `:abandoned`, `:unknown`, `:unstable`.
|
|
111
|
-
|
|
112
|
-
Other: `:tracker` (telemetry), `:undesirable`, `:score(rate, kind?)` —
|
|
113
|
-
kinds: `overall` (default), `license`, `maintenance`, `quality`,
|
|
114
|
-
`supplyChain`, `vulnerability`; e.g. `:score("<=0.5", "maintenance")`.
|
|
115
|
-
|
|
116
|
-
## Audit query starters
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
vlt query ':malware, :vuln(critical), :cve(*), :obfuscated' # critical issues
|
|
120
|
-
vlt query ':abandoned, :unmaintained, :unknown' # supply chain risk
|
|
121
|
-
vlt query ':license(copyleft), :license(unlicensed)' # license compliance
|
|
122
|
-
vlt query ':eval, :shell, :network, :fs' # behavior audit
|
|
123
|
-
```
|