@rushstack/lookup-by-path 0.5.22 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.json CHANGED
@@ -1,6 +1,33 @@
1
1
  {
2
2
  "name": "@rushstack/lookup-by-path",
3
3
  "entries": [
4
+ {
5
+ "version": "0.6.0",
6
+ "tag": "@rushstack/lookup-by-path_v0.6.0",
7
+ "date": "Thu, 08 May 2025 00:11:15 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Add `getFirstDifferenceInCommonNodes` API."
12
+ },
13
+ {
14
+ "comment": "Expose `tree` accessor on `IReadonlyLookupByPath` for a readonly view of the raw tree."
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "version": "0.5.23",
21
+ "tag": "@rushstack/lookup-by-path_v0.5.23",
22
+ "date": "Thu, 01 May 2025 15:11:33 GMT",
23
+ "comments": {
24
+ "dependency": [
25
+ {
26
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`"
27
+ }
28
+ ]
29
+ }
30
+ },
4
31
  {
5
32
  "version": "0.5.22",
6
33
  "tag": "@rushstack/lookup-by-path_v0.5.22",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # Change Log - @rushstack/lookup-by-path
2
2
 
3
- This log was last generated on Thu, 01 May 2025 00:11:12 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 08 May 2025 00:11:15 GMT and should not be manually modified.
4
+
5
+ ## 0.6.0
6
+ Thu, 08 May 2025 00:11:15 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Add `getFirstDifferenceInCommonNodes` API.
11
+ - Expose `tree` accessor on `IReadonlyLookupByPath` for a readonly view of the raw tree.
12
+
13
+ ## 0.5.23
14
+ Thu, 01 May 2025 15:11:33 GMT
15
+
16
+ _Version update only_
4
17
 
5
18
  ## 0.5.22
6
19
  Thu, 01 May 2025 00:11:12 GMT
@@ -4,6 +4,49 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
 
7
+ /**
8
+ * Recursively compares two path tries to find the first shared node with a different value.
9
+ *
10
+ * @param options - The options for the comparison
11
+ * @returns The path to the first differing node, or undefined if they are identical
12
+ *
13
+ * @remarks
14
+ * Ignores any nodes that are not shared between the two tries.
15
+ *
16
+ * @beta
17
+ */
18
+ export declare function getFirstDifferenceInCommonNodes<TItem extends {}>(options: IGetFirstDifferenceInCommonNodesOptions<TItem>): string | undefined;
19
+
20
+ /**
21
+ * Options for the getFirstDifferenceInCommonNodes function.
22
+ * @beta
23
+ */
24
+ export declare interface IGetFirstDifferenceInCommonNodesOptions<TItem extends {}> {
25
+ /**
26
+ * The first node to compare.
27
+ */
28
+ first: IReadonlyPathTrieNode<TItem>;
29
+ /**
30
+ * The second node to compare.
31
+ */
32
+ second: IReadonlyPathTrieNode<TItem>;
33
+ /**
34
+ * The path prefix to the current node.
35
+ * @defaultValue ''
36
+ */
37
+ prefix?: string;
38
+ /**
39
+ * The delimiter used to join path segments.
40
+ * @defaultValue '/'
41
+ */
42
+ delimiter?: string;
43
+ /**
44
+ * A function to compare the values of the nodes.
45
+ * If not provided, strict equality (===) is used.
46
+ */
47
+ equals?: (a: TItem, b: TItem) => boolean;
48
+ }
49
+
7
50
  /**
8
51
  * Object containing both the matched item and the start index of the remainder of the query.
9
52
  *
@@ -91,6 +134,10 @@ export declare interface IReadonlyLookupByPath<TItem extends {}> extends Iterabl
91
134
  * @returns The number of entries in this trie.
92
135
  */
93
136
  get size(): number;
137
+ /**
138
+ * @returns The root node of the trie, corresponding to the path ''
139
+ */
140
+ get tree(): IReadonlyPathTrieNode<TItem>;
94
141
  /**
95
142
  * Iterates over the entries in this trie.
96
143
  *
@@ -129,6 +176,25 @@ export declare interface IReadonlyLookupByPath<TItem extends {}> extends Iterabl
129
176
  groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;
130
177
  }
131
178
 
179
+ /**
180
+ * Readonly view of a node in the path trie used in LookupByPath
181
+ *
182
+ * @remarks
183
+ * This interface is used to facilitate parallel traversals for comparing two `LookupByPath` instances.
184
+ *
185
+ * @beta
186
+ */
187
+ export declare interface IReadonlyPathTrieNode<TItem extends {}> {
188
+ /**
189
+ * The value that exactly matches the current relative path
190
+ */
191
+ readonly value: TItem | undefined;
192
+ /**
193
+ * Child nodes by subfolder
194
+ */
195
+ readonly children: ReadonlyMap<string, IReadonlyPathTrieNode<TItem>> | undefined;
196
+ }
197
+
132
198
  /**
133
199
  * This class is used to associate path-like-strings, such as those returned by `git` commands,
134
200
  * with entities that correspond with ancestor folders, such as Rush Projects or npm packages.
@@ -180,9 +246,13 @@ export declare class LookupByPath<TItem extends {}> implements IReadonlyLookupBy
180
246
  static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable<string>;
181
247
  private static _iteratePrefixes;
182
248
  /**
183
- * {@inheritdoc IReadonlyLookupByPath}
249
+ * {@inheritdoc IReadonlyLookupByPath.size}
184
250
  */
185
251
  get size(): number;
252
+ /**
253
+ * {@inheritdoc IReadonlyLookupByPath.tree}
254
+ */
255
+ get tree(): IReadonlyPathTrieNode<TItem>;
186
256
  /**
187
257
  * Deletes all entries from this `LookupByPath` instance.
188
258
  *
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.52.5"
8
+ "packageVersion": "7.52.7"
9
9
  }
10
10
  ]
11
11
  }
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Readonly view of a node in the path trie used in LookupByPath
3
+ *
4
+ * @remarks
5
+ * This interface is used to facilitate parallel traversals for comparing two `LookupByPath` instances.
6
+ *
7
+ * @beta
8
+ */
9
+ export interface IReadonlyPathTrieNode<TItem extends {}> {
10
+ /**
11
+ * The value that exactly matches the current relative path
12
+ */
13
+ readonly value: TItem | undefined;
14
+ /**
15
+ * Child nodes by subfolder
16
+ */
17
+ readonly children: ReadonlyMap<string, IReadonlyPathTrieNode<TItem>> | undefined;
18
+ }
1
19
  /**
2
20
  * Object containing both the matched item and the start index of the remainder of the query.
3
21
  *
@@ -84,6 +102,10 @@ export interface IReadonlyLookupByPath<TItem extends {}> extends Iterable<[strin
84
102
  * @returns The number of entries in this trie.
85
103
  */
86
104
  get size(): number;
105
+ /**
106
+ * @returns The root node of the trie, corresponding to the path ''
107
+ */
108
+ get tree(): IReadonlyPathTrieNode<TItem>;
87
109
  /**
88
110
  * Iterates over the entries in this trie.
89
111
  *
@@ -172,9 +194,13 @@ export declare class LookupByPath<TItem extends {}> implements IReadonlyLookupBy
172
194
  static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable<string>;
173
195
  private static _iteratePrefixes;
174
196
  /**
175
- * {@inheritdoc IReadonlyLookupByPath}
197
+ * {@inheritdoc IReadonlyLookupByPath.size}
176
198
  */
177
199
  get size(): number;
200
+ /**
201
+ * {@inheritdoc IReadonlyLookupByPath.tree}
202
+ */
203
+ get tree(): IReadonlyPathTrieNode<TItem>;
178
204
  /**
179
205
  * Deletes all entries from this `LookupByPath` instance.
180
206
  *
@@ -1 +1 @@
1
- {"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"AAkBA;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,EAAE;IACrD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;CAClF;AAcD;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK,SAAS,EAAE;IAC5C;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,EAAE,CAAE,SAAQ,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxF;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAExE;;;;;;;;;;;;;OAaG;IACH,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAE3F;;;;;;;;;;;;OAYG;IACH,yBAAyB,CAAC,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,SAAS,CAAC;IAElF;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhD;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAAC;IAEnB;;OAEG;IACH,IAAI,IAAI,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAEzC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAE/E;;;;;;;;;OASG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAEzF;;;;;;;OAOG;IACH,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;CACzG;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,YAAY,CAAC,KAAK,SAAS,EAAE,CAAE,YAAW,qBAAqB,CAAC,KAAK,CAAC;IACjF;;OAEG;IACH,SAAgB,SAAS,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAE7C;;OAEG;IACH,OAAO,CAAC,KAAK,CAAS;IAEtB;;;;OAIG;gBACgB,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM;IAgB1E;;;;;;;;OAQG;WACY,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,QAAQ,CAAC,MAAM,CAAC;IAMrG,OAAO,CAAC,MAAM,CAAE,gBAAgB;IA2BhC;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAW,IAAI,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAE9C;IAED;;;;OAIG;IACI,KAAK,IAAI,IAAI;IAOpB;;;;;OAKG;IACI,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,GAAE,MAAuB,GAAG,IAAI;IAI9F;;;;;;;OAOG;IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAuB,GAAG,OAAO;IAW7E;;;;;OAKG;IACI,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IA0B9E;;OAEG;IACI,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAuB,GAAG,KAAK,GAAG,SAAS;IAI9F;;OAEG;IACI,sBAAsB,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAuB,GACjC,YAAY,CAAC,KAAK,CAAC,GAAG,SAAS;IAIlC;;OAEG;IACI,yBAAyB,CAAC,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,SAAS;IAqBxF;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAuB,GAAG,OAAO;IAKpE;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAuB,GAAG,KAAK,GAAG,SAAS;IAK9E;;OAEG;IACI,YAAY,CAAC,KAAK,EACvB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAC9B,SAAS,GAAE,MAAuB,GACjC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAmBjC;;OAEG;IACK,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,GAAE,MAAuB,GAAG,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IA0BtG;;OAEG;IACI,CAAC,MAAM,CAAC,QAAQ,CAAC,CACtB,KAAK,CAAC,EAAE,MAAM,EACd,SAAS,GAAE,MAAuB,GACjC,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAIpC;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;IAiC/B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;CAiB1B"}
@@ -80,11 +80,17 @@ class LookupByPath {
80
80
  }
81
81
  }
82
82
  /**
83
- * {@inheritdoc IReadonlyLookupByPath}
83
+ * {@inheritdoc IReadonlyLookupByPath.size}
84
84
  */
85
85
  get size() {
86
86
  return this._size;
87
87
  }
88
+ /**
89
+ * {@inheritdoc IReadonlyLookupByPath.tree}
90
+ */
91
+ get tree() {
92
+ return this._root;
93
+ }
88
94
  /**
89
95
  * Deletes all entries from this `LookupByPath` instance.
90
96
  *
@@ -1 +1 @@
1
- {"version":3,"file":"LookupByPath.js","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * A node in the path trie used in LookupByPath\n */\ninterface IPathTrieNode<TItem extends {}> {\n /**\n * The value that exactly matches the current relative path\n */\n value: TItem | undefined;\n\n /**\n * Child nodes by subfolder\n */\n children: Map<string, IPathTrieNode<TItem>> | undefined;\n}\n\ninterface IPrefixEntry {\n /**\n * The prefix that was matched\n */\n prefix: string;\n\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n}\n\n/**\n * Object containing both the matched item and the start index of the remainder of the query.\n *\n * @beta\n */\nexport interface IPrefixMatch<TItem extends {}> {\n /**\n * The item that matched the prefix\n */\n value: TItem;\n\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n\n /**\n * The last match found (with a shorter prefix), if any\n */\n lastMatch?: IPrefixMatch<TItem>;\n}\n\n/**\n * The readonly component of `LookupByPath`, to simplify unit testing.\n *\n * @beta\n */\nexport interface IReadonlyLookupByPath<TItem extends {}> extends Iterable<[string, TItem]> {\n /**\n * Searches for the item associated with `childPath`, or the nearest ancestor of that path that\n * has an associated item.\n *\n * @returns the found item, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findChildPath('foo/baz'); // returns 1\n * trie.findChildPath('foo/bar/baz'); // returns 2\n * ```\n */\n findChildPath(childPath: string, delimiter?: string): TItem | undefined;\n\n /**\n * Searches for the item for which the recorded prefix is the longest matching prefix of `query`.\n * Obtains both the item and the length of the matched prefix, so that the remainder of the path can be\n * extracted.\n *\n * @returns the found item and the length of the matched prefix, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findLongestPrefixMatch('foo/baz'); // returns { item: 1, index: 3 }\n * trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 }\n * ```\n */\n findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;\n\n /**\n * Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that\n * has an associated item.\n *\n * @returns the found item, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findChildPathFromSegments(['foo', 'baz']); // returns 1\n * trie.findChildPathFromSegments(['foo','bar', 'baz']); // returns 2\n * ```\n */\n findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;\n\n /**\n * Determines if an entry exists exactly at the specified path.\n *\n * @returns `true` if an entry exists at the specified path, `false` otherwise\n */\n has(query: string, delimiter?: string): boolean;\n\n /**\n * Retrieves the entry that exists exactly at the specified path, if any.\n *\n * @returns The entry that exists exactly at the specified path, or `undefined` if no entry exists.\n */\n get(query: string, delimiter?: string): TItem | undefined;\n\n /**\n * Gets the number of entries in this trie.\n *\n * @returns The number of entries in this trie.\n */\n get size(): number;\n\n /**\n * Iterates over the entries in this trie.\n *\n * @param query - An optional query. If specified only entries that start with the query will be returned.\n *\n * @returns An iterator over the entries under the specified query (or the root if no query is specified).\n * @remarks\n * Keys in the returned iterator use the provided delimiter to join segments.\n * Iteration order is not specified.\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * [...trie.entries(undefined, ',')); // returns [['foo', 1], ['foo,bar', 2]]\n * ```\n */\n entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;\n\n /**\n * Iterates over the entries in this trie.\n *\n * @param query - An optional query. If specified only entries that start with the query will be returned.\n *\n * @returns An iterator over the entries under the specified query (or the root if no query is specified).\n * @remarks\n * Keys in the returned iterator use the provided delimiter to join segments.\n * Iteration order is not specified.\n */\n [Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;\n\n /**\n * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path\n * is not found in the trie, the info is ignored.\n *\n * @returns The grouped info, grouped by the nearest entry in the trie that contains the path\n *\n * @param infoByPath - The info to be grouped, keyed by path\n */\n groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;\n}\n\n/**\n * This class is used to associate path-like-strings, such as those returned by `git` commands,\n * with entities that correspond with ancestor folders, such as Rush Projects or npm packages.\n *\n * It is optimized for efficiently locating the nearest ancestor path with an associated value.\n *\n * It is implemented as a Trie (https://en.wikipedia.org/wiki/Trie) data structure, with each edge\n * being a path segment.\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['bar', 2], ['foo/bar', 3]]);\n * trie.findChildPath('foo'); // returns 1\n * trie.findChildPath('foo/baz'); // returns 1\n * trie.findChildPath('baz'); // returns undefined\n * trie.findChildPath('foo/bar/baz'); returns 3\n * trie.findChildPath('bar/foo/bar'); returns 2\n * ```\n * @beta\n */\nexport class LookupByPath<TItem extends {}> implements IReadonlyLookupByPath<TItem> {\n /**\n * The delimiter used to split paths\n */\n public readonly delimiter: string;\n\n /**\n * The root node of the trie, corresponding to the path ''\n */\n private readonly _root: IPathTrieNode<TItem>;\n\n /**\n * The number of entries in this trie.\n */\n private _size: number;\n\n /**\n * Constructs a new `LookupByPath`\n *\n * @param entries - Initial path-value pairs to populate the trie.\n */\n public constructor(entries?: Iterable<[string, TItem]>, delimiter?: string) {\n this._root = {\n value: undefined,\n children: undefined\n };\n\n this.delimiter = delimiter ?? '/';\n this._size = 0;\n\n if (entries) {\n for (const [path, item] of entries) {\n this.setItem(path, item);\n }\n }\n }\n\n /**\n * Iterates over the segments of a serialized path.\n *\n * @example\n *\n * `LookupByPath.iteratePathSegments('foo/bar/baz')` yields 'foo', 'bar', 'baz'\n *\n * `LookupByPath.iteratePathSegments('foo\\\\bar\\\\baz', '\\\\')` yields 'foo', 'bar', 'baz'\n */\n public static *iteratePathSegments(serializedPath: string, delimiter: string = '/'): Iterable<string> {\n for (const prefixMatch of this._iteratePrefixes(serializedPath, delimiter)) {\n yield prefixMatch.prefix;\n }\n }\n\n private static *_iteratePrefixes(input: string, delimiter: string = '/'): Iterable<IPrefixEntry> {\n if (!input) {\n return;\n }\n\n let previousIndex: number = 0;\n let nextIndex: number = input.indexOf(delimiter);\n\n // Leading segments\n while (nextIndex >= 0) {\n yield {\n prefix: input.slice(previousIndex, nextIndex),\n index: nextIndex\n };\n previousIndex = nextIndex + 1;\n nextIndex = input.indexOf(delimiter, previousIndex);\n }\n\n // Last segment\n if (previousIndex < input.length) {\n yield {\n prefix: input.slice(previousIndex, input.length),\n index: input.length\n };\n }\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public get size(): number {\n return this._size;\n }\n\n /**\n * Deletes all entries from this `LookupByPath` instance.\n *\n * @returns this, for chained calls\n */\n public clear(): this {\n this._root.value = undefined;\n this._root.children = undefined;\n this._size = 0;\n return this;\n }\n\n /**\n * Associates the value with the specified serialized path.\n * If a value is already associated, will overwrite.\n *\n * @returns this, for chained calls\n */\n public setItem(serializedPath: string, value: TItem, delimiter: string = this.delimiter): this {\n return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, delimiter), value);\n }\n\n /**\n * Deletes an item if it exists.\n * @param query - The path to the item to delete\n * @param delimeter - Optional override delimeter for parsing the query\n * @returns `true` if the item was found and deleted, `false` otherwise\n * @remarks\n * If the node has children with values, they will be retained.\n */\n public deleteItem(query: string, delimeter: string = this.delimiter): boolean {\n const node: IPathTrieNode<TItem> | undefined = this._findNodeAtPrefix(query, delimeter);\n if (node?.value !== undefined) {\n node.value = undefined;\n this._size--;\n return true;\n }\n\n return false;\n }\n\n /**\n * Associates the value with the specified path.\n * If a value is already associated, will overwrite.\n *\n * @returns this, for chained calls\n */\n public setItemFromSegments(pathSegments: Iterable<string>, value: TItem): this {\n let node: IPathTrieNode<TItem> = this._root;\n for (const segment of pathSegments) {\n if (!node.children) {\n node.children = new Map();\n }\n let child: IPathTrieNode<TItem> | undefined = node.children.get(segment);\n if (!child) {\n node.children.set(\n segment,\n (child = {\n value: undefined,\n children: undefined\n })\n );\n }\n node = child;\n }\n if (node.value === undefined) {\n this._size++;\n }\n node.value = value;\n\n return this;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findChildPath(childPath: string, delimiter: string = this.delimiter): TItem | undefined {\n return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, delimiter));\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findLongestPrefixMatch(\n query: string,\n delimiter: string = this.delimiter\n ): IPrefixMatch<TItem> | undefined {\n return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, delimiter));\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n let best: TItem | undefined = node.value;\n // Trivial cases\n if (node.children) {\n for (const segment of childPathSegments) {\n const child: IPathTrieNode<TItem> | undefined = node.children.get(segment);\n if (!child) {\n break;\n }\n node = child;\n best = node.value ?? best;\n if (!node.children) {\n break;\n }\n }\n }\n\n return best;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public has(key: string, delimiter: string = this.delimiter): boolean {\n const match: IPrefixMatch<TItem> | undefined = this.findLongestPrefixMatch(key, delimiter);\n return match?.index === key.length;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public get(key: string, delimiter: string = this.delimiter): TItem | undefined {\n const match: IPrefixMatch<TItem> | undefined = this.findLongestPrefixMatch(key, delimiter);\n return match?.index === key.length ? match.value : undefined;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public groupByChild<TInfo>(\n infoByPath: Map<string, TInfo>,\n delimiter: string = this.delimiter\n ): Map<TItem, Map<string, TInfo>> {\n const groupedInfoByChild: Map<TItem, Map<string, TInfo>> = new Map();\n\n for (const [path, info] of infoByPath) {\n const child: TItem | undefined = this.findChildPath(path, delimiter);\n if (child === undefined) {\n continue;\n }\n let groupedInfo: Map<string, TInfo> | undefined = groupedInfoByChild.get(child);\n if (!groupedInfo) {\n groupedInfo = new Map();\n groupedInfoByChild.set(child, groupedInfo);\n }\n groupedInfo.set(path, info);\n }\n\n return groupedInfoByChild;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public *entries(query?: string, delimiter: string = this.delimiter): IterableIterator<[string, TItem]> {\n let root: IPathTrieNode<TItem> | undefined;\n if (query) {\n root = this._findNodeAtPrefix(query, delimiter);\n if (!root) {\n return;\n }\n } else {\n root = this._root;\n }\n\n const stack: [string, IPathTrieNode<TItem>][] = [[query ?? '', root]];\n while (stack.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const [prefix, node] = stack.pop()!;\n if (node.value !== undefined) {\n yield [prefix, node.value];\n }\n if (node.children) {\n for (const [segment, child] of node.children) {\n stack.push([prefix ? `${prefix}${delimiter}${segment}` : segment, child]);\n }\n }\n }\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public [Symbol.iterator](\n query?: string,\n delimiter: string = this.delimiter\n ): IterableIterator<[string, TItem]> {\n return this.entries(query, delimiter);\n }\n\n /**\n * Iterates through progressively longer prefixes of a given string and returns as soon\n * as the number of candidate items that match the prefix are 1 or 0.\n *\n * If a match is present, returns the matched itme and the length of the matched prefix.\n *\n * @returns the found item, or `undefined` if no item was found\n */\n private _findLongestPrefixMatch(prefixes: Iterable<IPrefixEntry>): IPrefixMatch<TItem> | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n let best: IPrefixMatch<TItem> | undefined = node.value\n ? {\n value: node.value,\n index: 0,\n lastMatch: undefined\n }\n : undefined;\n // Trivial cases\n if (node.children) {\n for (const { prefix: hash, index } of prefixes) {\n const child: IPathTrieNode<TItem> | undefined = node.children.get(hash);\n if (!child) {\n break;\n }\n node = child;\n if (node.value !== undefined) {\n best = {\n value: node.value,\n index,\n lastMatch: best\n };\n }\n if (!node.children) {\n break;\n }\n }\n }\n\n return best;\n }\n\n /**\n * Finds the node at the specified path, or `undefined` if no node was found.\n *\n * @param query - The path to the node to search for\n * @returns The trie node at the specified path, or `undefined` if no node was found\n */\n private _findNodeAtPrefix(\n query: string,\n delimiter: string = this.delimiter\n ): IPathTrieNode<TItem> | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n for (const { prefix } of LookupByPath._iteratePrefixes(query, delimiter)) {\n if (!node.children) {\n return undefined;\n }\n const child: IPathTrieNode<TItem> | undefined = node.children.get(prefix);\n if (!child) {\n return undefined;\n }\n node = child;\n }\n return node;\n }\n}\n"]}
1
+ {"version":3,"file":"LookupByPath.js","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * A node in the path trie used in LookupByPath\n */\ninterface IPathTrieNode<TItem extends {}> {\n /**\n * The value that exactly matches the current relative path\n */\n value: TItem | undefined;\n\n /**\n * Child nodes by subfolder\n */\n children: Map<string, IPathTrieNode<TItem>> | undefined;\n}\n\n/**\n * Readonly view of a node in the path trie used in LookupByPath\n *\n * @remarks\n * This interface is used to facilitate parallel traversals for comparing two `LookupByPath` instances.\n *\n * @beta\n */\nexport interface IReadonlyPathTrieNode<TItem extends {}> {\n /**\n * The value that exactly matches the current relative path\n */\n readonly value: TItem | undefined;\n\n /**\n * Child nodes by subfolder\n */\n readonly children: ReadonlyMap<string, IReadonlyPathTrieNode<TItem>> | undefined;\n}\n\ninterface IPrefixEntry {\n /**\n * The prefix that was matched\n */\n prefix: string;\n\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n}\n\n/**\n * Object containing both the matched item and the start index of the remainder of the query.\n *\n * @beta\n */\nexport interface IPrefixMatch<TItem extends {}> {\n /**\n * The item that matched the prefix\n */\n value: TItem;\n\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n\n /**\n * The last match found (with a shorter prefix), if any\n */\n lastMatch?: IPrefixMatch<TItem>;\n}\n\n/**\n * The readonly component of `LookupByPath`, to simplify unit testing.\n *\n * @beta\n */\nexport interface IReadonlyLookupByPath<TItem extends {}> extends Iterable<[string, TItem]> {\n /**\n * Searches for the item associated with `childPath`, or the nearest ancestor of that path that\n * has an associated item.\n *\n * @returns the found item, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findChildPath('foo/baz'); // returns 1\n * trie.findChildPath('foo/bar/baz'); // returns 2\n * ```\n */\n findChildPath(childPath: string, delimiter?: string): TItem | undefined;\n\n /**\n * Searches for the item for which the recorded prefix is the longest matching prefix of `query`.\n * Obtains both the item and the length of the matched prefix, so that the remainder of the path can be\n * extracted.\n *\n * @returns the found item and the length of the matched prefix, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findLongestPrefixMatch('foo/baz'); // returns { item: 1, index: 3 }\n * trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 }\n * ```\n */\n findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;\n\n /**\n * Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that\n * has an associated item.\n *\n * @returns the found item, or `undefined` if no item was found\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * trie.findChildPathFromSegments(['foo', 'baz']); // returns 1\n * trie.findChildPathFromSegments(['foo','bar', 'baz']); // returns 2\n * ```\n */\n findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;\n\n /**\n * Determines if an entry exists exactly at the specified path.\n *\n * @returns `true` if an entry exists at the specified path, `false` otherwise\n */\n has(query: string, delimiter?: string): boolean;\n\n /**\n * Retrieves the entry that exists exactly at the specified path, if any.\n *\n * @returns The entry that exists exactly at the specified path, or `undefined` if no entry exists.\n */\n get(query: string, delimiter?: string): TItem | undefined;\n\n /**\n * Gets the number of entries in this trie.\n *\n * @returns The number of entries in this trie.\n */\n get size(): number;\n\n /**\n * @returns The root node of the trie, corresponding to the path ''\n */\n get tree(): IReadonlyPathTrieNode<TItem>;\n\n /**\n * Iterates over the entries in this trie.\n *\n * @param query - An optional query. If specified only entries that start with the query will be returned.\n *\n * @returns An iterator over the entries under the specified query (or the root if no query is specified).\n * @remarks\n * Keys in the returned iterator use the provided delimiter to join segments.\n * Iteration order is not specified.\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);\n * [...trie.entries(undefined, ',')); // returns [['foo', 1], ['foo,bar', 2]]\n * ```\n */\n entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;\n\n /**\n * Iterates over the entries in this trie.\n *\n * @param query - An optional query. If specified only entries that start with the query will be returned.\n *\n * @returns An iterator over the entries under the specified query (or the root if no query is specified).\n * @remarks\n * Keys in the returned iterator use the provided delimiter to join segments.\n * Iteration order is not specified.\n */\n [Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;\n\n /**\n * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path\n * is not found in the trie, the info is ignored.\n *\n * @returns The grouped info, grouped by the nearest entry in the trie that contains the path\n *\n * @param infoByPath - The info to be grouped, keyed by path\n */\n groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;\n}\n\n/**\n * This class is used to associate path-like-strings, such as those returned by `git` commands,\n * with entities that correspond with ancestor folders, such as Rush Projects or npm packages.\n *\n * It is optimized for efficiently locating the nearest ancestor path with an associated value.\n *\n * It is implemented as a Trie (https://en.wikipedia.org/wiki/Trie) data structure, with each edge\n * being a path segment.\n *\n * @example\n * ```ts\n * const trie = new LookupByPath([['foo', 1], ['bar', 2], ['foo/bar', 3]]);\n * trie.findChildPath('foo'); // returns 1\n * trie.findChildPath('foo/baz'); // returns 1\n * trie.findChildPath('baz'); // returns undefined\n * trie.findChildPath('foo/bar/baz'); returns 3\n * trie.findChildPath('bar/foo/bar'); returns 2\n * ```\n * @beta\n */\nexport class LookupByPath<TItem extends {}> implements IReadonlyLookupByPath<TItem> {\n /**\n * The delimiter used to split paths\n */\n public readonly delimiter: string;\n\n /**\n * The root node of the trie, corresponding to the path ''\n */\n private readonly _root: IPathTrieNode<TItem>;\n\n /**\n * The number of entries in this trie.\n */\n private _size: number;\n\n /**\n * Constructs a new `LookupByPath`\n *\n * @param entries - Initial path-value pairs to populate the trie.\n */\n public constructor(entries?: Iterable<[string, TItem]>, delimiter?: string) {\n this._root = {\n value: undefined,\n children: undefined\n };\n\n this.delimiter = delimiter ?? '/';\n this._size = 0;\n\n if (entries) {\n for (const [path, item] of entries) {\n this.setItem(path, item);\n }\n }\n }\n\n /**\n * Iterates over the segments of a serialized path.\n *\n * @example\n *\n * `LookupByPath.iteratePathSegments('foo/bar/baz')` yields 'foo', 'bar', 'baz'\n *\n * `LookupByPath.iteratePathSegments('foo\\\\bar\\\\baz', '\\\\')` yields 'foo', 'bar', 'baz'\n */\n public static *iteratePathSegments(serializedPath: string, delimiter: string = '/'): Iterable<string> {\n for (const prefixMatch of this._iteratePrefixes(serializedPath, delimiter)) {\n yield prefixMatch.prefix;\n }\n }\n\n private static *_iteratePrefixes(input: string, delimiter: string = '/'): Iterable<IPrefixEntry> {\n if (!input) {\n return;\n }\n\n let previousIndex: number = 0;\n let nextIndex: number = input.indexOf(delimiter);\n\n // Leading segments\n while (nextIndex >= 0) {\n yield {\n prefix: input.slice(previousIndex, nextIndex),\n index: nextIndex\n };\n previousIndex = nextIndex + 1;\n nextIndex = input.indexOf(delimiter, previousIndex);\n }\n\n // Last segment\n if (previousIndex < input.length) {\n yield {\n prefix: input.slice(previousIndex, input.length),\n index: input.length\n };\n }\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath.size}\n */\n public get size(): number {\n return this._size;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath.tree}\n */\n public get tree(): IReadonlyPathTrieNode<TItem> {\n return this._root;\n }\n\n /**\n * Deletes all entries from this `LookupByPath` instance.\n *\n * @returns this, for chained calls\n */\n public clear(): this {\n this._root.value = undefined;\n this._root.children = undefined;\n this._size = 0;\n return this;\n }\n\n /**\n * Associates the value with the specified serialized path.\n * If a value is already associated, will overwrite.\n *\n * @returns this, for chained calls\n */\n public setItem(serializedPath: string, value: TItem, delimiter: string = this.delimiter): this {\n return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, delimiter), value);\n }\n\n /**\n * Deletes an item if it exists.\n * @param query - The path to the item to delete\n * @param delimeter - Optional override delimeter for parsing the query\n * @returns `true` if the item was found and deleted, `false` otherwise\n * @remarks\n * If the node has children with values, they will be retained.\n */\n public deleteItem(query: string, delimeter: string = this.delimiter): boolean {\n const node: IPathTrieNode<TItem> | undefined = this._findNodeAtPrefix(query, delimeter);\n if (node?.value !== undefined) {\n node.value = undefined;\n this._size--;\n return true;\n }\n\n return false;\n }\n\n /**\n * Associates the value with the specified path.\n * If a value is already associated, will overwrite.\n *\n * @returns this, for chained calls\n */\n public setItemFromSegments(pathSegments: Iterable<string>, value: TItem): this {\n let node: IPathTrieNode<TItem> = this._root;\n for (const segment of pathSegments) {\n if (!node.children) {\n node.children = new Map();\n }\n let child: IPathTrieNode<TItem> | undefined = node.children.get(segment);\n if (!child) {\n node.children.set(\n segment,\n (child = {\n value: undefined,\n children: undefined\n })\n );\n }\n node = child;\n }\n if (node.value === undefined) {\n this._size++;\n }\n node.value = value;\n\n return this;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findChildPath(childPath: string, delimiter: string = this.delimiter): TItem | undefined {\n return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, delimiter));\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findLongestPrefixMatch(\n query: string,\n delimiter: string = this.delimiter\n ): IPrefixMatch<TItem> | undefined {\n return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, delimiter));\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n let best: TItem | undefined = node.value;\n // Trivial cases\n if (node.children) {\n for (const segment of childPathSegments) {\n const child: IPathTrieNode<TItem> | undefined = node.children.get(segment);\n if (!child) {\n break;\n }\n node = child;\n best = node.value ?? best;\n if (!node.children) {\n break;\n }\n }\n }\n\n return best;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public has(key: string, delimiter: string = this.delimiter): boolean {\n const match: IPrefixMatch<TItem> | undefined = this.findLongestPrefixMatch(key, delimiter);\n return match?.index === key.length;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public get(key: string, delimiter: string = this.delimiter): TItem | undefined {\n const match: IPrefixMatch<TItem> | undefined = this.findLongestPrefixMatch(key, delimiter);\n return match?.index === key.length ? match.value : undefined;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public groupByChild<TInfo>(\n infoByPath: Map<string, TInfo>,\n delimiter: string = this.delimiter\n ): Map<TItem, Map<string, TInfo>> {\n const groupedInfoByChild: Map<TItem, Map<string, TInfo>> = new Map();\n\n for (const [path, info] of infoByPath) {\n const child: TItem | undefined = this.findChildPath(path, delimiter);\n if (child === undefined) {\n continue;\n }\n let groupedInfo: Map<string, TInfo> | undefined = groupedInfoByChild.get(child);\n if (!groupedInfo) {\n groupedInfo = new Map();\n groupedInfoByChild.set(child, groupedInfo);\n }\n groupedInfo.set(path, info);\n }\n\n return groupedInfoByChild;\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public *entries(query?: string, delimiter: string = this.delimiter): IterableIterator<[string, TItem]> {\n let root: IPathTrieNode<TItem> | undefined;\n if (query) {\n root = this._findNodeAtPrefix(query, delimiter);\n if (!root) {\n return;\n }\n } else {\n root = this._root;\n }\n\n const stack: [string, IPathTrieNode<TItem>][] = [[query ?? '', root]];\n while (stack.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const [prefix, node] = stack.pop()!;\n if (node.value !== undefined) {\n yield [prefix, node.value];\n }\n if (node.children) {\n for (const [segment, child] of node.children) {\n stack.push([prefix ? `${prefix}${delimiter}${segment}` : segment, child]);\n }\n }\n }\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public [Symbol.iterator](\n query?: string,\n delimiter: string = this.delimiter\n ): IterableIterator<[string, TItem]> {\n return this.entries(query, delimiter);\n }\n\n /**\n * Iterates through progressively longer prefixes of a given string and returns as soon\n * as the number of candidate items that match the prefix are 1 or 0.\n *\n * If a match is present, returns the matched itme and the length of the matched prefix.\n *\n * @returns the found item, or `undefined` if no item was found\n */\n private _findLongestPrefixMatch(prefixes: Iterable<IPrefixEntry>): IPrefixMatch<TItem> | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n let best: IPrefixMatch<TItem> | undefined = node.value\n ? {\n value: node.value,\n index: 0,\n lastMatch: undefined\n }\n : undefined;\n // Trivial cases\n if (node.children) {\n for (const { prefix: hash, index } of prefixes) {\n const child: IPathTrieNode<TItem> | undefined = node.children.get(hash);\n if (!child) {\n break;\n }\n node = child;\n if (node.value !== undefined) {\n best = {\n value: node.value,\n index,\n lastMatch: best\n };\n }\n if (!node.children) {\n break;\n }\n }\n }\n\n return best;\n }\n\n /**\n * Finds the node at the specified path, or `undefined` if no node was found.\n *\n * @param query - The path to the node to search for\n * @returns The trie node at the specified path, or `undefined` if no node was found\n */\n private _findNodeAtPrefix(\n query: string,\n delimiter: string = this.delimiter\n ): IPathTrieNode<TItem> | undefined {\n let node: IPathTrieNode<TItem> = this._root;\n for (const { prefix } of LookupByPath._iteratePrefixes(query, delimiter)) {\n if (!node.children) {\n return undefined;\n }\n const child: IPathTrieNode<TItem> | undefined = node.children.get(prefix);\n if (!child) {\n return undefined;\n }\n node = child;\n }\n return node;\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import type { IReadonlyPathTrieNode } from './LookupByPath';
2
+ /**
3
+ * Options for the getFirstDifferenceInCommonNodes function.
4
+ * @beta
5
+ */
6
+ export interface IGetFirstDifferenceInCommonNodesOptions<TItem extends {}> {
7
+ /**
8
+ * The first node to compare.
9
+ */
10
+ first: IReadonlyPathTrieNode<TItem>;
11
+ /**
12
+ * The second node to compare.
13
+ */
14
+ second: IReadonlyPathTrieNode<TItem>;
15
+ /**
16
+ * The path prefix to the current node.
17
+ * @defaultValue ''
18
+ */
19
+ prefix?: string;
20
+ /**
21
+ * The delimiter used to join path segments.
22
+ * @defaultValue '/'
23
+ */
24
+ delimiter?: string;
25
+ /**
26
+ * A function to compare the values of the nodes.
27
+ * If not provided, strict equality (===) is used.
28
+ */
29
+ equals?: (a: TItem, b: TItem) => boolean;
30
+ }
31
+ /**
32
+ * Recursively compares two path tries to find the first shared node with a different value.
33
+ *
34
+ * @param options - The options for the comparison
35
+ * @returns The path to the first differing node, or undefined if they are identical
36
+ *
37
+ * @remarks
38
+ * Ignores any nodes that are not shared between the two tries.
39
+ *
40
+ * @beta
41
+ */
42
+ export declare function getFirstDifferenceInCommonNodes<TItem extends {}>(options: IGetFirstDifferenceInCommonNodesOptions<TItem>): string | undefined;
43
+ //# sourceMappingURL=getFirstDifferenceInCommonNodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getFirstDifferenceInCommonNodes.d.ts","sourceRoot":"","sources":["../src/getFirstDifferenceInCommonNodes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,uCAAuC,CAAC,KAAK,SAAS,EAAE;IACvE;;OAEG;IACH,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACpC;;OAEG;IACH,MAAM,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,SAAS,EAAE,EAC9D,OAAO,EAAE,uCAAuC,CAAC,KAAK,CAAC,GACtD,MAAM,GAAG,SAAS,CAUpB"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.getFirstDifferenceInCommonNodes = getFirstDifferenceInCommonNodes;
6
+ /**
7
+ * Recursively compares two path tries to find the first shared node with a different value.
8
+ *
9
+ * @param options - The options for the comparison
10
+ * @returns The path to the first differing node, or undefined if they are identical
11
+ *
12
+ * @remarks
13
+ * Ignores any nodes that are not shared between the two tries.
14
+ *
15
+ * @beta
16
+ */
17
+ function getFirstDifferenceInCommonNodes(options) {
18
+ const { first, second, prefix = '', delimiter = '/', equals = defaultEquals } = options;
19
+ return getFirstDifferenceInCommonNodesInternal({
20
+ first,
21
+ second,
22
+ prefix,
23
+ delimiter,
24
+ equals
25
+ });
26
+ }
27
+ /**
28
+ * Recursively compares two path tries to find the first shared node with a different value.
29
+ *
30
+ * @param options - The options for the comparison
31
+ * @returns The path to the first differing node, or undefined if they are identical
32
+ *
33
+ * @remarks
34
+ * Ignores any nodes that are not shared between the two tries.
35
+ * Separated out to avoid redundant parameter defaulting in the recursive calls.
36
+ */
37
+ function getFirstDifferenceInCommonNodesInternal(options) {
38
+ const { first, second, prefix, delimiter, equals } = options;
39
+ const firstItem = first.value;
40
+ const secondItem = second.value;
41
+ if (firstItem !== undefined && secondItem !== undefined && !equals(firstItem, secondItem)) {
42
+ // If this value was present in both tries with different values, return the prefix for this node.
43
+ return prefix;
44
+ }
45
+ const { children: firstChildren } = first;
46
+ const { children: secondChildren } = second;
47
+ if (firstChildren && secondChildren) {
48
+ for (const [key, firstChild] of firstChildren) {
49
+ const secondChild = secondChildren.get(key);
50
+ if (!secondChild) {
51
+ continue;
52
+ }
53
+ const result = getFirstDifferenceInCommonNodesInternal({
54
+ first: firstChild,
55
+ second: secondChild,
56
+ prefix: key,
57
+ delimiter,
58
+ equals
59
+ });
60
+ if (result !== undefined) {
61
+ return prefix ? `${prefix}${delimiter}${result}` : result;
62
+ }
63
+ }
64
+ }
65
+ return;
66
+ }
67
+ /**
68
+ * Default equality function for comparing two items, using strict equality.
69
+ * @param a - The first item to compare
70
+ * @param b - The second item to compare
71
+ * @returns True if the items are reference equal, false otherwise
72
+ */
73
+ function defaultEquals(a, b) {
74
+ return a === b;
75
+ }
76
+ //# sourceMappingURL=getFirstDifferenceInCommonNodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getFirstDifferenceInCommonNodes.js","sourceRoot":"","sources":["../src/getFirstDifferenceInCommonNodes.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;AA6C3D,0EAYC;AAvBD;;;;;;;;;;GAUG;AACH,SAAgB,+BAA+B,CAC7C,OAAuD;IAEvD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,SAAS,GAAG,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAExF,OAAO,uCAAuC,CAAC;QAC7C,KAAK;QACL,MAAM;QACN,MAAM;QACN,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,uCAAuC,CAC9C,OAAiE;IAEjE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAE7D,MAAM,SAAS,GAAsB,KAAK,CAAC,KAAK,CAAC;IACjD,MAAM,UAAU,GAAsB,MAAM,CAAC,KAAK,CAAC;IAEnD,IAAI,SAAS,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;QAC1F,kGAAkG;QAClG,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAC1C,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAE5C,IAAI,aAAa,IAAI,cAAc,EAAE,CAAC;QACpC,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9C,MAAM,WAAW,GAA6C,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtF,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAuB,uCAAuC,CAAC;gBACzE,KAAK,EAAE,UAAU;gBACjB,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,GAAG;gBACX,SAAS;gBACT,MAAM;aACP,CAAC,CAAC;YAEH,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;AACT,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAQ,CAAQ,EAAE,CAAQ;IAC9C,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { IReadonlyPathTrieNode } from './LookupByPath';\n\n/**\n * Options for the getFirstDifferenceInCommonNodes function.\n * @beta\n */\nexport interface IGetFirstDifferenceInCommonNodesOptions<TItem extends {}> {\n /**\n * The first node to compare.\n */\n first: IReadonlyPathTrieNode<TItem>;\n /**\n * The second node to compare.\n */\n second: IReadonlyPathTrieNode<TItem>;\n /**\n * The path prefix to the current node.\n * @defaultValue ''\n */\n prefix?: string;\n /**\n * The delimiter used to join path segments.\n * @defaultValue '/'\n */\n delimiter?: string;\n /**\n * A function to compare the values of the nodes.\n * If not provided, strict equality (===) is used.\n */\n equals?: (a: TItem, b: TItem) => boolean;\n}\n\n/**\n * Recursively compares two path tries to find the first shared node with a different value.\n *\n * @param options - The options for the comparison\n * @returns The path to the first differing node, or undefined if they are identical\n *\n * @remarks\n * Ignores any nodes that are not shared between the two tries.\n *\n * @beta\n */\nexport function getFirstDifferenceInCommonNodes<TItem extends {}>(\n options: IGetFirstDifferenceInCommonNodesOptions<TItem>\n): string | undefined {\n const { first, second, prefix = '', delimiter = '/', equals = defaultEquals } = options;\n\n return getFirstDifferenceInCommonNodesInternal({\n first,\n second,\n prefix,\n delimiter,\n equals\n });\n}\n\n/**\n * Recursively compares two path tries to find the first shared node with a different value.\n *\n * @param options - The options for the comparison\n * @returns The path to the first differing node, or undefined if they are identical\n *\n * @remarks\n * Ignores any nodes that are not shared between the two tries.\n * Separated out to avoid redundant parameter defaulting in the recursive calls.\n */\nfunction getFirstDifferenceInCommonNodesInternal<TItem extends {}>(\n options: Required<IGetFirstDifferenceInCommonNodesOptions<TItem>>\n): string | undefined {\n const { first, second, prefix, delimiter, equals } = options;\n\n const firstItem: TItem | undefined = first.value;\n const secondItem: TItem | undefined = second.value;\n\n if (firstItem !== undefined && secondItem !== undefined && !equals(firstItem, secondItem)) {\n // If this value was present in both tries with different values, return the prefix for this node.\n return prefix;\n }\n\n const { children: firstChildren } = first;\n const { children: secondChildren } = second;\n\n if (firstChildren && secondChildren) {\n for (const [key, firstChild] of firstChildren) {\n const secondChild: IReadonlyPathTrieNode<TItem> | undefined = secondChildren.get(key);\n if (!secondChild) {\n continue;\n }\n const result: string | undefined = getFirstDifferenceInCommonNodesInternal({\n first: firstChild,\n second: secondChild,\n prefix: key,\n delimiter,\n equals\n });\n\n if (result !== undefined) {\n return prefix ? `${prefix}${delimiter}${result}` : result;\n }\n }\n }\n\n return;\n}\n\n/**\n * Default equality function for comparing two items, using strict equality.\n * @param a - The first item to compare\n * @param b - The second item to compare\n * @returns True if the items are reference equal, false otherwise\n */\nfunction defaultEquals<TItem>(a: TItem, b: TItem): boolean {\n return a === b;\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
- export type { IPrefixMatch, IReadonlyLookupByPath } from './LookupByPath';
6
+ export type { IPrefixMatch, IReadonlyLookupByPath, IReadonlyPathTrieNode } from './LookupByPath';
7
7
  export { LookupByPath } from './LookupByPath';
8
+ export type { IGetFirstDifferenceInCommonNodesOptions } from './getFirstDifferenceInCommonNodes';
9
+ export { getFirstDifferenceInCommonNodes } from './getFirstDifferenceInCommonNodes';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,uCAAuC,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC"}
package/lib/index.js CHANGED
@@ -2,7 +2,9 @@
2
2
  // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
3
  // See LICENSE in the project root for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.LookupByPath = void 0;
5
+ exports.getFirstDifferenceInCommonNodes = exports.LookupByPath = void 0;
6
6
  var LookupByPath_1 = require("./LookupByPath");
7
7
  Object.defineProperty(exports, "LookupByPath", { enumerable: true, get: function () { return LookupByPath_1.LookupByPath; } });
8
+ var getFirstDifferenceInCommonNodes_1 = require("./getFirstDifferenceInCommonNodes");
9
+ Object.defineProperty(exports, "getFirstDifferenceInCommonNodes", { enumerable: true, get: function () { return getFirstDifferenceInCommonNodes_1.getFirstDifferenceInCommonNodes; } });
8
10
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D,+CAA8C;AAArC,4GAAA,YAAY,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Strongly typed trie data structure for path and URL-like strings.\n *\n * @packageDocumentation\n */\n\nexport type { IPrefixMatch, IReadonlyLookupByPath } from './LookupByPath';\nexport { LookupByPath } from './LookupByPath';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,qFAAoF;AAA3E,kJAAA,+BAA+B,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Strongly typed trie data structure for path and URL-like strings.\n *\n * @packageDocumentation\n */\n\nexport type { IPrefixMatch, IReadonlyLookupByPath, IReadonlyPathTrieNode } from './LookupByPath';\nexport { LookupByPath } from './LookupByPath';\nexport type { IGetFirstDifferenceInCommonNodesOptions } from './getFirstDifferenceInCommonNodes';\nexport { getFirstDifferenceInCommonNodes } from './getFirstDifferenceInCommonNodes';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rushstack/lookup-by-path",
3
- "version": "0.5.22",
3
+ "version": "0.6.0",
4
4
  "description": "Strongly typed trie data structure for path and URL-like strings.",
5
5
  "main": "lib/index.js",
6
6
  "typings": "dist/lookup-by-path.d.ts",
@@ -18,7 +18,7 @@
18
18
  "directory": "libraries/lookup-by-path"
19
19
  },
20
20
  "devDependencies": {
21
- "@rushstack/heft": "0.73.4",
21
+ "@rushstack/heft": "0.73.5",
22
22
  "local-node-rig": "1.0.0"
23
23
  },
24
24
  "peerDependencies": {