treenode.ts 0.7.0 → 0.9.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.
@@ -1,28 +1,35 @@
1
- import { IParseable } from "./IParseable";
2
1
  /**
3
- * Search callback passed to `.pre`, `.post`, and `.breadth`.
4
2
  * @public
5
3
  */
6
- export type SearchCallback<T> = (node: TreeNode<T>) => boolean | void;
4
+ interface IParseable<T> {
5
+ model: T;
6
+ children: IParseable<T>[];
7
+ }
8
+
7
9
  /**
8
- * Search methods on TreeNode, passed to `.flatten`.
10
+ * Search callback passed to `.pre`, `.post`, and `.breadth`.
9
11
  * @public
10
12
  */
11
- export type SearchStrategy = "pre" | "post" | "breadth";
13
+ type SearchCallback<T> = (node: TreeNode<T>) => boolean | void;
12
14
  /**
13
- * Nested array representation of a tree.
15
+ * Search methods on TreeNode, passed to `.flatten`.
14
16
  * @public
15
17
  */
16
- export type NestedArray<T> = T | [T, ...(NestedArray<T> | T[])[]];
18
+ type SearchStrategy = "pre" | "post" | "breadth";
17
19
  /**
18
20
  * @public
19
21
  */
20
- export declare class TreeNode<T> {
22
+ declare class TreeNode<T> {
21
23
  model: T;
22
24
  parent: TreeNode<T> | null;
23
- children: TreeNode<T>[];
24
25
  private _index;
26
+ private _children;
25
27
  constructor(model: T, parent?: TreeNode<T> | null, children?: TreeNode<T>[]);
28
+ /**
29
+ * Returns the children of the node as a readonly array.
30
+ * Use add(), drop(), or swap() to modify children.
31
+ */
32
+ get children(): readonly TreeNode<T>[];
26
33
  /**
27
34
  * Parses object into a tree and returns the root node.
28
35
  */
@@ -66,12 +73,23 @@ export declare class TreeNode<T> {
66
73
  get siblings(): TreeNode<T>[];
67
74
  /**
68
75
  * Add node as a child.
76
+ * @param child - The node to add
77
+ * @param index - Optional index to insert at. If omitted, appends to end.
78
+ * @throws RangeError if index is out of bounds (negative or > children.length)
79
+ */
80
+ add(child: TreeNode<T>, index?: number): TreeNode<T>;
81
+ /**
82
+ * Swap children at indices i and j.
83
+ * @param i - First index
84
+ * @param j - Second index
69
85
  */
70
- add(child: TreeNode<T>): TreeNode<T>;
86
+ swap(i: number, j: number): void;
71
87
  /**
72
88
  * Add model as a child.
89
+ * @param model - The model to add
90
+ * @param index - Optional index to insert at. If omitted, appends to end.
73
91
  */
74
- addModel(model: T): TreeNode<T>;
92
+ addModel(model: T, index?: number): TreeNode<T>;
75
93
  /**
76
94
  * Remove current node and its children from the tree and return.
77
95
  */
@@ -125,22 +143,10 @@ export declare class TreeNode<T> {
125
143
  * Returns a list of nodes.
126
144
  */
127
145
  flatten(method: SearchStrategy): TreeNode<T>[];
128
- /**
129
- * Returns a nested array representation of the tree.
130
- * - Leaf -> value
131
- * - Single child -> [model, ...childResult]
132
- * - Multiple leaf children -> [model, [leaves...]]
133
- * - Multiple mixed children -> [model, child1Result, child2Result, ...]
134
- */
135
- toNestedArray(): NestedArray<T>;
136
- /**
137
- * Creates a tree from a nested array representation.
138
- * @see toNestedArray
139
- */
140
- static fromNestedArray<T>(input: NestedArray<T>): TreeNode<T>;
141
146
  /**
142
147
  * Returns an object representation of the tree.
143
148
  */
144
149
  toObject(): IParseable<T>;
145
150
  }
146
- //# sourceMappingURL=TreeNode.d.ts.map
151
+
152
+ export { type IParseable, type SearchCallback, type SearchStrategy, TreeNode };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,152 @@
1
- export { TreeNode, SearchCallback, SearchStrategy, NestedArray } from './TreeNode';
2
- export { IParseable } from './IParseable';
3
- //# sourceMappingURL=index.d.ts.map
1
+ /**
2
+ * @public
3
+ */
4
+ interface IParseable<T> {
5
+ model: T;
6
+ children: IParseable<T>[];
7
+ }
8
+
9
+ /**
10
+ * Search callback passed to `.pre`, `.post`, and `.breadth`.
11
+ * @public
12
+ */
13
+ type SearchCallback<T> = (node: TreeNode<T>) => boolean | void;
14
+ /**
15
+ * Search methods on TreeNode, passed to `.flatten`.
16
+ * @public
17
+ */
18
+ type SearchStrategy = "pre" | "post" | "breadth";
19
+ /**
20
+ * @public
21
+ */
22
+ declare class TreeNode<T> {
23
+ model: T;
24
+ parent: TreeNode<T> | null;
25
+ private _index;
26
+ private _children;
27
+ constructor(model: T, parent?: TreeNode<T> | null, children?: TreeNode<T>[]);
28
+ /**
29
+ * Returns the children of the node as a readonly array.
30
+ * Use add(), drop(), or swap() to modify children.
31
+ */
32
+ get children(): readonly TreeNode<T>[];
33
+ /**
34
+ * Parses object into a tree and returns the root node.
35
+ */
36
+ static parse<T>(tree: IParseable<T>): TreeNode<T>;
37
+ /**
38
+ * Index of the node among its siblings.
39
+ */
40
+ get index(): number;
41
+ /**
42
+ * Indices from the root to the node.
43
+ */
44
+ get indices(): number[];
45
+ /**
46
+ * Compressed path key: positive = run of first-children, negative = child index.
47
+ * e.g. [0,0,0,1,0,0] -> "3,-1,2"
48
+ */
49
+ get pathKey(): string;
50
+ /**
51
+ * Returns true if the node has children.
52
+ */
53
+ get hasChildren(): boolean;
54
+ /**
55
+ * Returns true if the node is the root (has no parent).
56
+ */
57
+ get isRoot(): boolean;
58
+ /**
59
+ * Returns true if the node is a leaf (has no children).
60
+ */
61
+ get isLeaf(): boolean;
62
+ /**
63
+ * Returns the root node of the tree.
64
+ */
65
+ get root(): TreeNode<T>;
66
+ /**
67
+ * Returns the depth of the node (root is 0).
68
+ */
69
+ get depth(): number;
70
+ /**
71
+ * Returns siblings of this node (excluding self).
72
+ */
73
+ get siblings(): TreeNode<T>[];
74
+ /**
75
+ * Add node as a child.
76
+ * @param child - The node to add
77
+ * @param index - Optional index to insert at. If omitted, appends to end.
78
+ * @throws RangeError if index is out of bounds (negative or > children.length)
79
+ */
80
+ add(child: TreeNode<T>, index?: number): TreeNode<T>;
81
+ /**
82
+ * Swap children at indices i and j.
83
+ * @param i - First index
84
+ * @param j - Second index
85
+ */
86
+ swap(i: number, j: number): void;
87
+ /**
88
+ * Add model as a child.
89
+ * @param model - The model to add
90
+ * @param index - Optional index to insert at. If omitted, appends to end.
91
+ */
92
+ addModel(model: T, index?: number): TreeNode<T>;
93
+ /**
94
+ * Remove current node and its children from the tree and return.
95
+ */
96
+ drop(): TreeNode<T>;
97
+ /**
98
+ * Returns a deep copy of structure, shallow copy of model.
99
+ */
100
+ clone(): TreeNode<T>;
101
+ /**
102
+ * Returns a node given a list of indices
103
+ */
104
+ fetch(indices: number[]): TreeNode<T> | null;
105
+ /**
106
+ * Returns a node given a pathKey string.
107
+ * @see pathKey
108
+ */
109
+ fetchByPathKey(pathKey: string): TreeNode<T> | null;
110
+ /**
111
+ * Returns list of nodes to the root.
112
+ */
113
+ path(): TreeNode<T>[];
114
+ /**
115
+ * Iterates over a node's children and returns a new root node.
116
+ */
117
+ map<U>(callback: (node: TreeNode<T>) => U): TreeNode<U>;
118
+ /**
119
+ * Iterates over a node's children and returns a new root node.
120
+ */
121
+ mapAsync<U>(callback: (node: TreeNode<T>, parent: TreeNode<U> | undefined) => Promise<U>, parent?: TreeNode<U>): Promise<TreeNode<U>>;
122
+ /**
123
+ * Breadth-first search, return true in the callback to end iteration.
124
+ */
125
+ breadth(callback: SearchCallback<T>): TreeNode<T> | null;
126
+ /**
127
+ * Depth-first pre-order search, return true in the callback to end iteration.
128
+ */
129
+ pre(callback: SearchCallback<T>): TreeNode<T> | null;
130
+ /**
131
+ * Depth-first post-order search, return true in the callback to end iteration.
132
+ */
133
+ post(callback: SearchCallback<T>): TreeNode<T> | null;
134
+ /**
135
+ * Find the first node matching the predicate.
136
+ */
137
+ find(predicate: (node: TreeNode<T>) => boolean, method?: SearchStrategy): TreeNode<T> | null;
138
+ /**
139
+ * Find all nodes matching the predicate.
140
+ */
141
+ findAll(predicate: (node: TreeNode<T>) => boolean, method?: SearchStrategy): TreeNode<T>[];
142
+ /**
143
+ * Returns a list of nodes.
144
+ */
145
+ flatten(method: SearchStrategy): TreeNode<T>[];
146
+ /**
147
+ * Returns an object representation of the tree.
148
+ */
149
+ toObject(): IParseable<T>;
150
+ }
151
+
152
+ export { type IParseable, type SearchCallback, type SearchStrategy, TreeNode };
package/dist/index.js CHANGED
@@ -1,6 +1,355 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TreeNode = void 0;
4
- var TreeNode_1 = require("./TreeNode");
5
- Object.defineProperty(exports, "TreeNode", { enumerable: true, get: function () { return TreeNode_1.TreeNode; } });
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ TreeNode: () => TreeNode
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/TreeNode.ts
28
+ var TreeNode = class _TreeNode {
29
+ constructor(model, parent = null, children = []) {
30
+ this.model = model;
31
+ this.parent = parent;
32
+ this._index = 0;
33
+ this._children = [];
34
+ this._children = children;
35
+ }
36
+ /**
37
+ * Returns the children of the node as a readonly array.
38
+ * Use add(), drop(), or swap() to modify children.
39
+ */
40
+ get children() {
41
+ return this._children;
42
+ }
43
+ /**
44
+ * Parses object into a tree and returns the root node.
45
+ */
46
+ static parse(tree) {
47
+ const node = new _TreeNode(tree.model);
48
+ tree.children.forEach((child) => node.add(_TreeNode.parse(child)));
49
+ return node;
50
+ }
51
+ /**
52
+ * Index of the node among its siblings.
53
+ */
54
+ get index() {
55
+ return this._index;
56
+ }
57
+ /**
58
+ * Indices from the root to the node.
59
+ */
60
+ get indices() {
61
+ const indices = [];
62
+ let node = this;
63
+ while (node.parent) {
64
+ indices.push(node.index);
65
+ node = node.parent;
66
+ }
67
+ return indices.reverse();
68
+ }
69
+ /**
70
+ * Compressed path key: positive = run of first-children, negative = child index.
71
+ * e.g. [0,0,0,1,0,0] -> "3,-1,2"
72
+ */
73
+ get pathKey() {
74
+ const indices = this.indices;
75
+ if (indices.length === 0) return "";
76
+ const parts = [];
77
+ let zeroCount = 0;
78
+ for (const idx of indices) {
79
+ if (idx === 0) {
80
+ zeroCount++;
81
+ } else {
82
+ if (zeroCount > 0) {
83
+ parts.push(zeroCount);
84
+ zeroCount = 0;
85
+ }
86
+ parts.push(-idx);
87
+ }
88
+ }
89
+ if (zeroCount > 0) {
90
+ parts.push(zeroCount);
91
+ }
92
+ return parts.join(",");
93
+ }
94
+ /**
95
+ * Returns true if the node has children.
96
+ */
97
+ get hasChildren() {
98
+ return this._children.length > 0;
99
+ }
100
+ /**
101
+ * Returns true if the node is the root (has no parent).
102
+ */
103
+ get isRoot() {
104
+ return this.parent === null;
105
+ }
106
+ /**
107
+ * Returns true if the node is a leaf (has no children).
108
+ */
109
+ get isLeaf() {
110
+ return !this.hasChildren;
111
+ }
112
+ /**
113
+ * Returns the root node of the tree.
114
+ */
115
+ get root() {
116
+ let node = this;
117
+ while (node.parent) {
118
+ node = node.parent;
119
+ }
120
+ return node;
121
+ }
122
+ /**
123
+ * Returns the depth of the node (root is 0).
124
+ */
125
+ get depth() {
126
+ return this.parent ? this.parent.depth + 1 : 0;
127
+ }
128
+ /**
129
+ * Returns siblings of this node (excluding self).
130
+ */
131
+ get siblings() {
132
+ if (this.isRoot) return [];
133
+ return this.parent.children.filter((child) => child !== this);
134
+ }
135
+ /**
136
+ * Add node as a child.
137
+ * @param child - The node to add
138
+ * @param index - Optional index to insert at. If omitted, appends to end.
139
+ * @throws RangeError if index is out of bounds (negative or > children.length)
140
+ */
141
+ add(child, index) {
142
+ child.parent = this;
143
+ if (index === void 0) {
144
+ child._index = this._children.length;
145
+ this._children.push(child);
146
+ } else {
147
+ if (index < 0 || index > this._children.length) {
148
+ throw new RangeError(`Invalid index: ${index}. Valid range: 0 to ${this._children.length}`);
149
+ }
150
+ this._children.splice(index, 0, child);
151
+ for (let i = index; i < this._children.length; i++) {
152
+ this._children[i]._index = i;
153
+ }
154
+ }
155
+ return child;
156
+ }
157
+ /**
158
+ * Swap children at indices i and j.
159
+ * @param i - First index
160
+ * @param j - Second index
161
+ */
162
+ swap(i, j) {
163
+ if (i < 0 || j < 0 || i >= this._children.length || j >= this._children.length) {
164
+ throw new RangeError(`Invalid indices: ${i}, ${j}. Children length: ${this._children.length}`);
165
+ }
166
+ if (i === j) return;
167
+ const temp = this._children[i];
168
+ this._children[i] = this._children[j];
169
+ this._children[j] = temp;
170
+ this._children[i]._index = i;
171
+ this._children[j]._index = j;
172
+ }
173
+ /**
174
+ * Add model as a child.
175
+ * @param model - The model to add
176
+ * @param index - Optional index to insert at. If omitted, appends to end.
177
+ */
178
+ addModel(model, index) {
179
+ return this.add(new _TreeNode(model), index);
180
+ }
181
+ /**
182
+ * Remove current node and its children from the tree and return.
183
+ */
184
+ drop() {
185
+ if (!this.isRoot) {
186
+ const idx = this._index;
187
+ const parentChildren = this.parent._children;
188
+ parentChildren.splice(idx, 1);
189
+ for (let i = idx; i < parentChildren.length; i++) {
190
+ parentChildren[i]._index = i;
191
+ }
192
+ this.parent = null;
193
+ this._index = 0;
194
+ }
195
+ return this;
196
+ }
197
+ /**
198
+ * Returns a deep copy of structure, shallow copy of model.
199
+ */
200
+ clone() {
201
+ const node = new _TreeNode(this.model);
202
+ node._children = this._children.map((child, i) => {
203
+ const newChild = child.clone();
204
+ newChild.parent = node;
205
+ newChild._index = i;
206
+ return newChild;
207
+ });
208
+ return node;
209
+ }
210
+ /**
211
+ * Returns a node given a list of indices
212
+ */
213
+ fetch(indices) {
214
+ let node = this;
215
+ for (const i of indices) {
216
+ node = node.children[i];
217
+ if (!node) return null;
218
+ }
219
+ return node;
220
+ }
221
+ /**
222
+ * Returns a node given a pathKey string.
223
+ * @see pathKey
224
+ */
225
+ fetchByPathKey(pathKey) {
226
+ if (pathKey === "") return this;
227
+ const indices = [];
228
+ const parts = pathKey.split(",").map(Number);
229
+ for (const part of parts) {
230
+ if (part >= 0) {
231
+ for (let i = 0; i < part; i++) {
232
+ indices.push(0);
233
+ }
234
+ } else {
235
+ indices.push(-part);
236
+ }
237
+ }
238
+ return this.fetch(indices);
239
+ }
240
+ /**
241
+ * Returns list of nodes to the root.
242
+ */
243
+ path() {
244
+ const path = [];
245
+ let node = this;
246
+ while (node) {
247
+ path.push(node);
248
+ node = node.parent;
249
+ }
250
+ return path.reverse();
251
+ }
252
+ /**
253
+ * Iterates over a node's children and returns a new root node.
254
+ */
255
+ map(callback) {
256
+ const node = new _TreeNode(callback(this));
257
+ node._children = this._children.map((child, i) => {
258
+ const newChild = child.map(callback);
259
+ newChild.parent = node;
260
+ newChild._index = i;
261
+ return newChild;
262
+ });
263
+ return node;
264
+ }
265
+ /**
266
+ * Iterates over a node's children and returns a new root node.
267
+ */
268
+ async mapAsync(callback, parent) {
269
+ const node = new _TreeNode(await callback(this, parent));
270
+ node._children = await Promise.all(this._children.map(async (child, i) => {
271
+ const newChild = await child.mapAsync(callback, node);
272
+ newChild.parent = node;
273
+ newChild._index = i;
274
+ return newChild;
275
+ }));
276
+ return node;
277
+ }
278
+ /**
279
+ * Breadth-first search, return true in the callback to end iteration.
280
+ */
281
+ breadth(callback) {
282
+ const queue = [this];
283
+ let head = 0;
284
+ while (head < queue.length) {
285
+ const node = queue[head++];
286
+ if (callback(node)) return node;
287
+ for (let i = 0, childCount = node.children.length; i < childCount; i++) {
288
+ queue.push(node.children[i]);
289
+ }
290
+ }
291
+ return null;
292
+ }
293
+ /**
294
+ * Depth-first pre-order search, return true in the callback to end iteration.
295
+ */
296
+ pre(callback) {
297
+ if (callback(this)) return this;
298
+ for (let i = 0, childCount = this.children.length; i < childCount; i++) {
299
+ const node = this.children[i].pre(callback);
300
+ if (node) return node;
301
+ }
302
+ return null;
303
+ }
304
+ /**
305
+ * Depth-first post-order search, return true in the callback to end iteration.
306
+ */
307
+ post(callback) {
308
+ for (let i = 0, childCount = this.children.length; i < childCount; i++) {
309
+ const node = this.children[i].post(callback);
310
+ if (node) return node;
311
+ }
312
+ if (callback(this)) return this;
313
+ return null;
314
+ }
315
+ /**
316
+ * Find the first node matching the predicate.
317
+ */
318
+ find(predicate, method = "pre") {
319
+ return this[method]((node) => predicate(node));
320
+ }
321
+ /**
322
+ * Find all nodes matching the predicate.
323
+ */
324
+ findAll(predicate, method = "pre") {
325
+ const results = [];
326
+ this[method]((node) => {
327
+ if (predicate(node)) results.push(node);
328
+ });
329
+ return results;
330
+ }
331
+ /**
332
+ * Returns a list of nodes.
333
+ */
334
+ flatten(method) {
335
+ const list = [];
336
+ this[method].call(this, (node) => {
337
+ list.push(node);
338
+ });
339
+ return list;
340
+ }
341
+ /**
342
+ * Returns an object representation of the tree.
343
+ */
344
+ toObject() {
345
+ return {
346
+ model: this.model,
347
+ children: this.children.map((child) => child.toObject())
348
+ };
349
+ }
350
+ };
351
+ // Annotate the CommonJS export names for ESM import in node:
352
+ 0 && (module.exports = {
353
+ TreeNode
354
+ });
6
355
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAmF;AAA1E,oGAAA,QAAQ,OAAA"}
1
+ {"version":3,"sources":["../src/index.ts","../src/TreeNode.ts"],"sourcesContent":["export { TreeNode, SearchCallback, SearchStrategy } from './TreeNode';\nexport { IParseable } from './IParseable';\n","import { IParseable } from \"./IParseable\";\n\n/**\n * Search callback passed to `.pre`, `.post`, and `.breadth`.\n * @public\n */\nexport type SearchCallback<T> = (node: TreeNode<T>) => boolean | void;\n\n/**\n * Search methods on TreeNode, passed to `.flatten`.\n * @public\n */\nexport type SearchStrategy = \"pre\" | \"post\" | \"breadth\";\n\n\n/**\n * @public\n */\nexport class TreeNode<T> {\n private _index: number = 0;\n private _children: TreeNode<T>[] = [];\n\n constructor(\n public model: T,\n public parent: TreeNode<T> | null = null,\n children: TreeNode<T>[] = []\n ) {\n this._children = children;\n }\n\n /**\n * Returns the children of the node as a readonly array.\n * Use add(), drop(), or swap() to modify children.\n */\n get children(): readonly TreeNode<T>[] {\n return this._children;\n }\n\n /**\n * Parses object into a tree and returns the root node.\n */\n static parse<T>(tree: IParseable<T>): TreeNode<T> {\n const node = new TreeNode(tree.model);\n tree.children.forEach((child) => node.add(TreeNode.parse(child)));\n return node;\n }\n\n /**\n * Index of the node among its siblings.\n */\n get index(): number {\n return this._index;\n }\n\n /**\n * Indices from the root to the node.\n */\n get indices(): number[] {\n const indices: number[] = [];\n let node: TreeNode<T> | null = this;\n while (node.parent) {\n indices.push(node.index);\n node = node.parent;\n }\n return indices.reverse();\n }\n\n /**\n * Compressed path key: positive = run of first-children, negative = child index.\n * e.g. [0,0,0,1,0,0] -> \"3,-1,2\"\n */\n get pathKey(): string {\n const indices = this.indices;\n if (indices.length === 0) return '';\n\n const parts: number[] = [];\n let zeroCount = 0;\n\n for (const idx of indices) {\n if (idx === 0) {\n zeroCount++;\n } else {\n if (zeroCount > 0) {\n parts.push(zeroCount);\n zeroCount = 0;\n }\n parts.push(-idx);\n }\n }\n\n if (zeroCount > 0) {\n parts.push(zeroCount);\n }\n\n return parts.join(',');\n }\n\n /**\n * Returns true if the node has children.\n */\n get hasChildren(): boolean {\n return this._children.length > 0;\n }\n\n /**\n * Returns true if the node is the root (has no parent).\n */\n get isRoot(): boolean {\n return this.parent === null;\n }\n\n /**\n * Returns true if the node is a leaf (has no children).\n */\n get isLeaf(): boolean {\n return !this.hasChildren;\n }\n\n /**\n * Returns the root node of the tree.\n */\n get root(): TreeNode<T> {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let node: TreeNode<T> = this;\n while (node.parent) {\n node = node.parent;\n }\n return node;\n }\n\n /**\n * Returns the depth of the node (root is 0).\n */\n get depth(): number {\n return this.parent ? this.parent.depth + 1 : 0;\n }\n\n /**\n * Returns siblings of this node (excluding self).\n */\n get siblings(): TreeNode<T>[] {\n if (this.isRoot) return [];\n return this.parent!.children.filter((child) => child !== this);\n }\n\n /**\n * Add node as a child.\n * @param child - The node to add\n * @param index - Optional index to insert at. If omitted, appends to end.\n * @throws RangeError if index is out of bounds (negative or > children.length)\n */\n add(child: TreeNode<T>, index?: number): TreeNode<T> {\n child.parent = this;\n if (index === undefined) {\n // Append at end\n child._index = this._children.length;\n this._children.push(child);\n } else {\n // Validate index\n if (index < 0 || index > this._children.length) {\n throw new RangeError(`Invalid index: ${index}. Valid range: 0 to ${this._children.length}`);\n }\n // Insert at specific index\n this._children.splice(index, 0, child);\n // Update indices for inserted and subsequent siblings\n for (let i = index; i < this._children.length; i++) {\n this._children[i]._index = i;\n }\n }\n return child;\n }\n\n /**\n * Swap children at indices i and j.\n * @param i - First index\n * @param j - Second index\n */\n swap(i: number, j: number): void {\n if (i < 0 || j < 0 || i >= this._children.length || j >= this._children.length) {\n throw new RangeError(`Invalid indices: ${i}, ${j}. Children length: ${this._children.length}`);\n }\n if (i === j) return;\n const temp = this._children[i];\n this._children[i] = this._children[j];\n this._children[j] = temp;\n this._children[i]._index = i;\n this._children[j]._index = j;\n }\n\n /**\n * Add model as a child.\n * @param model - The model to add\n * @param index - Optional index to insert at. If omitted, appends to end.\n */\n addModel(model: T, index?: number): TreeNode<T> {\n return this.add(new TreeNode<T>(model), index);\n }\n\n /**\n * Remove current node and its children from the tree and return.\n */\n drop(): TreeNode<T> {\n if (!this.isRoot) {\n const idx = this._index;\n const parentChildren = (this.parent as TreeNode<T>)._children;\n parentChildren.splice(idx, 1);\n // Update indices of subsequent siblings\n for (let i = idx; i < parentChildren.length; i++) {\n parentChildren[i]._index = i;\n }\n this.parent = null;\n this._index = 0;\n }\n return this;\n }\n\n /**\n * Returns a deep copy of structure, shallow copy of model.\n */\n clone(): TreeNode<T> {\n const node = new TreeNode<T>(this.model);\n node._children = this._children.map((child, i) => {\n const newChild = child.clone();\n newChild.parent = node;\n newChild._index = i;\n return newChild;\n });\n return node;\n }\n\n /**\n * Returns a node given a list of indices\n */\n fetch(indices: number[]): TreeNode<T> | null {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let node: TreeNode<T> = this;\n for (const i of indices) {\n node = node.children[i];\n if (!node) return null;\n }\n return node;\n }\n\n /**\n * Returns a node given a pathKey string.\n * @see pathKey\n */\n fetchByPathKey(pathKey: string): TreeNode<T> | null {\n if (pathKey === '') return this;\n\n const indices: number[] = [];\n const parts = pathKey.split(',').map(Number);\n\n for (const part of parts) {\n if (part >= 0) {\n for (let i = 0; i < part; i++) {\n indices.push(0);\n }\n } else {\n indices.push(-part);\n }\n }\n\n return this.fetch(indices);\n }\n\n /**\n * Returns list of nodes to the root.\n */\n path(): TreeNode<T>[] {\n const path: TreeNode<T>[] = [];\n let node: TreeNode<T> | null = this;\n while (node) {\n path.push(node);\n node = node.parent;\n }\n return path.reverse();\n }\n\n /**\n * Iterates over a node's children and returns a new root node.\n */\n map<U>(callback: (node: TreeNode<T>) => U): TreeNode<U> {\n const node = new TreeNode<U>(callback(this));\n node._children = this._children.map((child, i) => {\n const newChild = child.map(callback);\n newChild.parent = node;\n newChild._index = i;\n return newChild;\n });\n return node;\n }\n\n /**\n * Iterates over a node's children and returns a new root node.\n */\n async mapAsync<U>(callback: (node: TreeNode<T>, parent: TreeNode<U> | undefined) => Promise<U>, parent?: TreeNode<U>): Promise<TreeNode<U>>{\n const node = new TreeNode<U>(await callback(this, parent));\n node._children = await Promise.all(this._children.map(async (child, i) => {\n const newChild = await child.mapAsync(callback, node);\n newChild.parent = node;\n newChild._index = i;\n return newChild;\n }));\n return node;\n }\n\n /**\n * Breadth-first search, return true in the callback to end iteration.\n */\n breadth(callback: SearchCallback<T>): TreeNode<T> | null {\n const queue: TreeNode<T>[] = [this];\n let head = 0;\n\n while (head < queue.length) {\n const node = queue[head++];\n if (callback(node)) return node;\n for (let i = 0, childCount = node.children.length; i < childCount; i++) {\n queue.push(node.children[i]);\n }\n }\n\n return null;\n }\n\n /**\n * Depth-first pre-order search, return true in the callback to end iteration.\n */\n pre(callback: SearchCallback<T>): TreeNode<T> | null {\n if (callback(this)) return this;\n\n for (let i = 0, childCount = this.children.length; i < childCount; i++) {\n const node = this.children[i].pre(callback);\n if (node) return node;\n }\n\n return null;\n }\n\n /**\n * Depth-first post-order search, return true in the callback to end iteration.\n */\n post(callback: SearchCallback<T>): TreeNode<T> | null {\n for (let i = 0, childCount = this.children.length; i < childCount; i++) {\n const node = this.children[i].post(callback);\n if (node) return node;\n }\n\n if (callback(this)) return this;\n\n return null;\n }\n\n /**\n * Find the first node matching the predicate.\n */\n find(predicate: (node: TreeNode<T>) => boolean, method: SearchStrategy = \"pre\"): TreeNode<T> | null {\n return this[method]((node) => predicate(node));\n }\n\n /**\n * Find all nodes matching the predicate.\n */\n findAll(predicate: (node: TreeNode<T>) => boolean, method: SearchStrategy = \"pre\"): TreeNode<T>[] {\n const results: TreeNode<T>[] = [];\n this[method]((node) => {\n if (predicate(node)) results.push(node);\n });\n return results;\n }\n\n /**\n * Returns a list of nodes.\n */\n flatten(method: SearchStrategy): TreeNode<T>[] {\n const list: TreeNode<T>[] = [];\n this[method].call(this, (node) => {\n list.push(node);\n });\n return list;\n }\n\n /**\n * Returns an object representation of the tree.\n */\n toObject(): IParseable<T> {\n return {\n model: this.model,\n children: this.children.map((child) => child.toObject()),\n };\n }\n}\n"],"mappings":"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","names":[]}