@vltpkg/query 0.0.0-11 → 0.0.0-13
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/esm/attribute.d.ts.map +1 -1
- package/dist/esm/attribute.js +4 -11
- package/dist/esm/attribute.js.map +1 -1
- package/dist/esm/id.d.ts.map +1 -1
- package/dist/esm/id.js +2 -0
- package/dist/esm/id.js.map +1 -1
- package/dist/esm/index.d.ts +69 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +209 -10
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pseudo/outdated.d.ts.map +1 -1
- package/dist/esm/pseudo/outdated.js +3 -3
- package/dist/esm/pseudo/outdated.js.map +1 -1
- package/dist/esm/pseudo/published.d.ts.map +1 -1
- package/dist/esm/pseudo/published.js +1 -2
- package/dist/esm/pseudo/published.js.map +1 -1
- package/dist/esm/pseudo/root.d.ts +8 -0
- package/dist/esm/pseudo/root.d.ts.map +1 -0
- package/dist/esm/pseudo/root.js +22 -0
- package/dist/esm/pseudo/root.js.map +1 -0
- package/dist/esm/pseudo/semver.d.ts.map +1 -1
- package/dist/esm/pseudo/semver.js +2 -1
- package/dist/esm/pseudo/semver.js.map +1 -1
- package/dist/esm/pseudo/type.d.ts +8 -0
- package/dist/esm/pseudo/type.d.ts.map +1 -0
- package/dist/esm/pseudo/type.js +22 -0
- package/dist/esm/pseudo/type.js.map +1 -0
- package/dist/esm/pseudo/workspace.d.ts.map +1 -1
- package/dist/esm/pseudo/workspace.js +5 -2
- package/dist/esm/pseudo/workspace.js.map +1 -1
- package/dist/esm/pseudo.d.ts.map +1 -1
- package/dist/esm/pseudo.js +32 -44
- package/dist/esm/pseudo.js.map +1 -1
- package/dist/esm/types.d.ts +13 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/types.js +13 -0
- package/dist/esm/types.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attribute.d.ts","sourceRoot":"","sources":["../../src/attribute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"attribute.d.ts","sourceRoot":"","sources":["../../src/attribute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;AAOpE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,SAC9B,QAAQ,cACF,MAAM,EAAE,aACT,MAAM,KAChB,MAAM,EAAE,GAAG,SA+Db,CAAA;AAID,eAAO,MAAM,gBAAgB,UACpB,WAAW,cACN,YAAY,GAAG,SAAS,SAC7B,MAAM,gBACC,MAAM,eACP,OAAO,qBACF,MAAM,EAAE,KACzB,WAsCF,CAAA;AAcD,eAAO,MAAM,qBAAqB,2BAEjC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,UACb,WAAW,KACjB,OAAO,CAAC,WAAW,CA6BrB,CAAA"}
|
package/dist/esm/attribute.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
2
|
import { asAttributeNode } from "./types.js";
|
|
3
|
+
import { removeDanglingEdges } from "./pseudo/helpers.js";
|
|
3
4
|
// JSONField has a mapped type constituent that would coerce to [object Object]
|
|
4
5
|
// when stringified, which is what we want in this case.
|
|
5
6
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
@@ -93,17 +94,7 @@ export const filterAttributes = (state, comparator, value, propertyName, insensi
|
|
|
93
94
|
deleteNode(node);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
// edge.name is a special case in order
|
|
98
|
-
// to be able to match missing nodes by name
|
|
99
|
-
if (propertyName === 'name' && check(edge.name)) {
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
// remove any remaining dangling edge
|
|
103
|
-
if (!edge.to) {
|
|
104
|
-
state.partial.edges.delete(edge);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
97
|
+
removeDanglingEdges(state);
|
|
107
98
|
return state;
|
|
108
99
|
};
|
|
109
100
|
// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
|
|
@@ -135,6 +126,8 @@ export const attribute = async (state) => {
|
|
|
135
126
|
const value = curr.value || '';
|
|
136
127
|
const propertyName = curr.attribute;
|
|
137
128
|
const insensitive = !!curr.insensitive;
|
|
129
|
+
// Increment the commonCounter for specificity
|
|
130
|
+
state.specificity.commonCounter += 1;
|
|
138
131
|
return filterAttributes(state, operatorFn, value, propertyName, insensitive);
|
|
139
132
|
};
|
|
140
133
|
//# sourceMappingURL=attribute.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attribute.js","sourceRoot":"","sources":["../../src/attribute.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport type { NodeLike } from '@vltpkg/graph'\nimport type { JSONField, Manifest } from '@vltpkg/types'\nimport { asAttributeNode } from './types.ts'\nimport type { ParserState } from './types.ts'\n\nexport type ComparatorFn = (attr: string, value?: string) => boolean\n\n// JSONField has a mapped type constituent that would coerce to [object Object]\n// when stringified, which is what we want in this case.\n// eslint-disable-next-line @typescript-eslint/no-base-to-string\nconst jsonFieldToString = (v: JSONField) => String(v)\n\n/**\n * Retrieve the {@link Manifest} values found at the given `properties`\n * location for a given {@link Node}.\n */\nexport const getManifestPropertyValues = (\n node: NodeLike,\n properties: string[],\n attribute: string,\n): string[] | undefined => {\n if (!node.manifest) return\n\n const traverse = new Set<JSONField>([node.manifest as JSONField])\n const props = new Set<JSONField>()\n for (const key of properties) {\n for (const prop of traverse) {\n /* c8 ignore start - should be impossible */\n if (!prop) {\n throw error('failed to find nested property in :attr', {\n found: properties,\n })\n }\n /* c8 ignore stop */\n\n // expand the result list to include nested array values\n if (Array.isArray(prop)) {\n for (const p of prop) {\n traverse.add(p)\n }\n continue\n }\n\n // guard for inspecting keys of objects next\n if (\n typeof prop === 'string' ||\n typeof prop === 'number' ||\n typeof prop === 'boolean'\n ) {\n continue\n }\n\n // assign next value when found\n if (key in prop) {\n const nextValue = prop[key]\n if (nextValue) {\n if (key === attribute) {\n props.add(nextValue)\n } else {\n traverse.delete(prop)\n traverse.add(nextValue)\n }\n }\n }\n }\n }\n // if no value was found after trying a given key\n // then there's nothing to be collected\n if (!props.size) return\n\n // expand the result to include array values\n const collect = new Set<string>()\n for (const prop of props) {\n if (Array.isArray(prop)) {\n for (const p of prop) {\n collect.add(p ? jsonFieldToString(p) : '')\n }\n } else {\n collect.add(jsonFieldToString(prop))\n }\n }\n\n return [...collect]\n}\n\n// decorator style of function that will filter `ParserState` results\n// based on a provided `comparator` function\nexport const filterAttributes = (\n state: ParserState,\n comparator: ComparatorFn | undefined,\n value: string,\n propertyName: string,\n insensitive: boolean,\n prefixProperties: string[] = [],\n): ParserState => {\n const check = (attr: JSONField) =>\n comparator?.(\n insensitive ?\n jsonFieldToString(attr).toLowerCase()\n : jsonFieldToString(attr),\n insensitive ? value.toLowerCase() : value,\n )\n const deleteNode = (node: NodeLike) => {\n for (const edge of node.edgesIn) {\n state.partial.edges.delete(edge)\n }\n state.partial.nodes.delete(node)\n }\n\n for (const node of state.partial.nodes) {\n const prefixes =\n prefixProperties.length ? prefixProperties : [propertyName]\n const attrs = getManifestPropertyValues(\n node,\n prefixes,\n propertyName,\n )\n\n // if no attribute value was found, that means the attribute won't match\n if (!attrs?.length) {\n deleteNode(node)\n continue\n }\n\n // if the node attribute value won't match, then remove the node\n if (comparator && !attrs.some(check)) {\n deleteNode(node)\n }\n }\n\n for (const edge of state.partial.edges) {\n // edge.name is a special case in order\n // to be able to match missing nodes by name\n if (propertyName === 'name' && check(edge.name)) {\n continue\n }\n // remove any remaining dangling edge\n if (!edge.to) {\n state.partial.edges.delete(edge)\n }\n }\n return state\n}\n\n// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors\nconst attributeSelectors: Record<string, ComparatorFn> = {\n '=': (attr: string, value = '') => attr === value,\n '^=': (attr: string, value = '') => attr.startsWith(value),\n '$=': (attr: string, value = '') => attr.endsWith(value),\n '~=': (attr: string, value = '') =>\n new Set<string>(attr.match(/\\w+/g)).has(value),\n '*=': (attr: string, value = '') => attr.includes(value),\n '|=': (attr: string, value = '') =>\n attr === value || attr.startsWith(`${value}-`),\n undefined: (attr: string) => !!attr,\n}\nexport const attributeSelectorsMap = new Map<string, ComparatorFn>(\n Object.entries(attributeSelectors),\n)\n\n/**\n * Parse attributes selectors, e.g: `[name]`, `[name=value]`, etc\n */\nexport const attribute = async (\n state: ParserState,\n): Promise<ParserState> => {\n await state.cancellable()\n\n const curr = asAttributeNode(state.current)\n const operatorFn = attributeSelectorsMap.get(String(curr.operator))\n if (!operatorFn) {\n if (state.loose) {\n return state\n }\n\n throw error(`Unsupported attribute operator: ${curr.operator}`, {\n found: state.current,\n })\n }\n\n const value = curr.value || ''\n const propertyName = curr.attribute\n const insensitive = !!curr.insensitive\n return filterAttributes(\n state,\n operatorFn,\n value,\n propertyName,\n insensitive,\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"attribute.js","sourceRoot":"","sources":["../../src/attribute.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport type { NodeLike } from '@vltpkg/graph'\nimport type { JSONField, Manifest } from '@vltpkg/types'\nimport { asAttributeNode } from './types.ts'\nimport type { ParserState } from './types.ts'\nimport { removeDanglingEdges } from './pseudo/helpers.ts'\n\nexport type ComparatorFn = (attr: string, value?: string) => boolean\n\n// JSONField has a mapped type constituent that would coerce to [object Object]\n// when stringified, which is what we want in this case.\n// eslint-disable-next-line @typescript-eslint/no-base-to-string\nconst jsonFieldToString = (v: JSONField) => String(v)\n\n/**\n * Retrieve the {@link Manifest} values found at the given `properties`\n * location for a given {@link Node}.\n */\nexport const getManifestPropertyValues = (\n node: NodeLike,\n properties: string[],\n attribute: string,\n): string[] | undefined => {\n if (!node.manifest) return\n\n const traverse = new Set<JSONField>([node.manifest as JSONField])\n const props = new Set<JSONField>()\n for (const key of properties) {\n for (const prop of traverse) {\n /* c8 ignore start - should be impossible */\n if (!prop) {\n throw error('failed to find nested property in :attr', {\n found: properties,\n })\n }\n /* c8 ignore stop */\n\n // expand the result list to include nested array values\n if (Array.isArray(prop)) {\n for (const p of prop) {\n traverse.add(p)\n }\n continue\n }\n\n // guard for inspecting keys of objects next\n if (\n typeof prop === 'string' ||\n typeof prop === 'number' ||\n typeof prop === 'boolean'\n ) {\n continue\n }\n\n // assign next value when found\n if (key in prop) {\n const nextValue = prop[key]\n if (nextValue) {\n if (key === attribute) {\n props.add(nextValue)\n } else {\n traverse.delete(prop)\n traverse.add(nextValue)\n }\n }\n }\n }\n }\n // if no value was found after trying a given key\n // then there's nothing to be collected\n if (!props.size) return\n\n // expand the result to include array values\n const collect = new Set<string>()\n for (const prop of props) {\n if (Array.isArray(prop)) {\n for (const p of prop) {\n collect.add(p ? jsonFieldToString(p) : '')\n }\n } else {\n collect.add(jsonFieldToString(prop))\n }\n }\n\n return [...collect]\n}\n\n// decorator style of function that will filter `ParserState` results\n// based on a provided `comparator` function\nexport const filterAttributes = (\n state: ParserState,\n comparator: ComparatorFn | undefined,\n value: string,\n propertyName: string,\n insensitive: boolean,\n prefixProperties: string[] = [],\n): ParserState => {\n const check = (attr: JSONField) =>\n comparator?.(\n insensitive ?\n jsonFieldToString(attr).toLowerCase()\n : jsonFieldToString(attr),\n insensitive ? value.toLowerCase() : value,\n )\n const deleteNode = (node: NodeLike) => {\n for (const edge of node.edgesIn) {\n state.partial.edges.delete(edge)\n }\n state.partial.nodes.delete(node)\n }\n\n for (const node of state.partial.nodes) {\n const prefixes =\n prefixProperties.length ? prefixProperties : [propertyName]\n const attrs = getManifestPropertyValues(\n node,\n prefixes,\n propertyName,\n )\n\n // if no attribute value was found, that means the attribute won't match\n if (!attrs?.length) {\n deleteNode(node)\n continue\n }\n\n // if the node attribute value won't match, then remove the node\n if (comparator && !attrs.some(check)) {\n deleteNode(node)\n }\n }\n\n removeDanglingEdges(state)\n return state\n}\n\n// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors\nconst attributeSelectors: Record<string, ComparatorFn> = {\n '=': (attr: string, value = '') => attr === value,\n '^=': (attr: string, value = '') => attr.startsWith(value),\n '$=': (attr: string, value = '') => attr.endsWith(value),\n '~=': (attr: string, value = '') =>\n new Set<string>(attr.match(/\\w+/g)).has(value),\n '*=': (attr: string, value = '') => attr.includes(value),\n '|=': (attr: string, value = '') =>\n attr === value || attr.startsWith(`${value}-`),\n undefined: (attr: string) => !!attr,\n}\nexport const attributeSelectorsMap = new Map<string, ComparatorFn>(\n Object.entries(attributeSelectors),\n)\n\n/**\n * Parse attributes selectors, e.g: `[name]`, `[name=value]`, etc\n */\nexport const attribute = async (\n state: ParserState,\n): Promise<ParserState> => {\n await state.cancellable()\n\n const curr = asAttributeNode(state.current)\n const operatorFn = attributeSelectorsMap.get(String(curr.operator))\n if (!operatorFn) {\n if (state.loose) {\n return state\n }\n\n throw error(`Unsupported attribute operator: ${curr.operator}`, {\n found: state.current,\n })\n }\n\n const value = curr.value || ''\n const propertyName = curr.attribute\n const insensitive = !!curr.insensitive\n\n // Increment the commonCounter for specificity\n state.specificity.commonCounter += 1\n\n return filterAttributes(\n state,\n operatorFn,\n value,\n propertyName,\n insensitive,\n )\n}\n"]}
|
package/dist/esm/id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,EAAE,UACN,WAAW,KACjB,OAAO,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,EAAE,UACN,WAAW,KACjB,OAAO,CAAC,WAAW,CAoCrB,CAAA"}
|
package/dist/esm/id.js
CHANGED
package/dist/esm/id.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAG7C;;GAEG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,EACrB,KAAkB,EACI,EAAE;IACxB,MAAM,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEjD,8CAA8C;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,KAAK,CAAC,yBAAyB,CAAC,CAAA;IACxC,CAAC;IACD,oBAAoB;IAEpB,wCAAwC;IACxC,yCAAyC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACxB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,yDAAyD;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,IACE,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;YACvB,IAAI,CAAC,IAAI,KAAK,KAAK;YACnB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAC7B,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { asIdentifierNode } from './types.ts'\nimport type { ParserState } from './types.ts'\n\n/**\n * Parse ids, e.g: `#foo`\n */\nexport const id = async (\n state: ParserState,\n): Promise<ParserState> => {\n const { value } = asIdentifierNode(state.current)\n\n /* c8 ignore start - should not be possible */\n if (!value) {\n throw error('Missing identifier name')\n }\n /* c8 ignore stop */\n\n // Filter out any edges and their linked\n // nodes if they don't match the id value\n for (const edge of state.partial.edges) {\n if (edge.name !== value) {\n state.partial.edges.delete(edge)\n if (edge.to) {\n state.partial.nodes.delete(edge.to)\n }\n }\n }\n\n // Filter out importer nodes, this extra step is needed\n // to filter out nodes that have no edges linking to them\n for (const node of state.partial.nodes) {\n if (\n node.edgesIn.size === 0 &&\n node.name !== value &&\n state.partial.nodes.has(node)\n ) {\n state.partial.nodes.delete(node)\n }\n }\n\n return state\n}\n"]}
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAG7C;;GAEG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,EACrB,KAAkB,EACI,EAAE;IACxB,MAAM,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEjD,8CAA8C;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,KAAK,CAAC,yBAAyB,CAAC,CAAA;IACxC,CAAC;IACD,oBAAoB;IAEpB,wCAAwC;IACxC,yCAAyC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACxB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,yDAAyD;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,IACE,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;YACvB,IAAI,CAAC,IAAI,KAAK,KAAK;YACnB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAC7B,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,KAAK,CAAC,WAAW,CAAC,SAAS,IAAI,CAAC,CAAA;IAEhC,OAAO,KAAK,CAAA;AACd,CAAC,CAAA","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { asIdentifierNode } from './types.ts'\nimport type { ParserState } from './types.ts'\n\n/**\n * Parse ids, e.g: `#foo`\n */\nexport const id = async (\n state: ParserState,\n): Promise<ParserState> => {\n const { value } = asIdentifierNode(state.current)\n\n /* c8 ignore start - should not be possible */\n if (!value) {\n throw error('Missing identifier name')\n }\n /* c8 ignore stop */\n\n // Filter out any edges and their linked\n // nodes if they don't match the id value\n for (const edge of state.partial.edges) {\n if (edge.name !== value) {\n state.partial.edges.delete(edge)\n if (edge.to) {\n state.partial.nodes.delete(edge.to)\n }\n }\n }\n\n // Filter out importer nodes, this extra step is needed\n // to filter out nodes that have no edges linking to them\n for (const node of state.partial.nodes) {\n if (\n node.edgesIn.size === 0 &&\n node.name !== value &&\n state.partial.nodes.has(node)\n ) {\n state.partial.nodes.delete(node)\n }\n }\n\n // Increment the idCounter for specificity\n state.specificity.idCounter += 1\n\n return state\n}\n"]}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -2,7 +2,12 @@ import type { GraphLike } from '@vltpkg/graph';
|
|
|
2
2
|
import type { SpecOptions } from '@vltpkg/spec/browser';
|
|
3
3
|
import type { SecurityArchiveLike } from '@vltpkg/security-archive';
|
|
4
4
|
import type { ParsedSelectorToken, ParserState, QueryResponse } from './types.ts';
|
|
5
|
+
import type { DepID } from '@vltpkg/dep-id';
|
|
5
6
|
export * from './types.ts';
|
|
7
|
+
export type SearchOptions = {
|
|
8
|
+
signal: AbortSignal;
|
|
9
|
+
scopeIDs?: DepID[];
|
|
10
|
+
};
|
|
6
11
|
export declare const walk: (state: ParserState) => Promise<ParserState>;
|
|
7
12
|
export type QueryOptions = {
|
|
8
13
|
graph: GraphLike;
|
|
@@ -10,6 +15,57 @@ export type QueryOptions = {
|
|
|
10
15
|
specOptions: SpecOptions;
|
|
11
16
|
securityArchive: SecurityArchiveLike | undefined;
|
|
12
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* A valid item of a given breadcrumb.
|
|
20
|
+
*/
|
|
21
|
+
export type InteractiveBreadcrumbItem = {
|
|
22
|
+
value: string;
|
|
23
|
+
type: string;
|
|
24
|
+
prev: InteractiveBreadcrumbItem | undefined;
|
|
25
|
+
next: InteractiveBreadcrumbItem | undefined;
|
|
26
|
+
importer: boolean;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The InteractiveBreadcrumb class is used to represent a valid breadcrumb.
|
|
30
|
+
*
|
|
31
|
+
* "Breadcrumb" is a term used to describe the subset of the query language
|
|
32
|
+
* that uses only root/workspace selectors, id selectors & combinators.
|
|
33
|
+
*
|
|
34
|
+
* It implements an iterable, doubly-linked list of items that can be used
|
|
35
|
+
* to navigate through the breadcrumb.
|
|
36
|
+
*
|
|
37
|
+
* It also validates that each element of the provided query string is
|
|
38
|
+
* valid according to the previous definition of a "breadcrumb".
|
|
39
|
+
*/
|
|
40
|
+
export declare class InteractiveBreadcrumb implements Iterable<InteractiveBreadcrumbItem> {
|
|
41
|
+
#private;
|
|
42
|
+
comment: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Initializes the interactive breadcrumb with a query string.
|
|
45
|
+
*/
|
|
46
|
+
constructor(query: string);
|
|
47
|
+
/**
|
|
48
|
+
* The current breadcrumb item.
|
|
49
|
+
*/
|
|
50
|
+
get current(): InteractiveBreadcrumbItem;
|
|
51
|
+
/**
|
|
52
|
+
* The next breadcrumb item.
|
|
53
|
+
*/
|
|
54
|
+
next(): InteractiveBreadcrumbItem | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* The previous breadcrumb item.
|
|
57
|
+
*/
|
|
58
|
+
prev(): InteractiveBreadcrumbItem | undefined;
|
|
59
|
+
[Symbol.iterator](): ArrayIterator<InteractiveBreadcrumbItem>;
|
|
60
|
+
/**
|
|
61
|
+
* Empties the current breadcrumb list.
|
|
62
|
+
*/
|
|
63
|
+
clear(): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The Query class is used to search the graph for nodes and edges
|
|
67
|
+
* using the Dependency Selector Syntax (DSS).
|
|
68
|
+
*/
|
|
13
69
|
export declare class Query {
|
|
14
70
|
#private;
|
|
15
71
|
/**
|
|
@@ -18,14 +74,26 @@ export declare class Query {
|
|
|
18
74
|
* skip hydrating the security archive if it's not needed.
|
|
19
75
|
*/
|
|
20
76
|
static hasSecuritySelectors(query: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Sorts an array of QueryResponse objects by specificity. Objects with
|
|
79
|
+
* higher idCounter values come first, if idCounter values are equal,
|
|
80
|
+
* then objects with higher commonCounter values come first. Otherwise,
|
|
81
|
+
* the original order is preserved.
|
|
82
|
+
*/
|
|
83
|
+
static specificitySort(responses: QueryResponse[]): QueryResponse[];
|
|
21
84
|
constructor({ graph, retries, specOptions, securityArchive, }: QueryOptions);
|
|
22
85
|
/**
|
|
23
86
|
* Search the graph for nodes and edges that match the given query.
|
|
24
87
|
*/
|
|
25
|
-
search(query: string, signal
|
|
88
|
+
search(query: string, { signal, scopeIDs, }: SearchOptions): Promise<QueryResponse>;
|
|
26
89
|
/**
|
|
27
90
|
* Parses a query string in order to retrieve an array of tokens.
|
|
28
91
|
*/
|
|
29
92
|
static getQueryTokens(query: string): ParsedSelectorToken[];
|
|
93
|
+
/**
|
|
94
|
+
* Returns an {@link InteractiveBreadcrumb} list of items
|
|
95
|
+
* for a given query string.
|
|
96
|
+
*/
|
|
97
|
+
static getBreadcrumbItems(query: string): InteractiveBreadcrumb;
|
|
30
98
|
}
|
|
31
99
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAY,SAAS,EAAY,MAAM,eAAe,CAAA;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAY,SAAS,EAAY,MAAM,eAAe,CAAA;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAgBnE,OAAO,KAAK,EAEV,mBAAmB,EAEnB,WAAW,EAEX,aAAa,EAGd,MAAM,YAAY,CAAA;AAEnB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,cAAc,YAAY,CAAA;AAE1B,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,WAAW,CAAA;IACnB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAA;CACnB,CAAA;AA+CD,eAAO,MAAM,IAAI,UACR,WAAW,KACjB,OAAO,CAAC,WAAW,CAsDrB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,WAAW,CAAA;IACxB,eAAe,EAAE,mBAAmB,GAAG,SAAS,CAAA;CACjD,CAAA;AAiDD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,yBAAyB,GAAG,SAAS,CAAA;IAC3C,IAAI,EAAE,yBAAyB,GAAG,SAAS,CAAA;IAC3C,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,qBACX,YAAW,QAAQ,CAAC,yBAAyB,CAAC;;IAI9C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAE3B;;OAEG;gBACS,KAAK,EAAE,MAAM;IA0GzB;;OAEG;IACH,IAAI,OAAO,IAAI,yBAAyB,CAEvC;IAED;;OAEG;IACH,IAAI,IAAI,yBAAyB,GAAG,SAAS;IAQ7C;;OAEG;IACH,IAAI,IAAI,yBAAyB,GAAG,SAAS;IAQ7C,CAAC,MAAM,CAAC,QAAQ,CAAC;IAIjB;;OAEG;IACH,KAAK;CAON;AAED;;;GAGG;AACH,qBAAa,KAAK;;IAOhB;;;;OAIG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IASnD;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CACpB,SAAS,EAAE,aAAa,EAAE,GACzB,aAAa,EAAE;gBAqBN,EACV,KAAK,EACL,OAAO,EACP,WAAW,EACX,eAAe,GAChB,EAAE,YAAY;IAuLf;;OAEG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,EACE,MAAM,EACN,QAA0C,GAC3C,EAAE,aAAa,GACf,OAAO,CAAC,aAAa,CAAC;IAmEzB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAoE3D;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;CAGhE"}
|
package/dist/esm/index.js
CHANGED
|
@@ -4,7 +4,8 @@ import { attribute } from "./attribute.js";
|
|
|
4
4
|
import { combinator } from "./combinator.js";
|
|
5
5
|
import { id } from "./id.js";
|
|
6
6
|
import { pseudo } from "./pseudo.js";
|
|
7
|
-
import { isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, isPseudoNode, isIdentifierNode, isAttributeNode, } from "./types.js";
|
|
7
|
+
import { isPostcssNodeWithChildren, asPostcssNodeWithChildren, isSelectorNode, isPseudoNode, isIdentifierNode, isAttributeNode, isCombinatorNode, isCommentNode, } from "./types.js";
|
|
8
|
+
import { joinDepIDTuple } from '@vltpkg/dep-id/browser';
|
|
8
9
|
export * from "./types.js";
|
|
9
10
|
const noopFn = async (state) => state;
|
|
10
11
|
const selectors = {
|
|
@@ -15,7 +16,17 @@ const selectors = {
|
|
|
15
16
|
},
|
|
16
17
|
/* c8 ignore end */
|
|
17
18
|
combinator,
|
|
18
|
-
comment:
|
|
19
|
+
comment: async (state) => {
|
|
20
|
+
if (state.current.value && !state.comment) {
|
|
21
|
+
const commentValue = state.current.value;
|
|
22
|
+
const cleanComment = commentValue
|
|
23
|
+
.replace(/^\/\*/, '')
|
|
24
|
+
.replace(/\*\/$/, '')
|
|
25
|
+
.trim();
|
|
26
|
+
state.comment = cleanComment;
|
|
27
|
+
}
|
|
28
|
+
return state;
|
|
29
|
+
},
|
|
19
30
|
id,
|
|
20
31
|
nesting: noopFn,
|
|
21
32
|
pseudo,
|
|
@@ -124,6 +135,159 @@ const setMethodToJSON = (node) => {
|
|
|
124
135
|
insights,
|
|
125
136
|
});
|
|
126
137
|
};
|
|
138
|
+
/**
|
|
139
|
+
* The InteractiveBreadcrumb class is used to represent a valid breadcrumb.
|
|
140
|
+
*
|
|
141
|
+
* "Breadcrumb" is a term used to describe the subset of the query language
|
|
142
|
+
* that uses only root/workspace selectors, id selectors & combinators.
|
|
143
|
+
*
|
|
144
|
+
* It implements an iterable, doubly-linked list of items that can be used
|
|
145
|
+
* to navigate through the breadcrumb.
|
|
146
|
+
*
|
|
147
|
+
* It also validates that each element of the provided query string is
|
|
148
|
+
* valid according to the previous definition of a "breadcrumb".
|
|
149
|
+
*/
|
|
150
|
+
export class InteractiveBreadcrumb {
|
|
151
|
+
#current;
|
|
152
|
+
#items;
|
|
153
|
+
comment;
|
|
154
|
+
/**
|
|
155
|
+
* Initializes the interactive breadcrumb with a query string.
|
|
156
|
+
*/
|
|
157
|
+
constructor(query) {
|
|
158
|
+
this.#items = [];
|
|
159
|
+
const ast = parse(query);
|
|
160
|
+
// Keep track of the previous AST node for consolidation
|
|
161
|
+
let prevNode;
|
|
162
|
+
// iterates only at the first level of the AST since
|
|
163
|
+
// any nested nodes are invalid syntax
|
|
164
|
+
for (const item of ast.first.nodes) {
|
|
165
|
+
const isWorkspaceOrProject = isPseudoNode(item) &&
|
|
166
|
+
(item.value === ':workspace' || item.value === ':project');
|
|
167
|
+
const allowedPseudoNodes = isPseudoNode(item) &&
|
|
168
|
+
(item.value === ':root' ||
|
|
169
|
+
item.value === ':workspace' ||
|
|
170
|
+
item.value === ':project');
|
|
171
|
+
const allowedTypes = isIdentifierNode(item) ||
|
|
172
|
+
allowedPseudoNodes ||
|
|
173
|
+
(isCombinatorNode(item) && item.value === '>') ||
|
|
174
|
+
isCommentNode(item);
|
|
175
|
+
// Check if this is a nested selector that's not an allowed pseudo
|
|
176
|
+
const isNestedSelector = isPostcssNodeWithChildren(item) &&
|
|
177
|
+
!(allowedPseudoNodes && item.nodes.length === 0);
|
|
178
|
+
// validation, only the root/workspace selectors, id selectors
|
|
179
|
+
// and combinators are valid ast node items
|
|
180
|
+
if (isNestedSelector || !allowedTypes) {
|
|
181
|
+
throw error('Invalid query', { found: item });
|
|
182
|
+
}
|
|
183
|
+
// combinators and comments are skipped
|
|
184
|
+
if (isCombinatorNode(item)) {
|
|
185
|
+
prevNode = undefined;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
else if (isCommentNode(item)) {
|
|
189
|
+
const cleanComment = item.value
|
|
190
|
+
.replace(/^\/\*/, '')
|
|
191
|
+
.replace(/\*\/$/, '')
|
|
192
|
+
.trim();
|
|
193
|
+
this.comment = cleanComment;
|
|
194
|
+
prevNode = undefined;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// check if we need to consolidate with previous item
|
|
198
|
+
const isPrevWorkspaceOrProject = prevNode &&
|
|
199
|
+
isPseudoNode(prevNode) &&
|
|
200
|
+
(prevNode.value === ':workspace' ||
|
|
201
|
+
prevNode.value === ':project');
|
|
202
|
+
const isPrevId = prevNode && isIdentifierNode(prevNode);
|
|
203
|
+
const isCurrentId = isIdentifierNode(item);
|
|
204
|
+
const lastItem = this.#items.length > 0 ?
|
|
205
|
+
this.#items[this.#items.length - 1]
|
|
206
|
+
: null;
|
|
207
|
+
// current node is ID, previous was workspace/project
|
|
208
|
+
if (isCurrentId && isPrevWorkspaceOrProject && lastItem) {
|
|
209
|
+
// Modify the last item to include the ID
|
|
210
|
+
lastItem.value = `${lastItem.value}#${item.value}`;
|
|
211
|
+
prevNode = undefined;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// current node is workspace/project, previous was ID
|
|
215
|
+
if (isWorkspaceOrProject && isPrevId && lastItem) {
|
|
216
|
+
// Modify the last item to include the pseudo
|
|
217
|
+
lastItem.value = `${lastItem.value}${item.value}`;
|
|
218
|
+
lastItem.importer = true;
|
|
219
|
+
prevNode = undefined;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
// Default case: create a new item normally
|
|
223
|
+
const prev = this.#items[this.#items.length - 1];
|
|
224
|
+
const newItem = {
|
|
225
|
+
value: item.value,
|
|
226
|
+
type: item.type,
|
|
227
|
+
prev,
|
|
228
|
+
next: undefined,
|
|
229
|
+
importer: allowedPseudoNodes,
|
|
230
|
+
};
|
|
231
|
+
if (prev) {
|
|
232
|
+
prev.next = newItem;
|
|
233
|
+
}
|
|
234
|
+
this.#items.push(newItem);
|
|
235
|
+
prevNode = item;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// the parsed query should have at least one item
|
|
239
|
+
// that is then going to be set as the current item
|
|
240
|
+
if (!this.#items[0]) {
|
|
241
|
+
throw error('Failed to parse query', {
|
|
242
|
+
found: query,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
this.#current = this.#items[0];
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The current breadcrumb item.
|
|
249
|
+
*/
|
|
250
|
+
get current() {
|
|
251
|
+
return this.#current;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The next breadcrumb item.
|
|
255
|
+
*/
|
|
256
|
+
next() {
|
|
257
|
+
if (!this.#current.next) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
this.#current = this.#current.next;
|
|
261
|
+
return this.#current;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The previous breadcrumb item.
|
|
265
|
+
*/
|
|
266
|
+
prev() {
|
|
267
|
+
if (!this.#current.prev) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
this.#current = this.#current.prev;
|
|
271
|
+
return this.#current;
|
|
272
|
+
}
|
|
273
|
+
[Symbol.iterator]() {
|
|
274
|
+
return this.#items.values();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Empties the current breadcrumb list.
|
|
278
|
+
*/
|
|
279
|
+
clear() {
|
|
280
|
+
for (const item of this.#items) {
|
|
281
|
+
item.prev = undefined;
|
|
282
|
+
item.next = undefined;
|
|
283
|
+
}
|
|
284
|
+
this.#items.length = 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The Query class is used to search the graph for nodes and edges
|
|
289
|
+
* using the Dependency Selector Syntax (DSS).
|
|
290
|
+
*/
|
|
127
291
|
export class Query {
|
|
128
292
|
#cache;
|
|
129
293
|
#graph;
|
|
@@ -143,6 +307,26 @@ export class Query {
|
|
|
143
307
|
}
|
|
144
308
|
return false;
|
|
145
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Sorts an array of QueryResponse objects by specificity. Objects with
|
|
312
|
+
* higher idCounter values come first, if idCounter values are equal,
|
|
313
|
+
* then objects with higher commonCounter values come first. Otherwise,
|
|
314
|
+
* the original order is preserved.
|
|
315
|
+
*/
|
|
316
|
+
static specificitySort(responses) {
|
|
317
|
+
return [...responses].sort((a, b) => {
|
|
318
|
+
// First compare by idCounter (higher comes first)
|
|
319
|
+
if (a.specificity.idCounter !== b.specificity.idCounter) {
|
|
320
|
+
return b.specificity.idCounter - a.specificity.idCounter;
|
|
321
|
+
}
|
|
322
|
+
// If idCounter values are equal, compare by commonCounter
|
|
323
|
+
if (a.specificity.commonCounter !== b.specificity.commonCounter) {
|
|
324
|
+
return (b.specificity.commonCounter - a.specificity.commonCounter);
|
|
325
|
+
}
|
|
326
|
+
// If both counters are equal, preserve original order
|
|
327
|
+
return 0;
|
|
328
|
+
});
|
|
329
|
+
}
|
|
146
330
|
constructor({ graph, retries, specOptions, securityArchive, }) {
|
|
147
331
|
this.#cache = new Map();
|
|
148
332
|
this.#graph = graph;
|
|
@@ -173,10 +357,8 @@ export class Query {
|
|
|
173
357
|
abandoned: securityArchiveEntry.alerts.some(i => i.type === 'missingAuthor'),
|
|
174
358
|
confused: securityArchiveEntry.alerts.some(i => i.type === 'manifestConfusion'),
|
|
175
359
|
cve: securityArchiveEntry.alerts
|
|
176
|
-
.
|
|
177
|
-
|
|
178
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
|
|
179
|
-
.map(i => i.props?.cveId),
|
|
360
|
+
.map(i => i.props?.cveId)
|
|
361
|
+
.filter(i => i !== undefined),
|
|
180
362
|
cwe: Array.from(new Set(securityArchiveEntry.alerts
|
|
181
363
|
.filter(i => i.props?.cveId)
|
|
182
364
|
.flatMap(i => i.props?.cwes?.map(j => j.id)))),
|
|
@@ -236,9 +418,14 @@ export class Query {
|
|
|
236
418
|
/**
|
|
237
419
|
* Search the graph for nodes and edges that match the given query.
|
|
238
420
|
*/
|
|
239
|
-
async search(query, signal) {
|
|
421
|
+
async search(query, { signal, scopeIDs = [joinDepIDTuple(['file', '.'])], }) {
|
|
240
422
|
if (!query)
|
|
241
|
-
return {
|
|
423
|
+
return {
|
|
424
|
+
edges: [],
|
|
425
|
+
nodes: [],
|
|
426
|
+
comment: '',
|
|
427
|
+
specificity: { idCounter: 0, commonCounter: 0 },
|
|
428
|
+
};
|
|
242
429
|
const cachedResult = this.#cache.get(query);
|
|
243
430
|
if (cachedResult) {
|
|
244
431
|
return cachedResult;
|
|
@@ -255,12 +442,12 @@ export class Query {
|
|
|
255
442
|
const loose = asPostcssNodeWithChildren(current).nodes.length > 1;
|
|
256
443
|
// builds initial state and walks over it,
|
|
257
444
|
// retrieving the collected result
|
|
258
|
-
const { collect } = await walk({
|
|
445
|
+
const { collect, comment, specificity } = await walk({
|
|
259
446
|
cancellable: async () => {
|
|
260
447
|
await new Promise(resolve => {
|
|
261
448
|
setTimeout(resolve, 0);
|
|
262
449
|
});
|
|
263
|
-
signal
|
|
450
|
+
signal.throwIfAborted();
|
|
264
451
|
},
|
|
265
452
|
current,
|
|
266
453
|
initial: {
|
|
@@ -271,17 +458,22 @@ export class Query {
|
|
|
271
458
|
nodes: new Set(),
|
|
272
459
|
edges: new Set(),
|
|
273
460
|
},
|
|
461
|
+
comment: '',
|
|
274
462
|
loose,
|
|
275
463
|
partial: { nodes, edges },
|
|
276
464
|
retries: this.#retries,
|
|
277
465
|
signal,
|
|
278
466
|
securityArchive: this.#securityArchive,
|
|
279
467
|
specOptions: this.#specOptions,
|
|
468
|
+
scopeIDs,
|
|
280
469
|
walk,
|
|
470
|
+
specificity: { idCounter: 0, commonCounter: 0 },
|
|
281
471
|
});
|
|
282
472
|
const res = {
|
|
283
473
|
edges: this.#getQueryResponseEdges(collect.edges),
|
|
284
474
|
nodes: this.#getQueryResponseNodes(collect.nodes),
|
|
475
|
+
comment,
|
|
476
|
+
specificity,
|
|
285
477
|
};
|
|
286
478
|
this.#cache.set(query, res);
|
|
287
479
|
return res;
|
|
@@ -347,5 +539,12 @@ export class Query {
|
|
|
347
539
|
processNode(ast(query));
|
|
348
540
|
return tokens;
|
|
349
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Returns an {@link InteractiveBreadcrumb} list of items
|
|
544
|
+
* for a given query string.
|
|
545
|
+
*/
|
|
546
|
+
static getBreadcrumbItems(query) {
|
|
547
|
+
return new InteractiveBreadcrumb(query);
|
|
548
|
+
}
|
|
350
549
|
}
|
|
351
550
|
//# sourceMappingURL=index.js.map
|