@vltpkg/dss-breadcrumb 0.0.0-15 → 0.0.0-16

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.
@@ -1,12 +1,32 @@
1
+ import type { PostcssNode } from '@vltpkg/dss-parser';
1
2
  import type { ModifierBreadcrumb, ModifierBreadcrumbItem, ModifierInteractiveBreadcrumb, BreadcrumbSpecificity } from './types.ts';
2
3
  export * from './types.ts';
4
+ /**
5
+ * The returned pseudo selector parameters object.
6
+ */
7
+ type ParsedPseudoParameters = {
8
+ semverValue?: string;
9
+ };
10
+ /**
11
+ * Helper function to remove quotes from a string value.
12
+ */
13
+ export declare const removeQuotes: (value: string) => string;
14
+ /**
15
+ * Helper function to extract parameter value from pseudo selector nodes.
16
+ */
17
+ export declare const extractPseudoParameter: (item: any) => ParsedPseudoParameters;
18
+ /**
19
+ * Helper function to get the full text representation
20
+ * of a pseudo selector including parameters
21
+ */
22
+ export declare const getPseudoSelectorFullText: (item: PostcssNode) => string;
3
23
  /**
4
24
  * The Breadcrumb class is used to represent a valid breadcrumb
5
25
  * path that helps you traverse a graph and find a specific node or edge.
6
26
  *
7
27
  * Alongside the traditional analogy, "Breadcrumb" is also being used here
8
28
  * as a term used to describe the subset of the query language that uses
9
- * only root/workspace selectors, id selectors & combinators.
29
+ * only pseudo selectors, id selectors & combinators.
10
30
  *
11
31
  * The Breadcrumb class implements a doubly-linked list of items
12
32
  * that can be used to navigate through the breadcrumb.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAE1B;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IAEnD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,WAAW,EAAE,qBAAqB,CAAA;IAElC;;OAEG;gBACS,KAAK,EAAE,MAAM;IA8HzB;;OAEG;IACH,IAAI,KAAK,IAAI,sBAAsB,CAKlC;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,sBAAsB,CAMjC;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC;IAIjB;;OAEG;IACH,KAAK;IAQL;;;OAGG;IACH,WAAW;CAGZ;AAED;;;GAGG;AACH,qBAAa,qBACX,YAAW,6BAA6B;;gBAG5B,UAAU,EAAE,UAAU;IAIlC;;OAEG;IACH,IAAI,OAAO,IAAI,sBAAsB,GAAG,SAAS,CAEhD;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI;CAIb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,KAAG,kBACzB,CAAA;AAEvB;;;;;GAKG;AACH,eAAO,MAAM,eAAe,gBACb,kBAAkB,EAAE,KAChC,kBAAkB,EAepB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGrD,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EAGtB,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAE1B;;GAEG;AACH,KAAK,sBAAsB,GAAG;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AA4CD;;GAEG;AACH,eAAO,MAAM,YAAY,UAAW,MAAM,WACR,CAAA;AAElC;;GAEG;AACH,eAAO,MAAM,sBAAsB,SAC3B,GAAG,KACR,sBA4BF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,SAC9B,WAAW,KAChB,MA0BF,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IAEnD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,WAAW,EAAE,qBAAqB,CAAA;IAElC;;OAEG;gBAES,KAAK,EAAE,MAAM;IA6JzB;;OAEG;IACH,IAAI,KAAK,IAAI,sBAAsB,CAKlC;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,sBAAsB,CAMjC;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC;IAIjB;;OAEG;IACH,KAAK;IAQL;;;OAGG;IACH,WAAW;CAGZ;AAED;;;GAGG;AACH,qBAAa,qBACX,YAAW,6BAA6B;;gBAG5B,UAAU,EAAE,UAAU;IAIlC;;OAEG;IACH,IAAI,OAAO,IAAI,sBAAsB,GAAG,SAAS,CAEhD;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAElB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI;CAIb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,KAAG,kBACzB,CAAA;AAEvB;;;;;GAKG;AACH,eAAO,MAAM,eAAe,gBACb,kBAAkB,EAAE,KAChC,kBAAkB,EAepB,CAAA"}
package/dist/esm/index.js CHANGED
@@ -1,13 +1,103 @@
1
- import { isPostcssNodeWithChildren, isPseudoNode, isIdentifierNode, isCombinatorNode, isCommentNode, parse, } from '@vltpkg/dss-parser';
1
+ import { isPostcssNodeWithChildren, isPseudoNode, isIdentifierNode, isCombinatorNode, isCommentNode, isStringNode, isTagNode, asStringNode, asTagNode, parse, asPostcssNodeWithChildren, } from '@vltpkg/dss-parser';
2
2
  import { error } from '@vltpkg/error-cause';
3
+ import { intersects } from '@vltpkg/semver';
3
4
  export * from "./types.js";
5
+ /**
6
+ * A comparator function that always returns true.
7
+ */
8
+ const passthroughComparator = () => () => true;
9
+ /**
10
+ * A comparator function for semver pseudo selectors.
11
+ */
12
+ const semverComparator = ({ range }) => ({ semver }) => {
13
+ if (range && semver) {
14
+ return intersects(semver, range);
15
+ }
16
+ return false;
17
+ };
18
+ /**
19
+ * A map of pseudo selectors to their comparator functions.
20
+ */
21
+ const pseudoSelectors = new Map([
22
+ [':semver', semverComparator],
23
+ [':v', semverComparator],
24
+ ]);
25
+ /**
26
+ * The subset of importer pseudo selectors that are supported.
27
+ */
28
+ const importerNames = new Set([':project', ':workspace', ':root']);
29
+ // Add importer pseudo selectors to the list of supported selectors
30
+ for (const importerName of importerNames) {
31
+ pseudoSelectors.set(importerName, passthroughComparator);
32
+ }
33
+ /**
34
+ * Helper function to remove quotes from a string value.
35
+ */
36
+ export const removeQuotes = (value) => value.replace(/^"(.*?)"$/, '$1');
37
+ /**
38
+ * Helper function to extract parameter value from pseudo selector nodes.
39
+ */
40
+ export const extractPseudoParameter = (item) => {
41
+ if (!isPostcssNodeWithChildren(item) || !item.nodes[0]) {
42
+ return {};
43
+ }
44
+ let first;
45
+ try {
46
+ // Try to parse as string node first (quoted values)
47
+ const firstNode = asPostcssNodeWithChildren(item.nodes[0])
48
+ .nodes[0];
49
+ if (isStringNode(firstNode)) {
50
+ first = removeQuotes(firstNode.value);
51
+ }
52
+ // Handle tag node (unquoted values)
53
+ if (isTagNode(firstNode)) {
54
+ first = asTagNode(firstNode).value;
55
+ }
56
+ }
57
+ catch { }
58
+ if (item.value === ':semver' || item.value === ':v') {
59
+ return {
60
+ semverValue: first,
61
+ };
62
+ }
63
+ return {};
64
+ };
65
+ /**
66
+ * Helper function to get the full text representation
67
+ * of a pseudo selector including parameters
68
+ */
69
+ export const getPseudoSelectorFullText = (item) => {
70
+ if (!isPostcssNodeWithChildren(item) || !item.nodes[0]) {
71
+ return item.value || '';
72
+ }
73
+ const baseValue = item.value;
74
+ const paramNode = item.nodes[0];
75
+ let paramText = '';
76
+ if (isPostcssNodeWithChildren(paramNode)) {
77
+ // reconstruct the parameter by combining all child nodes
78
+ paramText = paramNode.nodes
79
+ .map(node => {
80
+ if (isStringNode(node)) {
81
+ return asStringNode(node).value;
82
+ }
83
+ else if (isTagNode(node)) {
84
+ return asTagNode(node).value;
85
+ }
86
+ else {
87
+ return node.value;
88
+ }
89
+ })
90
+ .join('');
91
+ }
92
+ return `${baseValue}(${paramText})`;
93
+ };
4
94
  /**
5
95
  * The Breadcrumb class is used to represent a valid breadcrumb
6
96
  * path that helps you traverse a graph and find a specific node or edge.
7
97
  *
8
98
  * Alongside the traditional analogy, "Breadcrumb" is also being used here
9
99
  * as a term used to describe the subset of the query language that uses
10
- * only root/workspace selectors, id selectors & combinators.
100
+ * only pseudo selectors, id selectors & combinators.
11
101
  *
12
102
  * The Breadcrumb class implements a doubly-linked list of items
13
103
  * that can be used to navigate through the breadcrumb.
@@ -29,32 +119,34 @@ export class Breadcrumb {
29
119
  this.#items = [];
30
120
  this.specificity = { idCounter: 0, commonCounter: 0 };
31
121
  const ast = parse(query);
32
- // Keep track of the previous AST node for consolidation
33
- let prevNode;
34
- // iterates only at the first level of the AST since
35
- // any nested nodes are invalid syntax
122
+ // Track whether we encountered a combinator since the last item
123
+ let afterCombinator = true;
124
+ // iterates only at the first level of the AST since any
125
+ // pseudo selectors that relies on nested nodes are invalid syntax
36
126
  for (const item of ast.first.nodes) {
37
- const isWorkspaceOrProject = isPseudoNode(item) &&
38
- (item.value === ':workspace' || item.value === ':project');
39
- const allowedPseudoNodes = isPseudoNode(item) &&
40
- (item.value === ':root' ||
41
- item.value === ':workspace' ||
42
- item.value === ':project');
127
+ const pseudoNode = isPseudoNode(item);
128
+ // checks for only supported pseudo selectors
129
+ if (pseudoNode && !pseudoSelectors.has(item.value)) {
130
+ throw error('Invalid pseudo selector', {
131
+ found: item.value,
132
+ });
133
+ }
43
134
  const allowedTypes = isIdentifierNode(item) ||
44
- allowedPseudoNodes ||
135
+ pseudoNode ||
45
136
  (isCombinatorNode(item) && item.value === '>') ||
46
137
  isCommentNode(item);
47
- // Check if this is a nested selector that's not an allowed pseudo
48
- const isNestedSelector = isPostcssNodeWithChildren(item) &&
49
- !(allowedPseudoNodes && item.nodes.length === 0);
50
- // validation, only the root/workspace selectors, id selectors
138
+ const hasChildren = isPostcssNodeWithChildren(item) && item.nodes.length > 0;
139
+ const semverNode = pseudoNode &&
140
+ (item.value === ':semver' || item.value === ':v');
141
+ // validation, only pseudo selectors, id selectors
51
142
  // and combinators are valid ast node items
52
- if (isNestedSelector || !allowedTypes) {
143
+ // pseudo selectors are allowed to have children (parameters)
144
+ if ((hasChildren && !pseudoNode) || !allowedTypes) {
53
145
  throw error('Invalid query', { found: query });
54
146
  }
55
147
  // combinators and comments are skipped
56
148
  if (isCombinatorNode(item)) {
57
- prevNode = undefined;
149
+ afterCombinator = true;
58
150
  continue;
59
151
  }
60
152
  else if (isCommentNode(item)) {
@@ -63,53 +155,77 @@ export class Breadcrumb {
63
155
  .replace(/\*\/$/, '')
64
156
  .trim();
65
157
  this.comment = cleanComment;
66
- prevNode = undefined;
158
+ afterCombinator = true;
67
159
  }
68
160
  else {
69
- // check if we need to consolidate with previous item
70
- const isPrevWorkspaceOrProject = prevNode &&
71
- isPseudoNode(prevNode) &&
72
- (prevNode.value === ':workspace' ||
73
- prevNode.value === ':project');
74
- const isPrevId = prevNode && isIdentifierNode(prevNode);
75
- const isCurrentId = isIdentifierNode(item);
76
161
  // we define the last item as we iterate through the list of
77
162
  // breadcrumb items so that this value can also be used to
78
163
  // update previous items when needed
79
164
  const lastItem = this.#items.length > 0 ?
80
165
  this.#items[this.#items.length - 1]
81
166
  : undefined;
82
- // current node is ID, previous was workspace/project
83
- // we fold the current node value into the same object
84
- // and move on to the next ast item
85
- if (isCurrentId && isPrevWorkspaceOrProject && lastItem) {
86
- // Modify the last item to include the ID
87
- lastItem.name = item.value;
88
- lastItem.value = `${lastItem.value}#${item.value}`;
89
- // Update specificity for the ID part
90
- this.specificity.idCounter++;
91
- prevNode = undefined;
167
+ // Extract parameter before potential consolidation
168
+ const providedRange = (pseudoNode &&
169
+ (item.value === ':semver' || item.value === ':v')) ?
170
+ (extractPseudoParameter(item).semverValue ?? '')
171
+ : '';
172
+ // get the comparator function for a given pseudo selector item
173
+ const internalOptions = {
174
+ ...(semverNode ? { range: providedRange } : {}),
175
+ };
176
+ const comparator = (pseudoSelectors.get(item.value) ?? passthroughComparator)(internalOptions);
177
+ // If we have a previous item and we haven't encountered a combinator
178
+ // since then, consolidate with the previous item
179
+ if (lastItem && !afterCombinator) {
180
+ // Check for invalid chained pseudo selectors
181
+ if (pseudoNode && isPseudoNode(lastItem)) {
182
+ throw error('Invalid query', { found: query });
183
+ }
184
+ // determine how to combine the values based on selector types
185
+ let currentValue = item.value;
186
+ if (item.type === 'id') {
187
+ currentValue = `#${item.value}`;
188
+ }
189
+ else if (pseudoNode) {
190
+ currentValue = getPseudoSelectorFullText(item);
191
+ }
192
+ lastItem.value = `${lastItem.value}${currentValue}`;
193
+ // if current item is an ID, update the name property
194
+ if (isIdentifierNode(item)) {
195
+ lastItem.name = item.value;
196
+ }
197
+ // Handle comparator and importer when consolidating with pseudo node
198
+ if (pseudoNode) {
199
+ const lastItemComparator = lastItem.comparator;
200
+ lastItem.comparator = (opts) => comparator(opts) && lastItemComparator(opts);
201
+ lastItem.importer ||= importerNames.has(item.value);
202
+ }
203
+ // update specificity counters
204
+ if (isIdentifierNode(item)) {
205
+ this.specificity.idCounter++;
206
+ }
207
+ else if (pseudoNode) {
208
+ this.specificity.commonCounter++;
209
+ }
210
+ afterCombinator = false;
92
211
  continue;
93
212
  }
94
- // current node is workspace/project, previous was ID
95
- // we fold the current node value into the same object
96
- // and move on to the next ast item
97
- if (isWorkspaceOrProject && isPrevId && lastItem) {
98
- // Modify the last item to include the pseudo
99
- lastItem.value = `${lastItem.value}${item.value}`;
100
- lastItem.importer = true;
101
- // Update specificity for the pseudo part
102
- this.specificity.commonCounter++;
103
- prevNode = undefined;
104
- continue;
213
+ // Create a new breadcrumb item
214
+ let itemValue = item.value;
215
+ if (item.type === 'id') {
216
+ itemValue = `#${item.value}`;
217
+ }
218
+ else if (pseudoNode) {
219
+ itemValue = getPseudoSelectorFullText(item);
105
220
  }
106
221
  const newItem = {
107
- value: item.type === 'id' ? `#${item.value}` : item.value,
222
+ comparator,
223
+ value: itemValue,
108
224
  name: item.type === 'id' ? item.value : undefined,
109
225
  type: item.type,
110
226
  prev: lastItem,
111
227
  next: undefined,
112
- importer: allowedPseudoNodes,
228
+ importer: pseudoNode && importerNames.has(item.value),
113
229
  };
114
230
  if (lastItem) {
115
231
  lastItem.next = newItem;
@@ -119,10 +235,10 @@ export class Breadcrumb {
119
235
  if (isIdentifierNode(item)) {
120
236
  this.specificity.idCounter++;
121
237
  }
122
- else if (isPseudoNode(item)) {
238
+ else if (pseudoNode) {
123
239
  this.specificity.commonCounter++;
124
240
  }
125
- prevNode = item;
241
+ afterCombinator = false;
126
242
  }
127
243
  }
128
244
  // the parsed query should have at least one item
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isPostcssNodeWithChildren,\n isPseudoNode,\n isIdentifierNode,\n isCombinatorNode,\n isCommentNode,\n parse,\n} from '@vltpkg/dss-parser'\nimport { error } from '@vltpkg/error-cause'\nimport type { PostcssNode } from '@vltpkg/dss-parser'\nimport type {\n ModifierBreadcrumb,\n ModifierBreadcrumbItem,\n ModifierInteractiveBreadcrumb,\n BreadcrumbSpecificity,\n} from './types.ts'\n\nexport * from './types.ts'\n\n/**\n * The Breadcrumb class is used to represent a valid breadcrumb\n * path that helps you traverse a graph and find a specific node or edge.\n *\n * Alongside the traditional analogy, \"Breadcrumb\" is also being used here\n * as a term used to describe the subset of the query language that uses\n * only root/workspace selectors, id selectors & combinators.\n *\n * The Breadcrumb class implements a doubly-linked list of items\n * that can be used to navigate through the breadcrumb.\n * The InteractiveBreadcrumb can also be used to keep track of state\n * of the current breadcrumb item that should be used for checks.\n *\n * It also validates that each element of the provided query string is\n * valid according to the previous definition of a \"Breadcrumb\" query\n * language subset.\n */\nexport class Breadcrumb implements ModifierBreadcrumb {\n #items: ModifierBreadcrumbItem[]\n comment: string | undefined\n specificity: BreadcrumbSpecificity\n\n /**\n * Initializes the interactive breadcrumb with a query string.\n */\n constructor(query: string) {\n this.#items = []\n this.specificity = { idCounter: 0, commonCounter: 0 }\n const ast = parse(query)\n\n // Keep track of the previous AST node for consolidation\n let prevNode: PostcssNode | undefined\n\n // iterates only at the first level of the AST since\n // any nested nodes are invalid syntax\n for (const item of ast.first.nodes) {\n const isWorkspaceOrProject =\n isPseudoNode(item) &&\n (item.value === ':workspace' || item.value === ':project')\n\n const allowedPseudoNodes =\n isPseudoNode(item) &&\n (item.value === ':root' ||\n item.value === ':workspace' ||\n item.value === ':project')\n\n const allowedTypes =\n isIdentifierNode(item) ||\n allowedPseudoNodes ||\n (isCombinatorNode(item) && item.value === '>') ||\n isCommentNode(item)\n\n // Check if this is a nested selector that's not an allowed pseudo\n const isNestedSelector =\n isPostcssNodeWithChildren(item) &&\n !(allowedPseudoNodes && item.nodes.length === 0)\n\n // validation, only the root/workspace selectors, id selectors\n // and combinators are valid ast node items\n if (isNestedSelector || !allowedTypes) {\n throw error('Invalid query', { found: query })\n }\n\n // combinators and comments are skipped\n if (isCombinatorNode(item)) {\n prevNode = undefined\n continue\n } else if (isCommentNode(item)) {\n const cleanComment = item.value\n .replace(/^\\/\\*/, '')\n .replace(/\\*\\/$/, '')\n .trim()\n this.comment = cleanComment\n prevNode = undefined\n } else {\n // check if we need to consolidate with previous item\n const isPrevWorkspaceOrProject =\n prevNode &&\n isPseudoNode(prevNode) &&\n (prevNode.value === ':workspace' ||\n prevNode.value === ':project')\n\n const isPrevId = prevNode && isIdentifierNode(prevNode)\n const isCurrentId = isIdentifierNode(item)\n\n // we define the last item as we iterate through the list of\n // breadcrumb items so that this value can also be used to\n // update previous items when needed\n const lastItem =\n this.#items.length > 0 ?\n this.#items[this.#items.length - 1]\n : undefined\n\n // current node is ID, previous was workspace/project\n // we fold the current node value into the same object\n // and move on to the next ast item\n if (isCurrentId && isPrevWorkspaceOrProject && lastItem) {\n // Modify the last item to include the ID\n lastItem.name = item.value\n lastItem.value = `${lastItem.value}#${item.value}`\n // Update specificity for the ID part\n this.specificity.idCounter++\n prevNode = undefined\n continue\n }\n\n // current node is workspace/project, previous was ID\n // we fold the current node value into the same object\n // and move on to the next ast item\n if (isWorkspaceOrProject && isPrevId && lastItem) {\n // Modify the last item to include the pseudo\n lastItem.value = `${lastItem.value}${item.value}`\n lastItem.importer = true\n // Update specificity for the pseudo part\n this.specificity.commonCounter++\n prevNode = undefined\n continue\n }\n\n const newItem = {\n value: item.type === 'id' ? `#${item.value}` : item.value,\n name: item.type === 'id' ? item.value : undefined,\n type: item.type,\n prev: lastItem,\n next: undefined,\n importer: allowedPseudoNodes,\n }\n if (lastItem) {\n lastItem.next = newItem\n }\n this.#items.push(newItem)\n\n // Update specificity counters\n if (isIdentifierNode(item)) {\n this.specificity.idCounter++\n } else if (isPseudoNode(item)) {\n this.specificity.commonCounter++\n }\n\n prevNode = item\n }\n }\n // the parsed query should have at least one item\n // that is then going to be set as the current item\n if (!this.#items[0]) {\n throw error('Failed to parse query', {\n found: query,\n })\n }\n }\n\n /**\n * Retrieves the first breadcrumb item.\n */\n get first(): ModifierBreadcrumbItem {\n if (!this.#items[0]) {\n throw error('Failed to find first breadcrumb item')\n }\n return this.#items[0]\n }\n\n /**\n * Retrieves the last breadcrumb item.\n */\n get last(): ModifierBreadcrumbItem {\n const lastItem = this.#items[this.#items.length - 1]\n if (!lastItem) {\n throw error('Failed to find first breadcrumb item')\n }\n return lastItem\n }\n\n /**\n * Returns `true` if the breadcrumb is composed of a single item.\n */\n get single(): boolean {\n return this.#items.length === 1\n }\n\n [Symbol.iterator]() {\n return this.#items.values()\n }\n\n /**\n * Empties the current breadcrumb list.\n */\n clear() {\n for (const item of this.#items) {\n item.prev = undefined\n item.next = undefined\n }\n this.#items.length = 0\n }\n\n /**\n * Gets an {@link InteractiveBreadcrumb} instance that can be\n * used to track state of the current breadcrumb item.\n */\n interactive() {\n return new InteractiveBreadcrumb(this)\n }\n}\n\n/**\n * The InteractiveBreadcrumb is used to keep track of state\n * of the current breadcrumb item that should be used for checks.\n */\nexport class InteractiveBreadcrumb\n implements ModifierInteractiveBreadcrumb\n{\n #current: ModifierBreadcrumbItem | undefined\n constructor(breadcrumb: Breadcrumb) {\n this.#current = breadcrumb.first\n }\n\n /**\n * The current breadcrumb item.\n */\n get current(): ModifierBreadcrumbItem | undefined {\n return this.#current\n }\n\n /**\n * Returns `true` if the current breadcrumb has no more items left.\n */\n get done(): boolean {\n return !this.#current\n }\n\n /**\n * The next breadcrumb item.\n */\n next(): this {\n this.#current = this.#current?.next\n return this\n }\n}\n\n/**\n * Returns an {@link Breadcrumb} list of items\n * for a given query string.\n */\nexport const parseBreadcrumb = (query: string): ModifierBreadcrumb =>\n new Breadcrumb(query)\n\n/**\n * Sorts an array of Breadcrumb objects by specificity. Objects with\n * higher idCounter values come first, if idCounter values are equal,\n * then objects with higher commonCounter values come first. Otherwise,\n * the original order is preserved.\n */\nexport const specificitySort = (\n breadcrumbs: ModifierBreadcrumb[],\n): ModifierBreadcrumb[] => {\n return [...breadcrumbs].sort((a, b) => {\n // First compare by idCounter (higher comes first)\n if (a.specificity.idCounter !== b.specificity.idCounter) {\n return b.specificity.idCounter - a.specificity.idCounter\n }\n\n // If idCounter values are equal, compare by commonCounter\n if (a.specificity.commonCounter !== b.specificity.commonCounter) {\n return b.specificity.commonCounter - a.specificity.commonCounter\n }\n\n // If both counters are equal, preserve original order\n return 0\n })\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,KAAK,EACL,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAU3C,cAAc,YAAY,CAAA;AAgB1B;;GAEG;AACH,MAAM,qBAAqB,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAA;AAE9C;;GAEG;AACH,MAAM,gBAAgB,GACpB,CAAC,EAAE,KAAK,EAAqC,EAAE,EAAE,CACjD,CAAC,EAAE,MAAM,EAA6B,EAAE,EAAE;IACxC,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;QACpB,OAAO,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAEH;;GAEG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAsC;IACnE,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAC7B,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACzB,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAA;AAElE,mEAAmE;AACnE,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;IACzC,eAAe,CAAC,GAAG,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAA;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAE,CAC5C,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,IAAS,EACe,EAAE;IAC1B,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,KAAK,CAAA;IACT,IAAI,CAAC;QACH,oDAAoD;QACpD,MAAM,SAAS,GAAG,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aACvD,KAAK,CAAC,CAAC,CAAC,CAAA;QAEX,IAAI,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QACvC,CAAC;QAED,oCAAoC;QACpC,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YACzB,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,KAAK,CAAA;QACpC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACpD,OAAO;YACL,WAAW,EAAE,KAAK;SACnB,CAAA;IACH,CAAC;IAED,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,IAAiB,EACT,EAAE;IACV,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAA;IAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAE/B,IAAI,SAAS,GAAG,EAAE,CAAA;IAElB,IAAI,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,yDAAyD;QACzD,SAAS,GAAG,SAAS,CAAC,KAAK;aACxB,GAAG,CAAC,IAAI,CAAC,EAAE;YACV,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAA;YACjC,CAAC;iBAAM,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAA;YAC9B,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAC,KAAK,CAAA;YACnB,CAAC;QACH,CAAC,CAAC;aACD,IAAI,CAAC,EAAE,CAAC,CAAA;IACb,CAAC;IAED,OAAO,GAAG,SAAS,IAAI,SAAS,GAAG,CAAA;AACrC,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,UAAU;IACrB,MAAM,CAA0B;IAChC,OAAO,CAAoB;IAC3B,WAAW,CAAuB;IAElC;;OAEG;IAEH,YAAY,KAAa;QACvB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAA;QACrD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QAExB,gEAAgE;QAChE,IAAI,eAAe,GAAG,IAAI,CAAA;QAE1B,wDAAwD;QACxD,kEAAkE;QAClE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;YAErC,6CAA6C;YAC7C,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnD,MAAM,KAAK,CAAC,yBAAyB,EAAE;oBACrC,KAAK,EAAE,IAAI,CAAC,KAAK;iBAClB,CAAC,CAAA;YACJ,CAAC;YAED,MAAM,YAAY,GAChB,gBAAgB,CAAC,IAAI,CAAC;gBACtB,UAAU;gBACV,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC;gBAC9C,aAAa,CAAC,IAAI,CAAC,CAAA;YACrB,MAAM,WAAW,GACf,yBAAyB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;YAC1D,MAAM,UAAU,GACd,UAAU;gBACV,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAA;YAEnD,kDAAkD;YAClD,2CAA2C;YAC3C,6DAA6D;YAC7D,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClD,MAAM,KAAK,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;YAChD,CAAC;YAED,uCAAuC;YACvC,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,eAAe,GAAG,IAAI,CAAA;gBACtB,SAAQ;YACV,CAAC;iBAAM,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK;qBAC5B,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;qBACpB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;qBACpB,IAAI,EAAE,CAAA;gBACT,IAAI,CAAC,OAAO,GAAG,YAAY,CAAA;gBAC3B,eAAe,GAAG,IAAI,CAAA;YACxB,CAAC;iBAAM,CAAC;gBACN,4DAA4D;gBAC5D,0DAA0D;gBAC1D,oCAAoC;gBACpC,MAAM,QAAQ,GACZ,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;oBACrC,CAAC,CAAC,SAAS,CAAA;gBAEb,mDAAmD;gBACnD,MAAM,aAAa,GACjB,CACE,UAAU;oBACV,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAClD,CAAC,CAAC;oBACD,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;oBAClD,CAAC,CAAC,EAAE,CAAA;gBAEN,+DAA+D;gBAC/D,MAAM,eAAe,GAAsC;oBACzD,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChD,CAAA;gBACD,MAAM,UAAU,GAAG,CACjB,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,qBAAqB,CACzD,CAAC,eAAe,CAAC,CAAA;gBAElB,qEAAqE;gBACrE,iDAAiD;gBACjD,IAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,CAAC;oBACjC,6CAA6C;oBAC7C,IAAI,UAAU,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACzC,MAAM,KAAK,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;oBAChD,CAAC;oBAED,8DAA8D;oBAC9D,IAAI,YAAY,GAAW,IAAI,CAAC,KAAK,CAAA;oBACrC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;wBACvB,YAAY,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,CAAA;oBACjC,CAAC;yBAAM,IAAI,UAAU,EAAE,CAAC;wBACtB,YAAY,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAA;oBAChD,CAAC;oBACD,QAAQ,CAAC,KAAK,GAAG,GAAG,QAAQ,CAAC,KAAK,GAAG,YAAY,EAAE,CAAA;oBAEnD,qDAAqD;oBACrD,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC3B,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAA;oBAC5B,CAAC;oBAED,qEAAqE;oBACrE,IAAI,UAAU,EAAE,CAAC;wBACf,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAA;wBAC9C,QAAQ,CAAC,UAAU,GAAG,CAAC,IAA+B,EAAE,EAAE,CACxD,UAAU,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAA;wBAC9C,QAAQ,CAAC,QAAQ,KAAK,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;oBACrD,CAAC;oBAED,8BAA8B;oBAC9B,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC3B,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAA;oBAC9B,CAAC;yBAAM,IAAI,UAAU,EAAE,CAAC;wBACtB,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAA;oBAClC,CAAC;oBAED,eAAe,GAAG,KAAK,CAAA;oBACvB,SAAQ;gBACV,CAAC;gBAED,+BAA+B;gBAC/B,IAAI,SAAS,GAAW,IAAI,CAAC,KAAK,CAAA;gBAClC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;oBACvB,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,CAAA;gBAC9B,CAAC;qBAAM,IAAI,UAAU,EAAE,CAAC;oBACtB,SAAS,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAA;gBAC7C,CAAC;gBAED,MAAM,OAAO,GAAG;oBACd,UAAU;oBACV,KAAK,EAAE,SAAS;oBAChB,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;oBACjD,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,SAAS;oBACf,QAAQ,EAAE,UAAU,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;iBACtD,CAAA;gBACD,IAAI,QAAQ,EAAE,CAAC;oBACb,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAA;gBACzB,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBAEzB,8BAA8B;gBAC9B,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3B,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAA;gBAC9B,CAAC;qBAAM,IAAI,UAAU,EAAE,CAAC;oBACtB,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAA;gBAClC,CAAC;gBAED,eAAe,GAAG,KAAK,CAAA;YACzB,CAAC;QACH,CAAC;QACD,iDAAiD;QACjD,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,MAAM,KAAK,CAAC,uBAAuB,EAAE;gBACnC,KAAK,EAAE,KAAK;aACb,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI,KAAK;QACP,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,MAAM,KAAK,CAAC,sCAAsC,CAAC,CAAA;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,KAAK,CAAC,sCAAsC,CAAC,CAAA;QACrD,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;OAEG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAA;IACjC,CAAC;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAA;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,GAAG,SAAS,CAAA;YACrB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAA;QACvB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;IACxB,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,qBAAqB;IAGhC,QAAQ,CAAoC;IAC5C,YAAY,UAAsB;QAChC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAA;IAClC,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAA;IACvB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAA;QACnC,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAa,EAAsB,EAAE,CACnE,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;AAEvB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,WAAiC,EACX,EAAE;IACxB,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACpC,kDAAkD;QAClD,IAAI,CAAC,CAAC,WAAW,CAAC,SAAS,KAAK,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;YACxD,OAAO,CAAC,CAAC,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,SAAS,CAAA;QAC1D,CAAC;QAED,0DAA0D;QAC1D,IAAI,CAAC,CAAC,WAAW,CAAC,aAAa,KAAK,CAAC,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC;YAChE,OAAO,CAAC,CAAC,WAAW,CAAC,aAAa,GAAG,CAAC,CAAC,WAAW,CAAC,aAAa,CAAA;QAClE,CAAC;QAED,sDAAsD;QACtD,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import {\n isPostcssNodeWithChildren,\n isPseudoNode,\n isIdentifierNode,\n isCombinatorNode,\n isCommentNode,\n isStringNode,\n isTagNode,\n asStringNode,\n asTagNode,\n parse,\n asPostcssNodeWithChildren,\n} from '@vltpkg/dss-parser'\nimport type { PostcssNode } from '@vltpkg/dss-parser'\nimport { error } from '@vltpkg/error-cause'\nimport { intersects } from '@vltpkg/semver'\nimport type {\n ModifierBreadcrumb,\n ModifierBreadcrumbItem,\n ModifierInteractiveBreadcrumb,\n BreadcrumbSpecificity,\n ModifierComparatorOptions,\n InternalModifierComparatorOptions,\n} from './types.ts'\n\nexport * from './types.ts'\n\n/**\n * The returned pseudo selector parameters object.\n */\ntype ParsedPseudoParameters = {\n semverValue?: string\n}\n\n/**\n * The higher level function for pseudo selectors comparators.\n */\ntype PseudoSelectorsComparatorFn = (\n internal: InternalModifierComparatorOptions,\n) => (opts: ModifierComparatorOptions) => boolean\n\n/**\n * A comparator function that always returns true.\n */\nconst passthroughComparator = () => () => true\n\n/**\n * A comparator function for semver pseudo selectors.\n */\nconst semverComparator =\n ({ range }: InternalModifierComparatorOptions) =>\n ({ semver }: ModifierComparatorOptions) => {\n if (range && semver) {\n return intersects(semver, range)\n }\n return false\n }\n\n/**\n * A map of pseudo selectors to their comparator functions.\n */\nconst pseudoSelectors = new Map<string, PseudoSelectorsComparatorFn>([\n [':semver', semverComparator],\n [':v', semverComparator],\n])\n\n/**\n * The subset of importer pseudo selectors that are supported.\n */\nconst importerNames = new Set([':project', ':workspace', ':root'])\n\n// Add importer pseudo selectors to the list of supported selectors\nfor (const importerName of importerNames) {\n pseudoSelectors.set(importerName, passthroughComparator)\n}\n\n/**\n * Helper function to remove quotes from a string value.\n */\nexport const removeQuotes = (value: string) =>\n value.replace(/^\"(.*?)\"$/, '$1')\n\n/**\n * Helper function to extract parameter value from pseudo selector nodes.\n */\nexport const extractPseudoParameter = (\n item: any,\n): ParsedPseudoParameters => {\n if (!isPostcssNodeWithChildren(item) || !item.nodes[0]) {\n return {}\n }\n\n let first\n try {\n // Try to parse as string node first (quoted values)\n const firstNode = asPostcssNodeWithChildren(item.nodes[0])\n .nodes[0]\n\n if (isStringNode(firstNode)) {\n first = removeQuotes(firstNode.value)\n }\n\n // Handle tag node (unquoted values)\n if (isTagNode(firstNode)) {\n first = asTagNode(firstNode).value\n }\n } catch {}\n\n if (item.value === ':semver' || item.value === ':v') {\n return {\n semverValue: first,\n }\n }\n\n return {}\n}\n\n/**\n * Helper function to get the full text representation\n * of a pseudo selector including parameters\n */\nexport const getPseudoSelectorFullText = (\n item: PostcssNode,\n): string => {\n if (!isPostcssNodeWithChildren(item) || !item.nodes[0]) {\n return item.value || ''\n }\n\n const baseValue = item.value\n const paramNode = item.nodes[0]\n\n let paramText = ''\n\n if (isPostcssNodeWithChildren(paramNode)) {\n // reconstruct the parameter by combining all child nodes\n paramText = paramNode.nodes\n .map(node => {\n if (isStringNode(node)) {\n return asStringNode(node).value\n } else if (isTagNode(node)) {\n return asTagNode(node).value\n } else {\n return node.value\n }\n })\n .join('')\n }\n\n return `${baseValue}(${paramText})`\n}\n\n/**\n * The Breadcrumb class is used to represent a valid breadcrumb\n * path that helps you traverse a graph and find a specific node or edge.\n *\n * Alongside the traditional analogy, \"Breadcrumb\" is also being used here\n * as a term used to describe the subset of the query language that uses\n * only pseudo selectors, id selectors & combinators.\n *\n * The Breadcrumb class implements a doubly-linked list of items\n * that can be used to navigate through the breadcrumb.\n * The InteractiveBreadcrumb can also be used to keep track of state\n * of the current breadcrumb item that should be used for checks.\n *\n * It also validates that each element of the provided query string is\n * valid according to the previous definition of a \"Breadcrumb\" query\n * language subset.\n */\nexport class Breadcrumb implements ModifierBreadcrumb {\n #items: ModifierBreadcrumbItem[]\n comment: string | undefined\n specificity: BreadcrumbSpecificity\n\n /**\n * Initializes the interactive breadcrumb with a query string.\n */\n\n constructor(query: string) {\n this.#items = []\n this.specificity = { idCounter: 0, commonCounter: 0 }\n const ast = parse(query)\n\n // Track whether we encountered a combinator since the last item\n let afterCombinator = true\n\n // iterates only at the first level of the AST since any\n // pseudo selectors that relies on nested nodes are invalid syntax\n for (const item of ast.first.nodes) {\n const pseudoNode = isPseudoNode(item)\n\n // checks for only supported pseudo selectors\n if (pseudoNode && !pseudoSelectors.has(item.value)) {\n throw error('Invalid pseudo selector', {\n found: item.value,\n })\n }\n\n const allowedTypes =\n isIdentifierNode(item) ||\n pseudoNode ||\n (isCombinatorNode(item) && item.value === '>') ||\n isCommentNode(item)\n const hasChildren =\n isPostcssNodeWithChildren(item) && item.nodes.length > 0\n const semverNode =\n pseudoNode &&\n (item.value === ':semver' || item.value === ':v')\n\n // validation, only pseudo selectors, id selectors\n // and combinators are valid ast node items\n // pseudo selectors are allowed to have children (parameters)\n if ((hasChildren && !pseudoNode) || !allowedTypes) {\n throw error('Invalid query', { found: query })\n }\n\n // combinators and comments are skipped\n if (isCombinatorNode(item)) {\n afterCombinator = true\n continue\n } else if (isCommentNode(item)) {\n const cleanComment = item.value\n .replace(/^\\/\\*/, '')\n .replace(/\\*\\/$/, '')\n .trim()\n this.comment = cleanComment\n afterCombinator = true\n } else {\n // we define the last item as we iterate through the list of\n // breadcrumb items so that this value can also be used to\n // update previous items when needed\n const lastItem =\n this.#items.length > 0 ?\n this.#items[this.#items.length - 1]\n : undefined\n\n // Extract parameter before potential consolidation\n const providedRange: string =\n (\n pseudoNode &&\n (item.value === ':semver' || item.value === ':v')\n ) ?\n (extractPseudoParameter(item).semverValue ?? '')\n : ''\n\n // get the comparator function for a given pseudo selector item\n const internalOptions: InternalModifierComparatorOptions = {\n ...(semverNode ? { range: providedRange } : {}),\n }\n const comparator = (\n pseudoSelectors.get(item.value) ?? passthroughComparator\n )(internalOptions)\n\n // If we have a previous item and we haven't encountered a combinator\n // since then, consolidate with the previous item\n if (lastItem && !afterCombinator) {\n // Check for invalid chained pseudo selectors\n if (pseudoNode && isPseudoNode(lastItem)) {\n throw error('Invalid query', { found: query })\n }\n\n // determine how to combine the values based on selector types\n let currentValue: string = item.value\n if (item.type === 'id') {\n currentValue = `#${item.value}`\n } else if (pseudoNode) {\n currentValue = getPseudoSelectorFullText(item)\n }\n lastItem.value = `${lastItem.value}${currentValue}`\n\n // if current item is an ID, update the name property\n if (isIdentifierNode(item)) {\n lastItem.name = item.value\n }\n\n // Handle comparator and importer when consolidating with pseudo node\n if (pseudoNode) {\n const lastItemComparator = lastItem.comparator\n lastItem.comparator = (opts: ModifierComparatorOptions) =>\n comparator(opts) && lastItemComparator(opts)\n lastItem.importer ||= importerNames.has(item.value)\n }\n\n // update specificity counters\n if (isIdentifierNode(item)) {\n this.specificity.idCounter++\n } else if (pseudoNode) {\n this.specificity.commonCounter++\n }\n\n afterCombinator = false\n continue\n }\n\n // Create a new breadcrumb item\n let itemValue: string = item.value\n if (item.type === 'id') {\n itemValue = `#${item.value}`\n } else if (pseudoNode) {\n itemValue = getPseudoSelectorFullText(item)\n }\n\n const newItem = {\n comparator,\n value: itemValue,\n name: item.type === 'id' ? item.value : undefined,\n type: item.type,\n prev: lastItem,\n next: undefined,\n importer: pseudoNode && importerNames.has(item.value),\n }\n if (lastItem) {\n lastItem.next = newItem\n }\n this.#items.push(newItem)\n\n // Update specificity counters\n if (isIdentifierNode(item)) {\n this.specificity.idCounter++\n } else if (pseudoNode) {\n this.specificity.commonCounter++\n }\n\n afterCombinator = false\n }\n }\n // the parsed query should have at least one item\n // that is then going to be set as the current item\n if (!this.#items[0]) {\n throw error('Failed to parse query', {\n found: query,\n })\n }\n }\n\n /**\n * Retrieves the first breadcrumb item.\n */\n get first(): ModifierBreadcrumbItem {\n if (!this.#items[0]) {\n throw error('Failed to find first breadcrumb item')\n }\n return this.#items[0]\n }\n\n /**\n * Retrieves the last breadcrumb item.\n */\n get last(): ModifierBreadcrumbItem {\n const lastItem = this.#items[this.#items.length - 1]\n if (!lastItem) {\n throw error('Failed to find first breadcrumb item')\n }\n return lastItem\n }\n\n /**\n * Returns `true` if the breadcrumb is composed of a single item.\n */\n get single(): boolean {\n return this.#items.length === 1\n }\n\n [Symbol.iterator]() {\n return this.#items.values()\n }\n\n /**\n * Empties the current breadcrumb list.\n */\n clear() {\n for (const item of this.#items) {\n item.prev = undefined\n item.next = undefined\n }\n this.#items.length = 0\n }\n\n /**\n * Gets an {@link InteractiveBreadcrumb} instance that can be\n * used to track state of the current breadcrumb item.\n */\n interactive() {\n return new InteractiveBreadcrumb(this)\n }\n}\n\n/**\n * The InteractiveBreadcrumb is used to keep track of state\n * of the current breadcrumb item that should be used for checks.\n */\nexport class InteractiveBreadcrumb\n implements ModifierInteractiveBreadcrumb\n{\n #current: ModifierBreadcrumbItem | undefined\n constructor(breadcrumb: Breadcrumb) {\n this.#current = breadcrumb.first\n }\n\n /**\n * The current breadcrumb item.\n */\n get current(): ModifierBreadcrumbItem | undefined {\n return this.#current\n }\n\n /**\n * Returns `true` if the current breadcrumb has no more items left.\n */\n get done(): boolean {\n return !this.#current\n }\n\n /**\n * The next breadcrumb item.\n */\n next(): this {\n this.#current = this.#current?.next\n return this\n }\n}\n\n/**\n * Returns an {@link Breadcrumb} list of items\n * for a given query string.\n */\nexport const parseBreadcrumb = (query: string): ModifierBreadcrumb =>\n new Breadcrumb(query)\n\n/**\n * Sorts an array of Breadcrumb objects by specificity. Objects with\n * higher idCounter values come first, if idCounter values are equal,\n * then objects with higher commonCounter values come first. Otherwise,\n * the original order is preserved.\n */\nexport const specificitySort = (\n breadcrumbs: ModifierBreadcrumb[],\n): ModifierBreadcrumb[] => {\n return [...breadcrumbs].sort((a, b) => {\n // First compare by idCounter (higher comes first)\n if (a.specificity.idCounter !== b.specificity.idCounter) {\n return b.specificity.idCounter - a.specificity.idCounter\n }\n\n // If idCounter values are equal, compare by commonCounter\n if (a.specificity.commonCounter !== b.specificity.commonCounter) {\n return b.specificity.commonCounter - a.specificity.commonCounter\n }\n\n // If both counters are equal, preserve original order\n return 0\n })\n}\n"]}
@@ -5,10 +5,23 @@ export type BreadcrumbSpecificity = {
5
5
  idCounter: number;
6
6
  commonCounter: number;
7
7
  };
8
+ /**
9
+ * Options for the higher-level comparing breadcrumbs function.
10
+ */
11
+ export type InternalModifierComparatorOptions = {
12
+ range?: string;
13
+ };
14
+ /**
15
+ * Options for comparing breadcrumbs.
16
+ */
17
+ export type ModifierComparatorOptions = {
18
+ semver?: string;
19
+ };
8
20
  /**
9
21
  * A valid item of a given breadcrumb.
10
22
  */
11
23
  export type ModifierBreadcrumbItem = {
24
+ comparator: (opts: ModifierComparatorOptions) => boolean;
12
25
  name?: string;
13
26
  value: string;
14
27
  type: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,IAAI,EAAE,sBAAsB,GAAG,SAAS,CAAA;IACxC,IAAI,EAAE,sBAAsB,GAAG,SAAS,CAAA;CACzC,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,kBACf,SAAQ,QAAQ,CAAC,sBAAsB,CAAC;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,EAAE,qBAAqB,CAAA;IAClC,WAAW,EAAE,MAAM,6BAA6B,CAAA;CACjD;AAED;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,sBAAsB,GAAG,SAAS,CAAA;IAC3C,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,6BAA6B,CAAA;CAC1C,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,OAAO,CAAA;IACxD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,IAAI,EAAE,sBAAsB,GAAG,SAAS,CAAA;IACxC,IAAI,EAAE,sBAAsB,GAAG,SAAS,CAAA;CACzC,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,kBACf,SAAQ,QAAQ,CAAC,sBAAsB,CAAC;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,EAAE,qBAAqB,CAAA;IAClC,WAAW,EAAE,MAAM,6BAA6B,CAAA;CACjD;AAED;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,sBAAsB,GAAG,SAAS,CAAA;IAC3C,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,6BAA6B,CAAA;CAC1C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * The specificity of a breadcrumb, used for sorting.\n */\nexport type BreadcrumbSpecificity = {\n idCounter: number\n commonCounter: number\n}\n\n/**\n * A valid item of a given breadcrumb.\n */\nexport type ModifierBreadcrumbItem = {\n name?: string\n value: string\n type: string\n importer: boolean\n prev: ModifierBreadcrumbItem | undefined\n next: ModifierBreadcrumbItem | undefined\n}\n\n/**\n * A breadcrumb is a linked list of items, where\n * each item has a value and a type.\n */\nexport interface ModifierBreadcrumb\n extends Iterable<ModifierBreadcrumbItem> {\n clear(): void\n comment: string | undefined\n first: ModifierBreadcrumbItem\n last: ModifierBreadcrumbItem\n single: boolean\n specificity: BreadcrumbSpecificity\n interactive: () => ModifierInteractiveBreadcrumb\n}\n\n/**\n * An interactive breadcrumb that holds state on what is the current item.\n */\nexport type ModifierInteractiveBreadcrumb = {\n current: ModifierBreadcrumbItem | undefined\n done: boolean\n next: () => ModifierInteractiveBreadcrumb\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * The specificity of a breadcrumb, used for sorting.\n */\nexport type BreadcrumbSpecificity = {\n idCounter: number\n commonCounter: number\n}\n\n/**\n * Options for the higher-level comparing breadcrumbs function.\n */\nexport type InternalModifierComparatorOptions = {\n range?: string\n}\n\n/**\n * Options for comparing breadcrumbs.\n */\nexport type ModifierComparatorOptions = {\n semver?: string\n}\n\n/**\n * A valid item of a given breadcrumb.\n */\nexport type ModifierBreadcrumbItem = {\n comparator: (opts: ModifierComparatorOptions) => boolean\n name?: string\n value: string\n type: string\n importer: boolean\n prev: ModifierBreadcrumbItem | undefined\n next: ModifierBreadcrumbItem | undefined\n}\n\n/**\n * A breadcrumb is a linked list of items, where\n * each item has a value and a type.\n */\nexport interface ModifierBreadcrumb\n extends Iterable<ModifierBreadcrumbItem> {\n clear(): void\n comment: string | undefined\n first: ModifierBreadcrumbItem\n last: ModifierBreadcrumbItem\n single: boolean\n specificity: BreadcrumbSpecificity\n interactive: () => ModifierInteractiveBreadcrumb\n}\n\n/**\n * An interactive breadcrumb that holds state on what is the current item.\n */\nexport type ModifierInteractiveBreadcrumb = {\n current: ModifierBreadcrumbItem | undefined\n done: boolean\n next: () => ModifierInteractiveBreadcrumb\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/dss-breadcrumb",
3
3
  "description": "The Dependency Selector Syntax (DSS) breadcrumb utilities",
4
- "version": "0.0.0-15",
4
+ "version": "0.0.0-16",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -19,14 +19,14 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@vltpkg/dss-parser": "0.0.0-15",
23
- "@vltpkg/error-cause": "0.0.0-15"
22
+ "@vltpkg/dss-parser": "0.0.0-16",
23
+ "@vltpkg/error-cause": "0.0.0-16"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@eslint/js": "^9.28.0",
27
27
  "@types/node": "^22.15.29",
28
28
  "eslint": "^9.28.0",
29
- "prettier": "^3.5.3",
29
+ "prettier": "^3.6.0",
30
30
  "tap": "^21.1.0",
31
31
  "tshy": "^3.0.2",
32
32
  "typedoc": "~0.27.9",