@itwin/presentation-hierarchies 2.0.0-alpha.12 → 2.0.0-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +301 -16
  2. package/README.md +2 -2
  3. package/lib/cjs/hierarchies/HierarchyNode.d.ts +13 -11
  4. package/lib/cjs/hierarchies/HierarchyNode.d.ts.map +1 -1
  5. package/lib/cjs/hierarchies/HierarchyNode.js +18 -0
  6. package/lib/cjs/hierarchies/HierarchyNode.js.map +1 -1
  7. package/lib/cjs/hierarchies/HierarchyNodeIdentifier.d.ts +2 -0
  8. package/lib/cjs/hierarchies/HierarchyNodeIdentifier.d.ts.map +1 -1
  9. package/lib/cjs/hierarchies/HierarchyNodeIdentifier.js +23 -6
  10. package/lib/cjs/hierarchies/HierarchyNodeIdentifier.js.map +1 -1
  11. package/lib/cjs/hierarchies/HierarchyNodeKey.d.ts +5 -4
  12. package/lib/cjs/hierarchies/HierarchyNodeKey.d.ts.map +1 -1
  13. package/lib/cjs/hierarchies/HierarchyNodeKey.js.map +1 -1
  14. package/lib/cjs/hierarchies/HierarchyProvider.d.ts +3 -3
  15. package/lib/cjs/hierarchies/HierarchyProvider.d.ts.map +1 -1
  16. package/lib/cjs/hierarchies/HierarchyProvider.js.map +1 -1
  17. package/lib/cjs/hierarchies/HierarchySearch.d.ts +206 -78
  18. package/lib/cjs/hierarchies/HierarchySearch.d.ts.map +1 -1
  19. package/lib/cjs/hierarchies/HierarchySearch.js +315 -113
  20. package/lib/cjs/hierarchies/HierarchySearch.js.map +1 -1
  21. package/lib/cjs/hierarchies/imodel/IModelHierarchyDefinition.d.ts +2 -2
  22. package/lib/cjs/hierarchies/imodel/IModelHierarchyDefinition.d.ts.map +1 -1
  23. package/lib/cjs/hierarchies/imodel/IModelHierarchyDefinition.js.map +1 -1
  24. package/lib/cjs/hierarchies/imodel/IModelHierarchyNode.d.ts +3 -3
  25. package/lib/cjs/hierarchies/imodel/IModelHierarchyNode.d.ts.map +1 -1
  26. package/lib/cjs/hierarchies/imodel/IModelHierarchyNode.js.map +1 -1
  27. package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.d.ts +9 -4
  28. package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.d.ts.map +1 -1
  29. package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.js +25 -16
  30. package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.js.map +1 -1
  31. package/lib/cjs/hierarchies/imodel/NodeSelectQueryFactory.d.ts +4 -4
  32. package/lib/cjs/hierarchies/imodel/NodeSelectQueryFactory.d.ts.map +1 -1
  33. package/lib/cjs/hierarchies/imodel/NodeSelectQueryFactory.js +12 -9
  34. package/lib/cjs/hierarchies/imodel/NodeSelectQueryFactory.js.map +1 -1
  35. package/lib/cjs/hierarchies/imodel/PredicateBasedHierarchyDefinition.d.ts +3 -3
  36. package/lib/cjs/hierarchies/imodel/PredicateBasedHierarchyDefinition.d.ts.map +1 -1
  37. package/lib/cjs/hierarchies/imodel/PredicateBasedHierarchyDefinition.js.map +1 -1
  38. package/lib/cjs/hierarchies/imodel/SearchHierarchyDefinition.d.ts +2 -2
  39. package/lib/cjs/hierarchies/imodel/SearchHierarchyDefinition.d.ts.map +1 -1
  40. package/lib/cjs/hierarchies/imodel/SearchHierarchyDefinition.js +31 -55
  41. package/lib/cjs/hierarchies/imodel/SearchHierarchyDefinition.js.map +1 -1
  42. package/lib/cjs/hierarchies/imodel/TreeNodesReader.d.ts +2 -2
  43. package/lib/cjs/hierarchies/imodel/TreeNodesReader.d.ts.map +1 -1
  44. package/lib/cjs/hierarchies/imodel/TreeNodesReader.js +1 -1
  45. package/lib/cjs/hierarchies/imodel/TreeNodesReader.js.map +1 -1
  46. package/lib/cjs/hierarchies/imodel/operators/grouping/BaseClassGrouping.js.map +1 -1
  47. package/lib/cjs/hierarchies/imodel/operators/grouping/ClassGrouping.d.ts.map +1 -1
  48. package/lib/cjs/hierarchies/imodel/operators/grouping/ClassGrouping.js +4 -1
  49. package/lib/cjs/hierarchies/imodel/operators/grouping/ClassGrouping.js.map +1 -1
  50. package/lib/cjs/hierarchies/imodel/operators/grouping/PropertiesGrouping.d.ts +1 -1
  51. package/lib/cjs/hierarchies/imodel/operators/grouping/PropertiesGrouping.d.ts.map +1 -1
  52. package/lib/cjs/hierarchies/imodel/operators/grouping/PropertiesGrouping.js.map +1 -1
  53. package/lib/cjs/hierarchies/internal/operators/ReduceToMergeMap.d.ts +2 -2
  54. package/lib/cjs/hierarchies/internal/operators/ReduceToMergeMap.d.ts.map +1 -1
  55. package/lib/cjs/hierarchies/internal/operators/ReduceToMergeMap.js.map +1 -1
  56. package/lib/cjs/hierarchies/internal/operators/Sorting.d.ts.map +1 -1
  57. package/lib/cjs/hierarchies/internal/operators/Sorting.js.map +1 -1
  58. package/lib/cjs/presentation-hierarchies.d.ts +1 -1
  59. package/lib/cjs/presentation-hierarchies.d.ts.map +1 -1
  60. package/lib/cjs/presentation-hierarchies.js +2 -1
  61. package/lib/cjs/presentation-hierarchies.js.map +1 -1
  62. package/lib/esm/hierarchies/HierarchyNode.d.ts +13 -11
  63. package/lib/esm/hierarchies/HierarchyNode.d.ts.map +1 -1
  64. package/lib/esm/hierarchies/HierarchyNode.js +18 -0
  65. package/lib/esm/hierarchies/HierarchyNode.js.map +1 -1
  66. package/lib/esm/hierarchies/HierarchyNodeIdentifier.d.ts +2 -0
  67. package/lib/esm/hierarchies/HierarchyNodeIdentifier.d.ts.map +1 -1
  68. package/lib/esm/hierarchies/HierarchyNodeIdentifier.js +23 -6
  69. package/lib/esm/hierarchies/HierarchyNodeIdentifier.js.map +1 -1
  70. package/lib/esm/hierarchies/HierarchyNodeKey.d.ts +5 -4
  71. package/lib/esm/hierarchies/HierarchyNodeKey.d.ts.map +1 -1
  72. package/lib/esm/hierarchies/HierarchyNodeKey.js.map +1 -1
  73. package/lib/esm/hierarchies/HierarchyProvider.d.ts +3 -3
  74. package/lib/esm/hierarchies/HierarchyProvider.d.ts.map +1 -1
  75. package/lib/esm/hierarchies/HierarchyProvider.js.map +1 -1
  76. package/lib/esm/hierarchies/HierarchySearch.d.ts +206 -78
  77. package/lib/esm/hierarchies/HierarchySearch.d.ts.map +1 -1
  78. package/lib/esm/hierarchies/HierarchySearch.js +314 -111
  79. package/lib/esm/hierarchies/HierarchySearch.js.map +1 -1
  80. package/lib/esm/hierarchies/imodel/IModelHierarchyDefinition.d.ts +2 -2
  81. package/lib/esm/hierarchies/imodel/IModelHierarchyDefinition.d.ts.map +1 -1
  82. package/lib/esm/hierarchies/imodel/IModelHierarchyDefinition.js.map +1 -1
  83. package/lib/esm/hierarchies/imodel/IModelHierarchyNode.d.ts +3 -3
  84. package/lib/esm/hierarchies/imodel/IModelHierarchyNode.d.ts.map +1 -1
  85. package/lib/esm/hierarchies/imodel/IModelHierarchyNode.js.map +1 -1
  86. package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.d.ts +9 -4
  87. package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.d.ts.map +1 -1
  88. package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.js +26 -17
  89. package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.js.map +1 -1
  90. package/lib/esm/hierarchies/imodel/NodeSelectQueryFactory.d.ts +4 -4
  91. package/lib/esm/hierarchies/imodel/NodeSelectQueryFactory.d.ts.map +1 -1
  92. package/lib/esm/hierarchies/imodel/NodeSelectQueryFactory.js +13 -10
  93. package/lib/esm/hierarchies/imodel/NodeSelectQueryFactory.js.map +1 -1
  94. package/lib/esm/hierarchies/imodel/PredicateBasedHierarchyDefinition.d.ts +3 -3
  95. package/lib/esm/hierarchies/imodel/PredicateBasedHierarchyDefinition.d.ts.map +1 -1
  96. package/lib/esm/hierarchies/imodel/PredicateBasedHierarchyDefinition.js.map +1 -1
  97. package/lib/esm/hierarchies/imodel/SearchHierarchyDefinition.d.ts +2 -2
  98. package/lib/esm/hierarchies/imodel/SearchHierarchyDefinition.d.ts.map +1 -1
  99. package/lib/esm/hierarchies/imodel/SearchHierarchyDefinition.js +32 -56
  100. package/lib/esm/hierarchies/imodel/SearchHierarchyDefinition.js.map +1 -1
  101. package/lib/esm/hierarchies/imodel/TreeNodesReader.d.ts +2 -2
  102. package/lib/esm/hierarchies/imodel/TreeNodesReader.d.ts.map +1 -1
  103. package/lib/esm/hierarchies/imodel/TreeNodesReader.js +2 -2
  104. package/lib/esm/hierarchies/imodel/TreeNodesReader.js.map +1 -1
  105. package/lib/esm/hierarchies/imodel/operators/grouping/BaseClassGrouping.js.map +1 -1
  106. package/lib/esm/hierarchies/imodel/operators/grouping/ClassGrouping.d.ts.map +1 -1
  107. package/lib/esm/hierarchies/imodel/operators/grouping/ClassGrouping.js +4 -1
  108. package/lib/esm/hierarchies/imodel/operators/grouping/ClassGrouping.js.map +1 -1
  109. package/lib/esm/hierarchies/imodel/operators/grouping/PropertiesGrouping.d.ts +1 -1
  110. package/lib/esm/hierarchies/imodel/operators/grouping/PropertiesGrouping.d.ts.map +1 -1
  111. package/lib/esm/hierarchies/imodel/operators/grouping/PropertiesGrouping.js.map +1 -1
  112. package/lib/esm/hierarchies/internal/operators/ReduceToMergeMap.d.ts +2 -2
  113. package/lib/esm/hierarchies/internal/operators/ReduceToMergeMap.d.ts.map +1 -1
  114. package/lib/esm/hierarchies/internal/operators/ReduceToMergeMap.js.map +1 -1
  115. package/lib/esm/hierarchies/internal/operators/Sorting.d.ts.map +1 -1
  116. package/lib/esm/hierarchies/internal/operators/Sorting.js.map +1 -1
  117. package/lib/esm/presentation-hierarchies.d.ts +1 -1
  118. package/lib/esm/presentation-hierarchies.d.ts.map +1 -1
  119. package/lib/esm/presentation-hierarchies.js +1 -1
  120. package/lib/esm/presentation-hierarchies.js.map +1 -1
  121. package/package.json +10 -10
@@ -2,38 +2,11 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
+ import { firstValueFrom, from, map, reduce } from "rxjs";
6
+ import { Dictionary } from "@itwin/core-bentley";
5
7
  import { HierarchyNodeIdentifier } from "./HierarchyNodeIdentifier.js";
6
8
  import { HierarchyNodeKey } from "./HierarchyNodeKey.js";
7
- var HierarchySearchPathOptions;
8
- (function (HierarchySearchPathOptions) {
9
- function mergeRevealOptions(lhs, rhs) {
10
- if (rhs === true || lhs === true) {
11
- return true;
12
- }
13
- if (!rhs || !lhs) {
14
- return !!rhs ? rhs : lhs;
15
- }
16
- const lhsDepth = "depthInPath" in lhs ? lhs.depthInPath : lhs.depthInHierarchy;
17
- const rhsDepth = "depthInPath" in rhs ? rhs.depthInPath : rhs.depthInHierarchy;
18
- const isLhsDepthBasedOnPath = "depthInPath" in lhs;
19
- const isRhsDepthBasedOnPath = "depthInPath" in rhs;
20
- if (isLhsDepthBasedOnPath) {
21
- if (isRhsDepthBasedOnPath) {
22
- return lhsDepth > rhsDepth ? lhs : rhs;
23
- }
24
- return lhs;
25
- }
26
- if (isRhsDepthBasedOnPath) {
27
- return rhs;
28
- }
29
- return lhsDepth > rhsDepth ? lhs : rhs;
30
- }
31
- HierarchySearchPathOptions.mergeRevealOptions = mergeRevealOptions;
32
- function mergeAutoExpandOption(lhs, rhs) {
33
- return lhs || rhs ? true : undefined;
34
- }
35
- HierarchySearchPathOptions.mergeAutoExpandOption = mergeAutoExpandOption;
36
- })(HierarchySearchPathOptions || (HierarchySearchPathOptions = {}));
9
+ import { releaseMainThreadOnItemsCount } from "./internal/operators/ReleaseMainThread.js";
37
10
  /** @public */
38
11
  // eslint-disable-next-line @typescript-eslint/no-redeclare
39
12
  export var HierarchySearchPath;
@@ -57,14 +30,14 @@ export var HierarchySearchPath;
57
30
  * - else if only one of the inputs is an object, return it,
58
31
  * - else if both inputs are falsy, return `false` or `undefined`,
59
32
  * - else:
60
- * - if only one of the inputs has `depthInHierarchy` set, return the other one,
61
- * - else return the one with greater `depthInPath` or `depthInHierarchy`.
33
+ * - if only one of the inputs has `groupingLevel` set, return that one,
34
+ * - else compare by matching reveal type (`groupingLevel` or `depthInPath`) and return the deeper one.
62
35
  *
63
36
  * @public
64
37
  */
65
38
  function mergeOptions(lhs, rhs) {
66
- const reveal = HierarchySearchPathOptions.mergeRevealOptions(lhs?.reveal, rhs?.reveal);
67
- const autoExpand = HierarchySearchPathOptions.mergeAutoExpandOption(lhs?.autoExpand, rhs?.autoExpand);
39
+ const reveal = mergeRevealOptions(lhs?.reveal, rhs?.reveal);
40
+ const autoExpand = mergeAutoExpandOption(lhs?.autoExpand, rhs?.autoExpand);
68
41
  return reveal || autoExpand
69
42
  ? {
70
43
  ...(reveal !== undefined ? { reveal } : undefined),
@@ -73,7 +46,264 @@ export var HierarchySearchPath;
73
46
  : undefined;
74
47
  }
75
48
  HierarchySearchPath.mergeOptions = mergeOptions;
49
+ function mergeRevealOptions(lhs, rhs) {
50
+ if (rhs === true || lhs === true) {
51
+ return true;
52
+ }
53
+ if (!rhs || !lhs) {
54
+ return !!rhs ? rhs : lhs;
55
+ }
56
+ if ("groupingLevel" in lhs) {
57
+ if ("groupingLevel" in rhs) {
58
+ return lhs.groupingLevel > rhs.groupingLevel ? lhs : rhs;
59
+ }
60
+ return lhs;
61
+ }
62
+ else if ("groupingLevel" in rhs) {
63
+ return rhs;
64
+ }
65
+ return lhs.depthInPath > rhs.depthInPath ? lhs : rhs;
66
+ }
67
+ function mergeAutoExpandOption(lhs, rhs) {
68
+ return lhs || rhs ? true : undefined;
69
+ }
76
70
  })(HierarchySearchPath || (HierarchySearchPath = {}));
71
+ /** @public */
72
+ export var HierarchySearchTree;
73
+ (function (HierarchySearchTree) {
74
+ /**
75
+ * Create a `HierarchySearchTree` builder utility that accepts hierarchy search paths or search trees one by one and builds
76
+ * a `HierarchySearchTree` structure based on them.
77
+ *
78
+ * Usage example:
79
+ *
80
+ * ```ts
81
+ * const builder = HierarchySearchTree.createBuilder();
82
+ * for (const path of searchPaths) {
83
+ * builder.accept({ path });
84
+ * }
85
+ * const searchTree = builder.getTree();
86
+ * ```
87
+ *
88
+ * @public
89
+ */
90
+ function createBuilder() {
91
+ var _a;
92
+ return new (class Impl {
93
+ #rootsDictionary = new Dictionary(HierarchyNodeIdentifier.compare);
94
+ static #mapDictionaryToTree(dictionary, parentEntries, props) {
95
+ const list = [];
96
+ for (const { children, ...entry } of dictionary.values()) {
97
+ let processedEntry = entry;
98
+ if (props?.processEntry) {
99
+ processedEntry = props.processEntry({ treeEntry: entry, parentEntries });
100
+ }
101
+ if (!processedEntry) {
102
+ continue;
103
+ }
104
+ const { extras: _, ...entryWithoutExtras } = processedEntry;
105
+ parentEntries.push(processedEntry);
106
+ list.push({ ...entryWithoutExtras, ...(children ? { children: Impl.#mapDictionaryToTree(children, parentEntries, props) } : undefined) });
107
+ parentEntries.pop();
108
+ }
109
+ return list;
110
+ }
111
+ static #assignAutoExpandOptionsBasedOnReveal(treePath, revealOption) {
112
+ if (revealOption === true) {
113
+ Impl.#assignOptionsOnTreePath({
114
+ treePath,
115
+ targetEntryIndex: treePath.length - 1,
116
+ getEntryOptions: (index, targetEntryIndex) => {
117
+ if (index === targetEntryIndex) {
118
+ // auto-expand all grouping nodes of the revealed node
119
+ return { autoExpand: { groupingLevel: Number.MAX_SAFE_INTEGER } };
120
+ }
121
+ // auto-expand all parent nodes
122
+ return { autoExpand: true };
123
+ },
124
+ });
125
+ }
126
+ else if (revealOption && "groupingLevel" in revealOption) {
127
+ Impl.#assignOptionsOnTreePath({
128
+ treePath,
129
+ targetEntryIndex: treePath.length - 1,
130
+ getEntryOptions: (index, targetEntryIndex) => {
131
+ if (index === targetEntryIndex) {
132
+ // the last entry should have `autoExpand` with `groupingLevel` set to the value based on `reveal.groupingLevel`
133
+ return { autoExpand: { groupingLevel: Math.max(revealOption.groupingLevel - 1, 0) } };
134
+ }
135
+ // auto-expand all parent nodes
136
+ return { autoExpand: true };
137
+ },
138
+ });
139
+ }
140
+ else if (revealOption && "depthInPath" in revealOption) {
141
+ Impl.#assignOptionsOnTreePath({
142
+ treePath,
143
+ targetEntryIndex: Math.min(revealOption.depthInPath, treePath.length - 1),
144
+ getEntryOptions: (index, targetEntryIndex) => {
145
+ if (index === targetEntryIndex) {
146
+ // auto-expand all grouping nodes of the revealed node
147
+ return { autoExpand: { groupingLevel: Number.MAX_SAFE_INTEGER } };
148
+ }
149
+ // auto-expand all parent nodes
150
+ return { autoExpand: true };
151
+ },
152
+ });
153
+ }
154
+ }
155
+ static #assignOptionsOnTreePath({ treePath, targetEntryIndex, getEntryOptions, }) {
156
+ // set all parent entries to auto-expand
157
+ for (let i = 0; i <= targetEntryIndex; i++) {
158
+ const options = mergeOptions(treePath[i].options, getEntryOptions(i, targetEntryIndex));
159
+ if (options) {
160
+ treePath[i].options = options;
161
+ }
162
+ }
163
+ }
164
+ #acceptNode({ parentEntries, level, node, handler, }) {
165
+ let entry = level.get(node.identifier);
166
+ if (!entry) {
167
+ if (handler?.onNewEntry && !handler.onNewEntry({ parentEntries, inputEntry: node })) {
168
+ return undefined;
169
+ }
170
+ entry = {
171
+ identifier: node.identifier,
172
+ children: node.hasChildren ? new Dictionary(HierarchyNodeIdentifier.compare) : undefined,
173
+ extras: {},
174
+ };
175
+ level.set(node.identifier, entry);
176
+ }
177
+ const isNodeSearchTarget = node.isTarget || !node.hasChildren;
178
+ if (isNodeSearchTarget && entry.children) {
179
+ entry.isTarget = true;
180
+ }
181
+ if (!entry.children && node.hasChildren) {
182
+ // Existing leaf nodes are implied targets. Preserve that status when adding children.
183
+ entry.isTarget = true;
184
+ entry.children = new Dictionary(HierarchyNodeIdentifier.compare);
185
+ }
186
+ handler?.onEntryHandled?.({ parentEntries, treeEntry: entry, inputEntry: node });
187
+ return entry;
188
+ }
189
+ #acceptPath({ path, handler }) {
190
+ const normalized = HierarchySearchPath.normalize(path);
191
+ const treePath = [];
192
+ let currentLevel = this.#rootsDictionary;
193
+ for (let i = 0; i < normalized.path.length; i++) {
194
+ const identifier = normalized.path[i];
195
+ const acceptedNode = this.#acceptNode({
196
+ parentEntries: treePath,
197
+ node: { identifier, hasChildren: i < normalized.path.length - 1 },
198
+ level: currentLevel,
199
+ handler,
200
+ });
201
+ if (!acceptedNode) {
202
+ break;
203
+ }
204
+ treePath.push(acceptedNode);
205
+ if (!acceptedNode.children) {
206
+ break;
207
+ }
208
+ currentLevel = acceptedNode.children;
209
+ }
210
+ if (treePath.length === 0) {
211
+ return;
212
+ }
213
+ // handle auto-expand
214
+ const lastNode = treePath[treePath.length - 1];
215
+ if (normalized.options?.autoExpand) {
216
+ (lastNode.options ??= {}).autoExpand = true;
217
+ }
218
+ // handle auto-reveal
219
+ Impl.#assignAutoExpandOptionsBasedOnReveal(treePath, normalized.options?.reveal);
220
+ }
221
+ #acceptTree({ tree, handler }) {
222
+ const acceptTreeNode = (parentEntries, parentInputs, level, node) => {
223
+ const acceptedNode = this.#acceptNode({
224
+ parentEntries,
225
+ node: { ...node, hasChildren: node.children !== undefined },
226
+ level,
227
+ handler,
228
+ });
229
+ if (!acceptedNode) {
230
+ // It was decided to reject this node and its children, if any
231
+ return;
232
+ }
233
+ const treePath = [...parentEntries, acceptedNode];
234
+ const inputsPath = [...parentInputs, node];
235
+ if (!node.children || node.isTarget) {
236
+ // Found an effective search target - merge options from its path
237
+ Impl.#assignOptionsOnTreePath({
238
+ treePath,
239
+ targetEntryIndex: treePath.length - 1,
240
+ getEntryOptions: (index) => inputsPath[index].options,
241
+ });
242
+ }
243
+ const currentLevel = acceptedNode.children;
244
+ if (currentLevel) {
245
+ node.children?.forEach((child) => acceptTreeNode(treePath, inputsPath, currentLevel, child));
246
+ }
247
+ };
248
+ acceptTreeNode([], [], this.#rootsDictionary, tree);
249
+ }
250
+ accept(props) {
251
+ if ("path" in props) {
252
+ this.#acceptPath(props);
253
+ }
254
+ else {
255
+ this.#acceptTree(props);
256
+ }
257
+ return this;
258
+ }
259
+ getTree(props) {
260
+ return Impl.#mapDictionaryToTree(this.#rootsDictionary, [], props);
261
+ }
262
+ })();
263
+ }
264
+ HierarchySearchTree.createBuilder = createBuilder;
265
+ /**
266
+ * Builds a list of `HierarchySearchTree` nodes from an iterable of search paths. Shared
267
+ * path prefixes are merged so that each unique hierarchy node identifier appears only once
268
+ * per level. The resulting trees carry `isTarget`, `options`, and `children` attributes
269
+ * derived from the paths and their options (`autoExpand`, `reveal`).
270
+ *
271
+ * @public
272
+ */
273
+ async function createFromPathsList(paths) {
274
+ return firstValueFrom(from(paths).pipe(releaseMainThreadOnItemsCount(1000), reduce((builder, path) => builder.accept({ path }), createBuilder()), map((builder) => builder.getTree())));
275
+ }
276
+ HierarchySearchTree.createFromPathsList = createFromPathsList;
277
+ /**
278
+ * Merges two `HierarchySearchTree` option objects. For the `autoExpand` attribute,
279
+ * `true` takes precedence over `{ groupingLevel }`, and when both sides are
280
+ * `{ groupingLevel }` objects the larger value wins.
281
+ * @public
282
+ */
283
+ function mergeOptions(lhs, rhs) {
284
+ if (!lhs) {
285
+ return rhs;
286
+ }
287
+ if (!rhs) {
288
+ return lhs;
289
+ }
290
+ const autoExpand = mergeSearchTreeAutoExpandOption(lhs.autoExpand, rhs.autoExpand);
291
+ const options = {
292
+ ...(autoExpand ? { autoExpand } : undefined),
293
+ };
294
+ return Object.keys(options).length > 0 ? options : undefined;
295
+ }
296
+ HierarchySearchTree.mergeOptions = mergeOptions;
297
+ function mergeSearchTreeAutoExpandOption(lhs, rhs) {
298
+ if (!lhs) {
299
+ return rhs;
300
+ }
301
+ if (!rhs) {
302
+ return lhs;
303
+ }
304
+ return lhs === true || rhs === true ? true : { groupingLevel: Math.max(lhs.groupingLevel, rhs.groupingLevel) };
305
+ }
306
+ })(HierarchySearchTree || (HierarchySearchTree = {}));
77
307
  function extractSearchPropsInternal(rootLevelSearchProps, parentNode) {
78
308
  if (!parentNode) {
79
309
  return rootLevelSearchProps ? { childrenTargetPaths: rootLevelSearchProps, hasSearchTargetAncestor: false } : undefined;
@@ -94,41 +324,37 @@ export function createHierarchySearchHelper(rootLevelSearchProps, parentNode) {
94
324
  const searchProps = extractSearchPropsInternal(rootLevelSearchProps, parentNode);
95
325
  const hasSearch = !!searchProps;
96
326
  function saveSearchPropsFromPathsIntoReducer(extractionProps) {
97
- // Passes down matching normalized paths to the reducer.
98
- // It uses `nodeKey`, `pathMatcher` or `asyncPathMatcher` to check if `HierarchyNodeIdentifier` at the first position in search path matches the node
327
+ // Passes down matching hierarchy search trees to the reducer.
328
+ // It uses `nodeKey`, `pathMatcher` or `asyncPathMatcher` to check if `HierarchyNodeIdentifier` in the search tree item's identifier matches the node
99
329
  // and if it does, the path is passed down to the reducer.
100
- // This function returns a promise only if asyncPathMatcher returns a promise.
330
+ // This function returns a promise only if `asyncPathMatcher` returns a promise.
101
331
  if (!searchProps?.childrenTargetPaths) {
102
332
  return;
103
333
  }
104
- const matchedPathPromises = new Array();
105
- for (const childrenTargetPaths of searchProps.childrenTargetPaths) {
106
- const normalizedPath = HierarchySearchPath.normalize(childrenTargetPaths);
107
- /* c8 ignore next 3 */
108
- if (normalizedPath.path.length === 0) {
109
- continue;
110
- }
111
- if ("nodeKey" in extractionProps) {
112
- if ((HierarchyNodeKey.isGeneric(extractionProps.nodeKey) && HierarchyNodeIdentifier.equal(normalizedPath.path[0], extractionProps.nodeKey)) ||
113
- (HierarchyNodeKey.isInstances(extractionProps.nodeKey) &&
114
- extractionProps.nodeKey.instanceKeys.some((ik) => HierarchyNodeIdentifier.equal(normalizedPath.path[0], ik)))) {
115
- extractionProps.pathsReducer.accept(normalizedPath);
334
+ const matchedTreePromises = new Array();
335
+ for (const childrenSearchTree of searchProps.childrenTargetPaths) {
336
+ if ("asyncPathMatcher" in extractionProps) {
337
+ const matchesPossiblyPromise = extractionProps.asyncPathMatcher(childrenSearchTree.identifier);
338
+ if (matchesPossiblyPromise instanceof Promise) {
339
+ matchedTreePromises.push(matchesPossiblyPromise.then((matches) => (matches ? childrenSearchTree : undefined)));
340
+ }
341
+ else if (matchesPossiblyPromise) {
342
+ extractionProps.pathsReducer.accept(childrenSearchTree);
116
343
  }
117
- continue;
118
- }
119
- const matchesPossiblyPromise = "pathMatcher" in extractionProps ? extractionProps.pathMatcher(normalizedPath.path[0]) : extractionProps.asyncPathMatcher(normalizedPath.path[0]);
120
- if (matchesPossiblyPromise instanceof Promise) {
121
- matchedPathPromises.push(matchesPossiblyPromise.then((matches) => (matches ? normalizedPath : undefined)));
122
- continue;
123
344
  }
124
- if (matchesPossiblyPromise) {
125
- extractionProps.pathsReducer.accept(normalizedPath);
345
+ else {
346
+ const matches = "pathMatcher" in extractionProps
347
+ ? extractionProps.pathMatcher(childrenSearchTree.identifier)
348
+ : nodeKeyMatchesIdentifier(extractionProps.nodeKey, childrenSearchTree.identifier);
349
+ if (matches) {
350
+ extractionProps.pathsReducer.accept(childrenSearchTree);
351
+ }
126
352
  }
127
353
  }
128
- if (matchedPathPromises.length === 0) {
354
+ if (matchedTreePromises.length === 0) {
129
355
  return;
130
356
  }
131
- return Promise.all(matchedPathPromises).then((matchedPath) => matchedPath.forEach((normalizedPath) => normalizedPath && extractionProps.pathsReducer.accept(normalizedPath)));
357
+ return Promise.all(matchedTreePromises).then((matchedTrees) => matchedTrees.forEach((matchedTree) => matchedTree && extractionProps.pathsReducer.accept(matchedTree)));
132
358
  }
133
359
  function createChildNodeProps(props) {
134
360
  if (!hasSearch) {
@@ -136,15 +362,15 @@ export function createHierarchySearchHelper(rootLevelSearchProps, parentNode) {
136
362
  }
137
363
  const reducer = new MatchingSearchPathsReducer(searchProps.hasSearchTargetAncestor);
138
364
  if ("asyncPathMatcher" in props) {
139
- const extractResult = saveSearchPropsFromPathsIntoReducer({ pathsReducer: reducer, asyncPathMatcher: props.asyncPathMatcher });
365
+ const extractResult = saveSearchPropsFromPathsIntoReducer({ pathsReducer: reducer, nodeKey: props.nodeKey, asyncPathMatcher: props.asyncPathMatcher });
140
366
  if (extractResult instanceof Promise) {
141
- return extractResult.then(() => reducer.getNodeProps(props.parentKeys));
367
+ return extractResult.then(() => reducer.aggregatedOptions);
142
368
  }
143
369
  }
144
370
  else {
145
- saveSearchPropsFromPathsIntoReducer({ ...props, pathsReducer: reducer });
371
+ saveSearchPropsFromPathsIntoReducer({ pathsReducer: reducer, ...props });
146
372
  }
147
- return reducer.getNodeProps(props.parentKeys);
373
+ return reducer.aggregatedOptions;
148
374
  }
149
375
  return {
150
376
  /** Returns a flag indicating if the hierarchy level is filtered. */
@@ -164,10 +390,7 @@ export function createHierarchySearchHelper(rootLevelSearchProps, parentNode) {
164
390
  if (!searchProps?.childrenTargetPaths) {
165
391
  return undefined;
166
392
  }
167
- return searchProps.childrenTargetPaths
168
- .map(HierarchySearchPath.normalize)
169
- .filter(({ path }) => path.length > 0)
170
- .map(({ path }) => path[0]);
393
+ return searchProps.childrenTargetPaths.map(({ identifier }) => identifier);
171
394
  },
172
395
  /**
173
396
  * When a hierarchy node is created for a filtered hierarchy level, it needs some attributes (e.g. `search`
@@ -179,13 +402,16 @@ export function createHierarchySearchHelper(rootLevelSearchProps, parentNode) {
179
402
  * `nodeKey` prop can be used to check the whole identifier.
180
403
  *
181
404
  * There are multiple overloads of `createChildNodeProps`: depending on props type it returns different values:
182
- * - `parentKeys` is defined and `pathMatcher` or `nodeKey` is provided - returns undefined **or** `search` and `autoExpand` prop from `HierarchyNode`;
183
- * - `parentKeys` is undefined - does not return `HierarchyNode.autoExpand` option;
184
- * - props have `asyncPathMatcher` - returns either Promise or the regular return value based on whether or not `asyncPathMatcher` returns a promise.
405
+ * - `asyncPathMatcher` is provided - returns either Promise or the regular return value based on whether or not `asyncPathMatcher` returns a `Promise`.
406
+ * - `pathMatcher` or only `nodeKey` is provided - returns undefined **or** `search` and `autoExpand` prop from `HierarchyNode`;
185
407
  */
186
408
  createChildNodeProps,
187
409
  };
188
410
  }
411
+ function nodeKeyMatchesIdentifier(nodeKey, identifier) {
412
+ return ((HierarchyNodeKey.isGeneric(nodeKey) && HierarchyNodeIdentifier.equal(identifier, nodeKey)) ||
413
+ (HierarchyNodeKey.isInstances(nodeKey) && nodeKey.instanceKeys.some((ik) => HierarchyNodeIdentifier.equal(identifier, ik))));
414
+ }
189
415
  /**
190
416
  * Extracts information from search paths and later returns `search` and `autoExpand` values from `HierarchyNode`.
191
417
  *
@@ -199,56 +425,33 @@ class MatchingSearchPathsReducer {
199
425
  _hasSearchTargetAncestor;
200
426
  _childrenTargetPaths = new Array();
201
427
  _isSearchTarget = false;
202
- _searchTargetOptions = undefined;
203
- _revealOption = false;
428
+ _options = undefined;
204
429
  constructor(_hasSearchTargetAncestor) {
205
430
  this._hasSearchTargetAncestor = _hasSearchTargetAncestor;
206
431
  }
207
- accept(normalizedPath) {
208
- const { path, options } = normalizedPath;
209
- if (path.length === 1) {
432
+ accept(tree) {
433
+ if (tree.isTarget || tree.children === undefined) {
210
434
  this._isSearchTarget = true;
211
- this._searchTargetOptions = HierarchySearchPath.mergeOptions(this._searchTargetOptions, options);
212
435
  }
213
- else if (path.length > 1) {
214
- this._childrenTargetPaths.push({ path: path.slice(1), options });
215
- this._revealOption = HierarchySearchPathOptions.mergeRevealOptions(options?.reveal, this._revealOption);
436
+ if (tree.children && tree.children.length > 0) {
437
+ this._childrenTargetPaths.push(...tree.children);
216
438
  }
439
+ this._options = HierarchySearchTree.mergeOptions(this._options, tree.options);
217
440
  }
218
- getNodeProps(parentKeys) {
441
+ get aggregatedOptions() {
442
+ const search = this._hasSearchTargetAncestor || this._isSearchTarget || this._childrenTargetPaths.length > 0 || this._options
443
+ ? {
444
+ ...(this._hasSearchTargetAncestor ? { hasSearchTargetAncestor: true } : undefined),
445
+ ...(this._isSearchTarget ? { isSearchTarget: true } : undefined),
446
+ ...(this._childrenTargetPaths.length > 0 ? { childrenTargetPaths: this._childrenTargetPaths } : undefined),
447
+ ...(this._options ? { options: this._options } : undefined),
448
+ }
449
+ : undefined;
450
+ const autoExpand = this._options?.autoExpand === true;
219
451
  return {
220
- ...(this._hasSearchTargetAncestor || this._isSearchTarget || this._childrenTargetPaths.length > 0
221
- ? {
222
- search: {
223
- ...(this._hasSearchTargetAncestor ? { hasSearchTargetAncestor: true } : undefined),
224
- ...(this._isSearchTarget ? { isSearchTarget: true, searchTargetOptions: this._searchTargetOptions } : undefined),
225
- ...(this._childrenTargetPaths.length > 0 ? { childrenTargetPaths: this._childrenTargetPaths } : undefined),
226
- },
227
- }
228
- : undefined),
229
- ...(parentKeys &&
230
- (shouldAutoExpandBasedOnReveal({
231
- reveal: this._revealOption,
232
- nodePositionInHierarchy: parentKeys.length,
233
- nodePositionInPath: parentKeys.filter((key) => !HierarchyNodeKey.isGrouping(key)).length,
234
- }) ||
235
- !!this._searchTargetOptions?.autoExpand)
236
- ? { autoExpand: true }
237
- : undefined),
452
+ ...(search ? { search } : undefined),
453
+ ...(autoExpand ? { autoExpand } : undefined),
238
454
  };
239
455
  }
240
456
  }
241
- /** @internal */
242
- export function shouldAutoExpandBasedOnReveal({ reveal, nodePositionInPath, nodePositionInHierarchy, }) {
243
- if (!reveal) {
244
- return false;
245
- }
246
- if (reveal === true) {
247
- return true;
248
- }
249
- if ("depthInHierarchy" in reveal) {
250
- return nodePositionInHierarchy < reveal.depthInHierarchy;
251
- }
252
- return nodePositionInPath < reveal.depthInPath;
253
- }
254
457
  //# sourceMappingURL=HierarchySearch.js.map