@rushstack/lookup-by-path 0.4.7 → 0.5.1
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 +24 -0
- package/CHANGELOG.md +14 -1
- package/dist/lookup-by-path.d.ts +101 -10
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/LookupByPath.d.ts +101 -10
- package/lib/LookupByPath.d.ts.map +1 -1
- package/lib/LookupByPath.js +114 -8
- package/lib/LookupByPath.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/lookup-by-path",
|
|
3
3
|
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.5.1",
|
|
6
|
+
"tag": "@rushstack/lookup-by-path_v0.5.1",
|
|
7
|
+
"date": "Tue, 07 Jan 2025 22:17:32 GMT",
|
|
8
|
+
"comments": {
|
|
9
|
+
"dependency": [
|
|
10
|
+
{
|
|
11
|
+
"comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "0.5.0",
|
|
18
|
+
"tag": "@rushstack/lookup-by-path_v0.5.0",
|
|
19
|
+
"date": "Wed, 18 Dec 2024 01:11:33 GMT",
|
|
20
|
+
"comments": {
|
|
21
|
+
"minor": [
|
|
22
|
+
{
|
|
23
|
+
"comment": "Update all methods to accept optional override delimiters. Add `size`, `entries(), `get()`, `has()`, `removeItem()`. Make class iterable.\nExplicitly exclude `undefined` and `null` from the allowed types for the type parameter `TItem`."
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
4
28
|
{
|
|
5
29
|
"version": "0.4.7",
|
|
6
30
|
"tag": "@rushstack/lookup-by-path_v0.4.7",
|
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
|
|
3
|
+
This log was last generated on Tue, 07 Jan 2025 22:17:32 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
## 0.5.1
|
|
6
|
+
Tue, 07 Jan 2025 22:17:32 GMT
|
|
7
|
+
|
|
8
|
+
_Version update only_
|
|
9
|
+
|
|
10
|
+
## 0.5.0
|
|
11
|
+
Wed, 18 Dec 2024 01:11:33 GMT
|
|
12
|
+
|
|
13
|
+
### Minor changes
|
|
14
|
+
|
|
15
|
+
- Update all methods to accept optional override delimiters. Add `size`, `entries(), `get()`, `has()`, `removeItem()`. Make class iterable.
|
|
16
|
+
Explicitly exclude `undefined` and `null` from the allowed types for the type parameter `TItem`.
|
|
4
17
|
|
|
5
18
|
## 0.4.7
|
|
6
19
|
Sat, 14 Dec 2024 01:11:07 GMT
|
package/dist/lookup-by-path.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @beta
|
|
11
11
|
*/
|
|
12
|
-
export declare interface IPrefixMatch<TItem> {
|
|
12
|
+
export declare interface IPrefixMatch<TItem extends {}> {
|
|
13
13
|
/**
|
|
14
14
|
* The item that matched the prefix
|
|
15
15
|
*/
|
|
@@ -29,7 +29,7 @@ export declare interface IPrefixMatch<TItem> {
|
|
|
29
29
|
*
|
|
30
30
|
* @beta
|
|
31
31
|
*/
|
|
32
|
-
export declare interface IReadonlyLookupByPath<TItem> {
|
|
32
|
+
export declare interface IReadonlyLookupByPath<TItem extends {}> extends Iterable<[string, TItem]> {
|
|
33
33
|
/**
|
|
34
34
|
* Searches for the item associated with `childPath`, or the nearest ancestor of that path that
|
|
35
35
|
* has an associated item.
|
|
@@ -43,7 +43,7 @@ export declare interface IReadonlyLookupByPath<TItem> {
|
|
|
43
43
|
* trie.findChildPath('foo/bar/baz'); // returns 2
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
findChildPath(childPath: string): TItem | undefined;
|
|
46
|
+
findChildPath(childPath: string, delimiter?: string): TItem | undefined;
|
|
47
47
|
/**
|
|
48
48
|
* Searches for the item for which the recorded prefix is the longest matching prefix of `query`.
|
|
49
49
|
* Obtains both the item and the length of the matched prefix, so that the remainder of the path can be
|
|
@@ -58,7 +58,7 @@ export declare interface IReadonlyLookupByPath<TItem> {
|
|
|
58
58
|
* trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 }
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
-
findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined;
|
|
61
|
+
findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;
|
|
62
62
|
/**
|
|
63
63
|
* Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that
|
|
64
64
|
* has an associated item.
|
|
@@ -73,6 +73,51 @@ export declare interface IReadonlyLookupByPath<TItem> {
|
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
75
|
findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Determines if an entry exists exactly at the specified path.
|
|
78
|
+
*
|
|
79
|
+
* @returns `true` if an entry exists at the specified path, `false` otherwise
|
|
80
|
+
*/
|
|
81
|
+
has(query: string, delimiter?: string): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Retrieves the entry that exists exactly at the specified path, if any.
|
|
84
|
+
*
|
|
85
|
+
* @returns The entry that exists exactly at the specified path, or `undefined` if no entry exists.
|
|
86
|
+
*/
|
|
87
|
+
get(query: string, delimiter?: string): TItem | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Gets the number of entries in this trie.
|
|
90
|
+
*
|
|
91
|
+
* @returns The number of entries in this trie.
|
|
92
|
+
*/
|
|
93
|
+
get size(): number;
|
|
94
|
+
/**
|
|
95
|
+
* Iterates over the entries in this trie.
|
|
96
|
+
*
|
|
97
|
+
* @param query - An optional query. If specified only entries that start with the query will be returned.
|
|
98
|
+
*
|
|
99
|
+
* @returns An iterator over the entries under the specified query (or the root if no query is specified).
|
|
100
|
+
* @remarks
|
|
101
|
+
* Keys in the returned iterator use the provided delimiter to join segments.
|
|
102
|
+
* Iteration order is not specified.
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);
|
|
106
|
+
* [...trie.entries(undefined, ',')); // returns [['foo', 1], ['foo,bar', 2]]
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
110
|
+
/**
|
|
111
|
+
* Iterates over the entries in this trie.
|
|
112
|
+
*
|
|
113
|
+
* @param query - An optional query. If specified only entries that start with the query will be returned.
|
|
114
|
+
*
|
|
115
|
+
* @returns An iterator over the entries under the specified query (or the root if no query is specified).
|
|
116
|
+
* @remarks
|
|
117
|
+
* Keys in the returned iterator use the provided delimiter to join segments.
|
|
118
|
+
* Iteration order is not specified.
|
|
119
|
+
*/
|
|
120
|
+
[Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
76
121
|
/**
|
|
77
122
|
* Groups the provided map of info by the nearest entry in the trie that contains the path. If the path
|
|
78
123
|
* is not found in the trie, the info is ignored.
|
|
@@ -81,7 +126,7 @@ export declare interface IReadonlyLookupByPath<TItem> {
|
|
|
81
126
|
*
|
|
82
127
|
* @param infoByPath - The info to be grouped, keyed by path
|
|
83
128
|
*/
|
|
84
|
-
groupByChild<TInfo>(infoByPath: Map<string, TInfo
|
|
129
|
+
groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;
|
|
85
130
|
}
|
|
86
131
|
|
|
87
132
|
/**
|
|
@@ -104,7 +149,7 @@ export declare interface IReadonlyLookupByPath<TItem> {
|
|
|
104
149
|
* ```
|
|
105
150
|
* @beta
|
|
106
151
|
*/
|
|
107
|
-
export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem> {
|
|
152
|
+
export declare class LookupByPath<TItem extends {}> implements IReadonlyLookupByPath<TItem> {
|
|
108
153
|
/**
|
|
109
154
|
* The delimiter used to split paths
|
|
110
155
|
*/
|
|
@@ -113,6 +158,10 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
113
158
|
* The root node of the trie, corresponding to the path ''
|
|
114
159
|
*/
|
|
115
160
|
private readonly _root;
|
|
161
|
+
/**
|
|
162
|
+
* The number of entries in this trie.
|
|
163
|
+
*/
|
|
164
|
+
private _size;
|
|
116
165
|
/**
|
|
117
166
|
* Constructs a new `LookupByPath`
|
|
118
167
|
*
|
|
@@ -130,13 +179,32 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
130
179
|
*/
|
|
131
180
|
static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable<string>;
|
|
132
181
|
private static _iteratePrefixes;
|
|
182
|
+
/**
|
|
183
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
184
|
+
*/
|
|
185
|
+
get size(): number;
|
|
186
|
+
/**
|
|
187
|
+
* Deletes all entries from this `LookupByPath` instance.
|
|
188
|
+
*
|
|
189
|
+
* @returns this, for chained calls
|
|
190
|
+
*/
|
|
191
|
+
clear(): this;
|
|
133
192
|
/**
|
|
134
193
|
* Associates the value with the specified serialized path.
|
|
135
194
|
* If a value is already associated, will overwrite.
|
|
136
195
|
*
|
|
137
196
|
* @returns this, for chained calls
|
|
138
197
|
*/
|
|
139
|
-
setItem(serializedPath: string, value: TItem): this;
|
|
198
|
+
setItem(serializedPath: string, value: TItem, delimiter?: string): this;
|
|
199
|
+
/**
|
|
200
|
+
* Deletes an item if it exists.
|
|
201
|
+
* @param query - The path to the item to delete
|
|
202
|
+
* @param delimeter - Optional override delimeter for parsing the query
|
|
203
|
+
* @returns `true` if the item was found and deleted, `false` otherwise
|
|
204
|
+
* @remarks
|
|
205
|
+
* If the node has children with values, they will be retained.
|
|
206
|
+
*/
|
|
207
|
+
deleteItem(query: string, delimeter?: string): boolean;
|
|
140
208
|
/**
|
|
141
209
|
* Associates the value with the specified path.
|
|
142
210
|
* If a value is already associated, will overwrite.
|
|
@@ -147,11 +215,11 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
147
215
|
/**
|
|
148
216
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
149
217
|
*/
|
|
150
|
-
findChildPath(childPath: string): TItem | undefined;
|
|
218
|
+
findChildPath(childPath: string, delimiter?: string): TItem | undefined;
|
|
151
219
|
/**
|
|
152
220
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
153
221
|
*/
|
|
154
|
-
findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined;
|
|
222
|
+
findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;
|
|
155
223
|
/**
|
|
156
224
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
157
225
|
*/
|
|
@@ -159,7 +227,23 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
159
227
|
/**
|
|
160
228
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
161
229
|
*/
|
|
162
|
-
|
|
230
|
+
has(key: string, delimiter?: string): boolean;
|
|
231
|
+
/**
|
|
232
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
233
|
+
*/
|
|
234
|
+
get(key: string, delimiter?: string): TItem | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
237
|
+
*/
|
|
238
|
+
groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;
|
|
239
|
+
/**
|
|
240
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
241
|
+
*/
|
|
242
|
+
entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
243
|
+
/**
|
|
244
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
245
|
+
*/
|
|
246
|
+
[Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
163
247
|
/**
|
|
164
248
|
* Iterates through progressively longer prefixes of a given string and returns as soon
|
|
165
249
|
* as the number of candidate items that match the prefix are 1 or 0.
|
|
@@ -169,6 +253,13 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
169
253
|
* @returns the found item, or `undefined` if no item was found
|
|
170
254
|
*/
|
|
171
255
|
private _findLongestPrefixMatch;
|
|
256
|
+
/**
|
|
257
|
+
* Finds the node at the specified path, or `undefined` if no node was found.
|
|
258
|
+
*
|
|
259
|
+
* @param query - The path to the node to search for
|
|
260
|
+
* @returns The trie node at the specified path, or `undefined` if no node was found
|
|
261
|
+
*/
|
|
262
|
+
private _findNodeAtPrefix;
|
|
172
263
|
}
|
|
173
264
|
|
|
174
265
|
export { }
|
package/dist/tsdoc-metadata.json
CHANGED
package/lib/LookupByPath.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @beta
|
|
5
5
|
*/
|
|
6
|
-
export interface IPrefixMatch<TItem> {
|
|
6
|
+
export interface IPrefixMatch<TItem extends {}> {
|
|
7
7
|
/**
|
|
8
8
|
* The item that matched the prefix
|
|
9
9
|
*/
|
|
@@ -22,7 +22,7 @@ export interface IPrefixMatch<TItem> {
|
|
|
22
22
|
*
|
|
23
23
|
* @beta
|
|
24
24
|
*/
|
|
25
|
-
export interface IReadonlyLookupByPath<TItem> {
|
|
25
|
+
export interface IReadonlyLookupByPath<TItem extends {}> extends Iterable<[string, TItem]> {
|
|
26
26
|
/**
|
|
27
27
|
* Searches for the item associated with `childPath`, or the nearest ancestor of that path that
|
|
28
28
|
* has an associated item.
|
|
@@ -36,7 +36,7 @@ export interface IReadonlyLookupByPath<TItem> {
|
|
|
36
36
|
* trie.findChildPath('foo/bar/baz'); // returns 2
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
findChildPath(childPath: string): TItem | undefined;
|
|
39
|
+
findChildPath(childPath: string, delimiter?: string): TItem | undefined;
|
|
40
40
|
/**
|
|
41
41
|
* Searches for the item for which the recorded prefix is the longest matching prefix of `query`.
|
|
42
42
|
* Obtains both the item and the length of the matched prefix, so that the remainder of the path can be
|
|
@@ -51,7 +51,7 @@ export interface IReadonlyLookupByPath<TItem> {
|
|
|
51
51
|
* trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 }
|
|
52
52
|
* ```
|
|
53
53
|
*/
|
|
54
|
-
findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined;
|
|
54
|
+
findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;
|
|
55
55
|
/**
|
|
56
56
|
* Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that
|
|
57
57
|
* has an associated item.
|
|
@@ -66,6 +66,51 @@ export interface IReadonlyLookupByPath<TItem> {
|
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
68
|
findChildPathFromSegments(childPathSegments: Iterable<string>): TItem | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Determines if an entry exists exactly at the specified path.
|
|
71
|
+
*
|
|
72
|
+
* @returns `true` if an entry exists at the specified path, `false` otherwise
|
|
73
|
+
*/
|
|
74
|
+
has(query: string, delimiter?: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Retrieves the entry that exists exactly at the specified path, if any.
|
|
77
|
+
*
|
|
78
|
+
* @returns The entry that exists exactly at the specified path, or `undefined` if no entry exists.
|
|
79
|
+
*/
|
|
80
|
+
get(query: string, delimiter?: string): TItem | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Gets the number of entries in this trie.
|
|
83
|
+
*
|
|
84
|
+
* @returns The number of entries in this trie.
|
|
85
|
+
*/
|
|
86
|
+
get size(): number;
|
|
87
|
+
/**
|
|
88
|
+
* Iterates over the entries in this trie.
|
|
89
|
+
*
|
|
90
|
+
* @param query - An optional query. If specified only entries that start with the query will be returned.
|
|
91
|
+
*
|
|
92
|
+
* @returns An iterator over the entries under the specified query (or the root if no query is specified).
|
|
93
|
+
* @remarks
|
|
94
|
+
* Keys in the returned iterator use the provided delimiter to join segments.
|
|
95
|
+
* Iteration order is not specified.
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]);
|
|
99
|
+
* [...trie.entries(undefined, ',')); // returns [['foo', 1], ['foo,bar', 2]]
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
103
|
+
/**
|
|
104
|
+
* Iterates over the entries in this trie.
|
|
105
|
+
*
|
|
106
|
+
* @param query - An optional query. If specified only entries that start with the query will be returned.
|
|
107
|
+
*
|
|
108
|
+
* @returns An iterator over the entries under the specified query (or the root if no query is specified).
|
|
109
|
+
* @remarks
|
|
110
|
+
* Keys in the returned iterator use the provided delimiter to join segments.
|
|
111
|
+
* Iteration order is not specified.
|
|
112
|
+
*/
|
|
113
|
+
[Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
69
114
|
/**
|
|
70
115
|
* Groups the provided map of info by the nearest entry in the trie that contains the path. If the path
|
|
71
116
|
* is not found in the trie, the info is ignored.
|
|
@@ -74,7 +119,7 @@ export interface IReadonlyLookupByPath<TItem> {
|
|
|
74
119
|
*
|
|
75
120
|
* @param infoByPath - The info to be grouped, keyed by path
|
|
76
121
|
*/
|
|
77
|
-
groupByChild<TInfo>(infoByPath: Map<string, TInfo
|
|
122
|
+
groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;
|
|
78
123
|
}
|
|
79
124
|
/**
|
|
80
125
|
* This class is used to associate path-like-strings, such as those returned by `git` commands,
|
|
@@ -96,7 +141,7 @@ export interface IReadonlyLookupByPath<TItem> {
|
|
|
96
141
|
* ```
|
|
97
142
|
* @beta
|
|
98
143
|
*/
|
|
99
|
-
export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem> {
|
|
144
|
+
export declare class LookupByPath<TItem extends {}> implements IReadonlyLookupByPath<TItem> {
|
|
100
145
|
/**
|
|
101
146
|
* The delimiter used to split paths
|
|
102
147
|
*/
|
|
@@ -105,6 +150,10 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
105
150
|
* The root node of the trie, corresponding to the path ''
|
|
106
151
|
*/
|
|
107
152
|
private readonly _root;
|
|
153
|
+
/**
|
|
154
|
+
* The number of entries in this trie.
|
|
155
|
+
*/
|
|
156
|
+
private _size;
|
|
108
157
|
/**
|
|
109
158
|
* Constructs a new `LookupByPath`
|
|
110
159
|
*
|
|
@@ -122,13 +171,32 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
122
171
|
*/
|
|
123
172
|
static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable<string>;
|
|
124
173
|
private static _iteratePrefixes;
|
|
174
|
+
/**
|
|
175
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
176
|
+
*/
|
|
177
|
+
get size(): number;
|
|
178
|
+
/**
|
|
179
|
+
* Deletes all entries from this `LookupByPath` instance.
|
|
180
|
+
*
|
|
181
|
+
* @returns this, for chained calls
|
|
182
|
+
*/
|
|
183
|
+
clear(): this;
|
|
125
184
|
/**
|
|
126
185
|
* Associates the value with the specified serialized path.
|
|
127
186
|
* If a value is already associated, will overwrite.
|
|
128
187
|
*
|
|
129
188
|
* @returns this, for chained calls
|
|
130
189
|
*/
|
|
131
|
-
setItem(serializedPath: string, value: TItem): this;
|
|
190
|
+
setItem(serializedPath: string, value: TItem, delimiter?: string): this;
|
|
191
|
+
/**
|
|
192
|
+
* Deletes an item if it exists.
|
|
193
|
+
* @param query - The path to the item to delete
|
|
194
|
+
* @param delimeter - Optional override delimeter for parsing the query
|
|
195
|
+
* @returns `true` if the item was found and deleted, `false` otherwise
|
|
196
|
+
* @remarks
|
|
197
|
+
* If the node has children with values, they will be retained.
|
|
198
|
+
*/
|
|
199
|
+
deleteItem(query: string, delimeter?: string): boolean;
|
|
132
200
|
/**
|
|
133
201
|
* Associates the value with the specified path.
|
|
134
202
|
* If a value is already associated, will overwrite.
|
|
@@ -139,11 +207,11 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
139
207
|
/**
|
|
140
208
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
141
209
|
*/
|
|
142
|
-
findChildPath(childPath: string): TItem | undefined;
|
|
210
|
+
findChildPath(childPath: string, delimiter?: string): TItem | undefined;
|
|
143
211
|
/**
|
|
144
212
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
145
213
|
*/
|
|
146
|
-
findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined;
|
|
214
|
+
findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch<TItem> | undefined;
|
|
147
215
|
/**
|
|
148
216
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
149
217
|
*/
|
|
@@ -151,7 +219,23 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
151
219
|
/**
|
|
152
220
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
153
221
|
*/
|
|
154
|
-
|
|
222
|
+
has(key: string, delimiter?: string): boolean;
|
|
223
|
+
/**
|
|
224
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
225
|
+
*/
|
|
226
|
+
get(key: string, delimiter?: string): TItem | undefined;
|
|
227
|
+
/**
|
|
228
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
229
|
+
*/
|
|
230
|
+
groupByChild<TInfo>(infoByPath: Map<string, TInfo>, delimiter?: string): Map<TItem, Map<string, TInfo>>;
|
|
231
|
+
/**
|
|
232
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
233
|
+
*/
|
|
234
|
+
entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
235
|
+
/**
|
|
236
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
237
|
+
*/
|
|
238
|
+
[Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>;
|
|
155
239
|
/**
|
|
156
240
|
* Iterates through progressively longer prefixes of a given string and returns as soon
|
|
157
241
|
* as the number of candidate items that match the prefix are 1 or 0.
|
|
@@ -161,5 +245,12 @@ export declare class LookupByPath<TItem> implements IReadonlyLookupByPath<TItem>
|
|
|
161
245
|
* @returns the found item, or `undefined` if no item was found
|
|
162
246
|
*/
|
|
163
247
|
private _findLongestPrefixMatch;
|
|
248
|
+
/**
|
|
249
|
+
* Finds the node at the specified path, or `undefined` if no node was found.
|
|
250
|
+
*
|
|
251
|
+
* @param query - The path to the node to search for
|
|
252
|
+
* @returns The trie node at the specified path, or `undefined` if no node was found
|
|
253
|
+
*/
|
|
254
|
+
private _findNodeAtPrefix;
|
|
164
255
|
}
|
|
165
256
|
//# sourceMappingURL=LookupByPath.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LookupByPath.d.ts","sourceRoot":"","sources":["../src/LookupByPath.ts"],"names":[],"mappings":"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"}
|
package/lib/LookupByPath.js
CHANGED
|
@@ -35,6 +35,7 @@ class LookupByPath {
|
|
|
35
35
|
children: undefined
|
|
36
36
|
};
|
|
37
37
|
this.delimiter = delimiter !== null && delimiter !== void 0 ? delimiter : '/';
|
|
38
|
+
this._size = 0;
|
|
38
39
|
if (entries) {
|
|
39
40
|
for (const [path, item] of entries) {
|
|
40
41
|
this.setItem(path, item);
|
|
@@ -78,14 +79,48 @@ class LookupByPath {
|
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
84
|
+
*/
|
|
85
|
+
get size() {
|
|
86
|
+
return this._size;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Deletes all entries from this `LookupByPath` instance.
|
|
90
|
+
*
|
|
91
|
+
* @returns this, for chained calls
|
|
92
|
+
*/
|
|
93
|
+
clear() {
|
|
94
|
+
this._root.value = undefined;
|
|
95
|
+
this._root.children = undefined;
|
|
96
|
+
this._size = 0;
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
81
99
|
/**
|
|
82
100
|
* Associates the value with the specified serialized path.
|
|
83
101
|
* If a value is already associated, will overwrite.
|
|
84
102
|
*
|
|
85
103
|
* @returns this, for chained calls
|
|
86
104
|
*/
|
|
87
|
-
setItem(serializedPath, value) {
|
|
88
|
-
return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath,
|
|
105
|
+
setItem(serializedPath, value, delimiter = this.delimiter) {
|
|
106
|
+
return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, delimiter), value);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Deletes an item if it exists.
|
|
110
|
+
* @param query - The path to the item to delete
|
|
111
|
+
* @param delimeter - Optional override delimeter for parsing the query
|
|
112
|
+
* @returns `true` if the item was found and deleted, `false` otherwise
|
|
113
|
+
* @remarks
|
|
114
|
+
* If the node has children with values, they will be retained.
|
|
115
|
+
*/
|
|
116
|
+
deleteItem(query, delimeter = this.delimiter) {
|
|
117
|
+
const node = this._findNodeAtPrefix(query, delimeter);
|
|
118
|
+
if ((node === null || node === void 0 ? void 0 : node.value) !== undefined) {
|
|
119
|
+
node.value = undefined;
|
|
120
|
+
this._size--;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
89
124
|
}
|
|
90
125
|
/**
|
|
91
126
|
* Associates the value with the specified path.
|
|
@@ -108,20 +143,23 @@ class LookupByPath {
|
|
|
108
143
|
}
|
|
109
144
|
node = child;
|
|
110
145
|
}
|
|
146
|
+
if (node.value === undefined) {
|
|
147
|
+
this._size++;
|
|
148
|
+
}
|
|
111
149
|
node.value = value;
|
|
112
150
|
return this;
|
|
113
151
|
}
|
|
114
152
|
/**
|
|
115
153
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
116
154
|
*/
|
|
117
|
-
findChildPath(childPath) {
|
|
118
|
-
return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath,
|
|
155
|
+
findChildPath(childPath, delimiter = this.delimiter) {
|
|
156
|
+
return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, delimiter));
|
|
119
157
|
}
|
|
120
158
|
/**
|
|
121
159
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
122
160
|
*/
|
|
123
|
-
findLongestPrefixMatch(query) {
|
|
124
|
-
return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query,
|
|
161
|
+
findLongestPrefixMatch(query, delimiter = this.delimiter) {
|
|
162
|
+
return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, delimiter));
|
|
125
163
|
}
|
|
126
164
|
/**
|
|
127
165
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
@@ -149,10 +187,24 @@ class LookupByPath {
|
|
|
149
187
|
/**
|
|
150
188
|
* {@inheritdoc IReadonlyLookupByPath}
|
|
151
189
|
*/
|
|
152
|
-
|
|
190
|
+
has(key, delimiter = this.delimiter) {
|
|
191
|
+
const match = this.findLongestPrefixMatch(key, delimiter);
|
|
192
|
+
return (match === null || match === void 0 ? void 0 : match.index) === key.length;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
196
|
+
*/
|
|
197
|
+
get(key, delimiter = this.delimiter) {
|
|
198
|
+
const match = this.findLongestPrefixMatch(key, delimiter);
|
|
199
|
+
return (match === null || match === void 0 ? void 0 : match.index) === key.length ? match.value : undefined;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
203
|
+
*/
|
|
204
|
+
groupByChild(infoByPath, delimiter = this.delimiter) {
|
|
153
205
|
const groupedInfoByChild = new Map();
|
|
154
206
|
for (const [path, info] of infoByPath) {
|
|
155
|
-
const child = this.findChildPath(path);
|
|
207
|
+
const child = this.findChildPath(path, delimiter);
|
|
156
208
|
if (child === undefined) {
|
|
157
209
|
continue;
|
|
158
210
|
}
|
|
@@ -165,6 +217,40 @@ class LookupByPath {
|
|
|
165
217
|
}
|
|
166
218
|
return groupedInfoByChild;
|
|
167
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
222
|
+
*/
|
|
223
|
+
*entries(query, delimiter = this.delimiter) {
|
|
224
|
+
let root;
|
|
225
|
+
if (query) {
|
|
226
|
+
root = this._findNodeAtPrefix(query, delimiter);
|
|
227
|
+
if (!root) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
root = this._root;
|
|
233
|
+
}
|
|
234
|
+
const stack = [[query !== null && query !== void 0 ? query : '', root]];
|
|
235
|
+
while (stack.length > 0) {
|
|
236
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
237
|
+
const [prefix, node] = stack.pop();
|
|
238
|
+
if (node.value !== undefined) {
|
|
239
|
+
yield [prefix, node.value];
|
|
240
|
+
}
|
|
241
|
+
if (node.children) {
|
|
242
|
+
for (const [segment, child] of node.children) {
|
|
243
|
+
stack.push([prefix ? `${prefix}${delimiter}${segment}` : segment, child]);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* {@inheritdoc IReadonlyLookupByPath}
|
|
250
|
+
*/
|
|
251
|
+
[Symbol.iterator](query, delimiter = this.delimiter) {
|
|
252
|
+
return this.entries(query, delimiter);
|
|
253
|
+
}
|
|
168
254
|
/**
|
|
169
255
|
* Iterates through progressively longer prefixes of a given string and returns as soon
|
|
170
256
|
* as the number of candidate items that match the prefix are 1 or 0.
|
|
@@ -204,6 +290,26 @@ class LookupByPath {
|
|
|
204
290
|
}
|
|
205
291
|
return best;
|
|
206
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Finds the node at the specified path, or `undefined` if no node was found.
|
|
295
|
+
*
|
|
296
|
+
* @param query - The path to the node to search for
|
|
297
|
+
* @returns The trie node at the specified path, or `undefined` if no node was found
|
|
298
|
+
*/
|
|
299
|
+
_findNodeAtPrefix(query, delimiter = this.delimiter) {
|
|
300
|
+
let node = this._root;
|
|
301
|
+
for (const { prefix } of LookupByPath._iteratePrefixes(query, delimiter)) {
|
|
302
|
+
if (!node.children) {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
const child = node.children.get(prefix);
|
|
306
|
+
if (!child) {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
node = child;
|
|
310
|
+
}
|
|
311
|
+
return node;
|
|
312
|
+
}
|
|
207
313
|
}
|
|
208
314
|
exports.LookupByPath = LookupByPath;
|
|
209
315
|
//# sourceMappingURL=LookupByPath.js.map
|
package/lib/LookupByPath.js.map
CHANGED
|
@@ -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> {\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 * The readonly component of `LookupByPath`, to simplify unit testing.\n *\n * @beta\n */\nexport interface IReadonlyLookupByPath<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): 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): 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 * 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>): 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> implements IReadonlyLookupByPath<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 * {@inheritdoc IReadonlyLookupByPath}\n */\n public findChildPath(childPath: string): TItem | undefined {\n return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, this.delimiter));\n }\n\n /**\n * {@inheritdoc IReadonlyLookupByPath}\n */\n public findLongestPrefixMatch(query: string): IPrefixMatch<TItem> | undefined {\n return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, this.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 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"]}
|
|
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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/lookup-by-path",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
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.
|
|
21
|
+
"@rushstack/heft": "0.68.12",
|
|
22
22
|
"local-node-rig": "1.0.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|