@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.
Files changed (38) hide show
  1. package/dist/esm/attribute.d.ts.map +1 -1
  2. package/dist/esm/attribute.js +4 -11
  3. package/dist/esm/attribute.js.map +1 -1
  4. package/dist/esm/id.d.ts.map +1 -1
  5. package/dist/esm/id.js +2 -0
  6. package/dist/esm/id.js.map +1 -1
  7. package/dist/esm/index.d.ts +69 -1
  8. package/dist/esm/index.d.ts.map +1 -1
  9. package/dist/esm/index.js +209 -10
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/pseudo/outdated.d.ts.map +1 -1
  12. package/dist/esm/pseudo/outdated.js +3 -3
  13. package/dist/esm/pseudo/outdated.js.map +1 -1
  14. package/dist/esm/pseudo/published.d.ts.map +1 -1
  15. package/dist/esm/pseudo/published.js +1 -2
  16. package/dist/esm/pseudo/published.js.map +1 -1
  17. package/dist/esm/pseudo/root.d.ts +8 -0
  18. package/dist/esm/pseudo/root.d.ts.map +1 -0
  19. package/dist/esm/pseudo/root.js +22 -0
  20. package/dist/esm/pseudo/root.js.map +1 -0
  21. package/dist/esm/pseudo/semver.d.ts.map +1 -1
  22. package/dist/esm/pseudo/semver.js +2 -1
  23. package/dist/esm/pseudo/semver.js.map +1 -1
  24. package/dist/esm/pseudo/type.d.ts +8 -0
  25. package/dist/esm/pseudo/type.d.ts.map +1 -0
  26. package/dist/esm/pseudo/type.js +22 -0
  27. package/dist/esm/pseudo/type.js.map +1 -0
  28. package/dist/esm/pseudo/workspace.d.ts.map +1 -1
  29. package/dist/esm/pseudo/workspace.js +5 -2
  30. package/dist/esm/pseudo/workspace.js.map +1 -1
  31. package/dist/esm/pseudo.d.ts.map +1 -1
  32. package/dist/esm/pseudo.js +32 -44
  33. package/dist/esm/pseudo.js.map +1 -1
  34. package/dist/esm/types.d.ts +13 -1
  35. package/dist/esm/types.d.ts.map +1 -1
  36. package/dist/esm/types.js +13 -0
  37. package/dist/esm/types.js.map +1 -1
  38. 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;AAE7C,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,WAgDF,CAAA;AAcD,eAAO,MAAM,qBAAqB,2BAEjC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,UACb,WAAW,KACjB,OAAO,CAAC,WAAW,CAyBrB,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"}
@@ -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
- for (const edge of state.partial.edges) {
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"]}
@@ -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,CAiCrB,CAAA"}
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
@@ -29,6 +29,8 @@ export const id = async (state) => {
29
29
  state.partial.nodes.delete(node);
30
30
  }
31
31
  }
32
+ // Increment the idCounter for specificity
33
+ state.specificity.idCounter += 1;
32
34
  return state;
33
35
  };
34
36
  //# sourceMappingURL=id.js.map
@@ -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"]}
@@ -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?: AbortSignal): Promise<QueryResponse>;
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
@@ -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;AAcnE,OAAO,KAAK,EAEV,mBAAmB,EAEnB,WAAW,EAEX,aAAa,EAGd,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAqC1B,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,qBAAa,KAAK;;IAOhB;;;;OAIG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;gBASvC,EACV,KAAK,EACL,OAAO,EACP,WAAW,EACX,eAAe,GAChB,EAAE,YAAY;IAyLf;;OAEG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC;IAwDzB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE;CAmE5D"}
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: noopFn,
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
- .filter(i => i.props?.cveId)
177
- // can not be undefined because of the filter above but TS doesn't know that
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 { edges: [], nodes: [] };
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?.throwIfAborted();
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