@rushstack/lookup-by-path 0.2.4 → 0.3.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,30 @@
1
1
  {
2
2
  "name": "@rushstack/lookup-by-path",
3
3
  "entries": [
4
+ {
5
+ "version": "0.3.0",
6
+ "tag": "@rushstack/lookup-by-path_v0.3.0",
7
+ "date": "Thu, 03 Oct 2024 15:11:00 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Allow for a map of file paths to arbitrary info to be grouped by the nearest entry in the LookupByPath trie"
12
+ }
13
+ ]
14
+ }
15
+ },
16
+ {
17
+ "version": "0.2.5",
18
+ "tag": "@rushstack/lookup-by-path_v0.2.5",
19
+ "date": "Wed, 02 Oct 2024 00:11:19 GMT",
20
+ "comments": {
21
+ "dependency": [
22
+ {
23
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`"
24
+ }
25
+ ]
26
+ }
27
+ },
4
28
  {
5
29
  "version": "0.2.4",
6
30
  "tag": "@rushstack/lookup-by-path_v0.2.4",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Change Log - @rushstack/lookup-by-path
2
2
 
3
- This log was last generated on Tue, 01 Oct 2024 00:11:28 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 03 Oct 2024 15:11:00 GMT and should not be manually modified.
4
+
5
+ ## 0.3.0
6
+ Thu, 03 Oct 2024 15:11:00 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Allow for a map of file paths to arbitrary info to be grouped by the nearest entry in the LookupByPath trie
11
+
12
+ ## 0.2.5
13
+ Wed, 02 Oct 2024 00:11:19 GMT
14
+
15
+ _Version update only_
4
16
 
5
17
  ## 0.2.4
6
18
  Tue, 01 Oct 2024 00:11:28 GMT
@@ -127,6 +127,15 @@ export declare class LookupByPath<TItem> {
127
127
  * ```
128
128
  */
129
129
  findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;
130
+ /**
131
+ * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path
132
+ * is not found in the trie, the info is ignored.
133
+ *
134
+ * @returns The grouped info, grouped by the nearest entry in the trie that contains the path
135
+ *
136
+ * @param infoByPath - The info to be grouped, keyed by path
137
+ */
138
+ groupByChild<TInfo>(infoByPath: Map<string, TInfo>): Map<TItem, Map<string, TInfo>>;
130
139
  /**
131
140
  * Iterates through progressively longer prefixes of a given string and returns as soon
132
141
  * as the number of candidate items that match the prefix are 1 or 0.
@@ -120,6 +120,15 @@ export declare class LookupByPath<TItem> {
120
120
  * ```
121
121
  */
122
122
  findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;
123
+ /**
124
+ * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path
125
+ * is not found in the trie, the info is ignored.
126
+ *
127
+ * @returns The grouped info, grouped by the nearest entry in the trie that contains the path
128
+ *
129
+ * @param infoByPath - The info to be grouped, keyed by path
130
+ */
131
+ groupByChild<TInfo>(infoByPath: Map<string, TInfo>): Map<TItem, Map<string, TInfo>>;
123
132
  /**
124
133
  * Iterates through progressively longer prefixes of a given string and returns as soon
125
134
  * as the number of candidate items that match the prefix are 1 or 0.
@@ -1 +1 @@
1
- {"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"AA4BA;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK;IACjC;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,YAAY,CAAC,KAAK;IAC7B;;OAEG;IACH,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAE7C;;;;OAIG;gBACgB,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM;IAe1E;;;;;;;;OAQG;WACY,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,QAAQ,CAAC,MAAM,CAAC;IAMrG,OAAO,CAAC,MAAM,CAAE,gBAAgB;IA2BhC;;;;;OAKG;IACI,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAI1D;;;;;OAKG;IACI,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAuB9E;;;;;;;;;;;;OAYG;IACI,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAI1D;;;;;;;;;;;;;OAaG;IACI,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,SAAS;IAI7E;;;;;;;;;;;;OAYG;IACI,yBAAyB,CAAC,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,SAAS;IAqBxF;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;CAgChC"}
1
+ {"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"AA4BA;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK;IACjC;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,YAAY,CAAC,KAAK;IAC7B;;OAEG;IACH,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAE7C;;;;OAIG;gBACgB,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM;IAe1E;;;;;;;;OAQG;WACY,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,QAAQ,CAAC,MAAM,CAAC;IAMrG,OAAO,CAAC,MAAM,CAAE,gBAAgB;IA2BhC;;;;;OAKG;IACI,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAI1D;;;;;OAKG;IACI,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAuB9E;;;;;;;;;;;;OAYG;IACI,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAI1D;;;;;;;;;;;;;OAaG;IACI,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,SAAS;IAI7E;;;;;;;;;;;;OAYG;IACI,yBAAyB,CAAC,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,SAAS;IAqBxF;;;;;;;OAOG;IACI,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAmB1F;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;CAgChC"}
@@ -177,6 +177,30 @@ class LookupByPath {
177
177
  }
178
178
  return best;
179
179
  }
180
+ /**
181
+ * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path
182
+ * is not found in the trie, the info is ignored.
183
+ *
184
+ * @returns The grouped info, grouped by the nearest entry in the trie that contains the path
185
+ *
186
+ * @param infoByPath - The info to be grouped, keyed by path
187
+ */
188
+ groupByChild(infoByPath) {
189
+ const groupedInfoByChild = new Map();
190
+ for (const [path, info] of infoByPath) {
191
+ const child = this.findChildPath(path);
192
+ if (child === undefined) {
193
+ continue;
194
+ }
195
+ let groupedInfo = groupedInfoByChild.get(child);
196
+ if (!groupedInfo) {
197
+ groupedInfo = new Map();
198
+ groupedInfoByChild.set(child, groupedInfo);
199
+ }
200
+ groupedInfo.set(path, info);
201
+ }
202
+ return groupedInfoByChild;
203
+ }
180
204
  /**
181
205
  * Iterates through progressively longer prefixes of a given string and returns as soon
182
206
  * as the number of candidate items that match the prefix are 1 or 0.
@@ -1 +1 @@
1
- {"version":3,"file":"LookupByPath.js","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AA+C3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAa,YAAY;IAUvB;;;;OAIG;IACH,YAAmB,OAAmC,EAAE,SAAkB;QACxE,IAAI,CAAC,KAAK,GAAG;YACX,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,SAAS;SACpB,CAAC;QAEF,IAAI,CAAC,SAAS,GAAG,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;QAElC,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,CAAC,mBAAmB,CAAC,cAAsB,EAAE,YAAoB,GAAG;QAChF,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,SAAS,CAAC,EAAE,CAAC;YAC3E,MAAM,WAAW,CAAC,MAAM,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,CAAC,gBAAgB,CAAC,KAAa,EAAE,YAAoB,GAAG;QACrE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QAED,IAAI,aAAa,GAAW,CAAC,CAAC;QAC9B,IAAI,SAAS,GAAW,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEjD,mBAAmB;QACnB,OAAO,SAAS,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM;gBACJ,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,SAAS,CAAC;gBAC7C,KAAK,EAAE,SAAS;aACjB,CAAC;YACF,aAAa,GAAG,SAAS,GAAG,CAAC,CAAC;YAC9B,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACtD,CAAC;QAED,eAAe;QACf,IAAI,aAAa,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM;gBACJ,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC;gBAChD,KAAK,EAAE,KAAK,CAAC,MAAM;aACpB,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,OAAO,CAAC,cAAsB,EAAE,KAAY;QACjD,OAAO,IAAI,CAAC,mBAAmB,CAAC,YAAY,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3G,CAAC;IAED;;;;;OAKG;IACI,mBAAmB,CAAC,YAA8B,EAAE,KAAY;QACrE,IAAI,IAAI,GAAyB,IAAI,CAAC,KAAK,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;YAC5B,CAAC;YACD,IAAI,KAAK,GAAqC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,QAAQ,CAAC,GAAG,CACf,OAAO,EACP,CAAC,KAAK,GAAG;oBACP,KAAK,EAAE,SAAS;oBAChB,QAAQ,EAAE,SAAS;iBACpB,CAAC,CACH,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,aAAa,CAAC,SAAiB;QACpC,OAAO,IAAI,CAAC,yBAAyB,CAAC,YAAY,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACrG,CAAC;IAED;;;;;;;;;;;;;OAaG;IACI,sBAAsB,CAAC,KAAa;QACzC,OAAO,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,yBAAyB,CAAC,iBAAmC;;QAClE,IAAI,IAAI,GAAyB,IAAI,CAAC,KAAK,CAAC;QAC5C,IAAI,IAAI,GAAsB,IAAI,CAAC,KAAK,CAAC;QACzC,gBAAgB;QAChB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;gBACxC,MAAM,KAAK,GAAqC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC3E,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM;gBACR,CAAC;gBACD,IAAI,GAAG,KAAK,CAAC;gBACb,IAAI,GAAG,MAAA,IAAI,CAAC,KAAK,mCAAI,IAAI,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACnB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACK,uBAAuB,CAAC,QAAgC;QAC9D,IAAI,IAAI,GAAyB,IAAI,CAAC,KAAK,CAAC;QAC5C,IAAI,IAAI,GAAoC,IAAI,CAAC,KAAK;YACpD,CAAC,CAAC;gBACE,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,CAAC;gBACR,SAAS,EAAE,SAAS;aACrB;YACH,CAAC,CAAC,SAAS,CAAC;QACd,gBAAgB;QAChB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC/C,MAAM,KAAK,GAAqC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACxE,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM;gBACR,CAAC;gBACD,IAAI,GAAG,KAAK,CAAC;gBACb,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC7B,IAAI,GAAG;wBACL,KAAK,EAAE,IAAI,CAAC,KAAK;wBACjB,KAAK;wBACL,SAAS,EAAE,IAAI;qBAChB,CAAC;gBACJ,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACnB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA5ND,oCA4NC","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> {\n /**\n * The value that exactly matches the current relative path\n */\n value: TItem | undefined;\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 * 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> {\n /**\n * The item that matched the prefix\n */\n value: TItem;\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n /**\n * The last match found (with a shorter prefix), if any\n */\n lastMatch?: IPrefixMatch<TItem>;\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> {\n /**\n * The delimiter used to split paths\n */\n public readonly delimiter: string;\n /**\n * The root node of the trie, corresponding to the path ''\n */\n private readonly _root: IPathTrieNode<TItem>;\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\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 * 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): this {\n return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, this.delimiter), value);\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 node.value = value;\n\n return this;\n }\n\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 public findChildPath(childPath: string): TItem | undefined {\n return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, this.delimiter));\n }\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 public findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined {\n return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, this.delimiter));\n }\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 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 * 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"]}
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> {\n /**\n * The value that exactly matches the current relative path\n */\n value: TItem | undefined;\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 * 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> {\n /**\n * The item that matched the prefix\n */\n value: TItem;\n /**\n * The index of the first character after the matched prefix\n */\n index: number;\n /**\n * The last match found (with a shorter prefix), if any\n */\n lastMatch?: IPrefixMatch<TItem>;\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> {\n /**\n * The delimiter used to split paths\n */\n public readonly delimiter: string;\n /**\n * The root node of the trie, corresponding to the path ''\n */\n private readonly _root: IPathTrieNode<TItem>;\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\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 * 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): this {\n return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, this.delimiter), value);\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 node.value = value;\n\n return this;\n }\n\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 public findChildPath(childPath: string): TItem | undefined {\n return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, this.delimiter));\n }\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 public findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined {\n return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, this.delimiter));\n }\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 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 * 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 public groupByChild<TInfo>(infoByPath: Map<string, TInfo>): 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);\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 * 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rushstack/lookup-by-path",
3
- "version": "0.2.4",
3
+ "version": "0.3.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.68.1",
21
+ "@rushstack/heft": "0.68.2",
22
22
  "local-node-rig": "1.0.0"
23
23
  },
24
24
  "peerDependencies": {
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=LookupByPath.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LookupByPath.test.d.ts","sourceRoot":"","sources":["../src/LookupByPath.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"LookupByPath.test.js","sourceRoot":"","sources":["../src/LookupByPath.test.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\nimport { LookupByPath } from './LookupByPath';\n\ndescribe(LookupByPath.iteratePathSegments.name, () => {\n it('returns empty for an empty string', () => {\n const result = [...LookupByPath.iteratePathSegments('')];\n expect(result.length).toEqual(0);\n });\n it('returns the only segment of a trival string', () => {\n const result = [...LookupByPath.iteratePathSegments('foo')];\n expect(result).toEqual(['foo']);\n });\n it('treats backslashes as ordinary characters, per POSIX', () => {\n const result = [...LookupByPath.iteratePathSegments('foo\\\\bar\\\\baz')];\n expect(result).toEqual(['foo\\\\bar\\\\baz']);\n });\n it('iterates segments', () => {\n const result = [...LookupByPath.iteratePathSegments('foo/bar/baz')];\n expect(result).toEqual(['foo', 'bar', 'baz']);\n });\n it('returns correct last single character segment', () => {\n const result = [...LookupByPath.iteratePathSegments('foo/a')];\n expect(result).toEqual(['foo', 'a']);\n });\n});\n\ndescribe(LookupByPath.prototype.findChildPath.name, () => {\n it('returns empty for an empty tree', () => {\n expect(new LookupByPath().findChildPath('foo')).toEqual(undefined);\n });\n it('returns the matching node for a trivial tree', () => {\n expect(new LookupByPath([['foo', 1]]).findChildPath('foo')).toEqual(1);\n });\n it('returns the matching node for a single-layer tree', () => {\n const tree: LookupByPath<number> = new LookupByPath([\n ['foo', 1],\n ['bar', 2],\n ['baz', 3]\n ]);\n\n expect(tree.findChildPath('foo')).toEqual(1);\n expect(tree.findChildPath('bar')).toEqual(2);\n expect(tree.findChildPath('baz')).toEqual(3);\n expect(tree.findChildPath('buzz')).toEqual(undefined);\n });\n it('returns the matching parent for multi-layer queries', () => {\n const tree: LookupByPath<number> = new LookupByPath([\n ['foo', 1],\n ['bar', 2],\n ['baz', 3]\n ]);\n\n expect(tree.findChildPath('foo/bar')).toEqual(1);\n expect(tree.findChildPath('bar/baz')).toEqual(2);\n expect(tree.findChildPath('baz/foo')).toEqual(3);\n expect(tree.findChildPath('foo/foo')).toEqual(1);\n });\n it('returns the matching parent for multi-layer queries in multi-layer trees', () => {\n const tree: LookupByPath<number> = new LookupByPath([\n ['foo', 1],\n ['bar', 2],\n ['baz', 3],\n ['foo/bar', 4],\n ['foo/bar/baz', 5],\n ['baz/foo', 6],\n ['baz/baz/baz/baz', 7]\n ]);\n\n expect(tree.findChildPath('foo/foo')).toEqual(1);\n expect(tree.findChildPath('foo/bar\\\\baz')).toEqual(1);\n\n expect(tree.findChildPath('bar/baz')).toEqual(2);\n\n expect(tree.findChildPath('baz/bar')).toEqual(3);\n expect(tree.findChildPath('baz/baz')).toEqual(3);\n expect(tree.findChildPath('baz/baz/baz')).toEqual(3);\n\n expect(tree.findChildPath('foo/bar')).toEqual(4);\n expect(tree.findChildPath('foo/bar/foo')).toEqual(4);\n\n expect(tree.findChildPath('foo/bar/baz')).toEqual(5);\n expect(tree.findChildPath('foo/bar/baz/baz/baz/baz/baz')).toEqual(5);\n\n expect(tree.findChildPath('baz/foo/')).toEqual(6);\n\n expect(tree.findChildPath('baz/baz/baz/baz')).toEqual(7);\n\n expect(tree.findChildPath('')).toEqual(undefined);\n expect(tree.findChildPath('foofoo')).toEqual(undefined);\n expect(tree.findChildPath('foo\\\\bar\\\\baz')).toEqual(undefined);\n });\n it('handles custom delimiters', () => {\n const tree: LookupByPath<number> = new LookupByPath(\n [\n ['foo,bar', 1],\n ['foo/bar', 2]\n ],\n ','\n );\n\n expect(tree.findChildPath('foo/bar,baz')).toEqual(2);\n expect(tree.findChildPath('foo,bar/baz')).toEqual(undefined);\n expect(tree.findChildPathFromSegments(['foo', 'bar', 'baz'])).toEqual(1);\n });\n});\n\ndescribe(LookupByPath.prototype.findLongestPrefixMatch.name, () => {\n it('returns empty for an empty tree', () => {\n expect(new LookupByPath().findLongestPrefixMatch('foo')).toEqual(undefined);\n });\n it('returns the matching node for a trivial tree', () => {\n expect(new LookupByPath([['foo', 1]]).findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 });\n });\n it('returns the matching node for a single-layer tree', () => {\n const tree: LookupByPath<number> = new LookupByPath([\n ['foo', 1],\n ['barbar', 2],\n ['baz', 3]\n ]);\n\n expect(tree.findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 });\n expect(tree.findLongestPrefixMatch('barbar')).toEqual({ value: 2, index: 6 });\n expect(tree.findLongestPrefixMatch('baz')).toEqual({ value: 3, index: 3 });\n expect(tree.findLongestPrefixMatch('buzz')).toEqual(undefined);\n });\n it('returns the matching parent for multi-layer queries', () => {\n const tree: LookupByPath<number> = new LookupByPath([\n ['foo', 1],\n ['barbar', 2],\n ['baz', 3],\n ['foo/bar', 4]\n ]);\n\n expect(tree.findLongestPrefixMatch('foo/bar')).toEqual({\n value: 4,\n index: 7,\n lastMatch: { value: 1, index: 3 }\n });\n expect(tree.findLongestPrefixMatch('barbar/baz')).toEqual({ value: 2, index: 6 });\n expect(tree.findLongestPrefixMatch('baz/foo')).toEqual({ value: 3, index: 3 });\n expect(tree.findLongestPrefixMatch('foo/foo')).toEqual({ value: 1, index: 3 });\n });\n});\n"]}