fast-tree-builder 0.0.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright 2023 László BULIK
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the “Software”),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # fast-tree-builder
2
+
3
+ [![Build Status](https://github.com/lionel87/fast-tree-builder/actions/workflows/coveralls.yaml/badge.svg)](https://github.com/lionel87/fast-tree-builder/actions/workflows/coveralls.yaml)
4
+ [![Coverage Status](https://coveralls.io/repos/github/lionel87/fast-tree-builder/badge.svg?branch=master)](https://coveralls.io/github/lionel87/fast-tree-builder?branch=master)
5
+ ![npms.io (quality)](https://img.shields.io/npms-io/quality-score/fast-tree-builder?label=quality)
6
+ ![Maintenance](https://img.shields.io/maintenance/yes/2023)
7
+
8
+ `fast-tree-builder` is an npm package that allows you to efficiently build trees from iterable data structures. With its optimized algorithm, strong TypeScript typings, and customizable node structure, it provides a reliable solution for organizing and manipulating hierarchical data.
9
+
10
+
11
+ ## Features
12
+
13
+ Efficient Tree Building: The package utilizes an optimized algorithm to construct trees efficiently, ensuring quick performance even with large datasets.
14
+
15
+ - **Bi-Directional Tree Traversal**: Traverse the built tree in both directions, enabling easy navigation between parent and child nodes.
16
+
17
+ - **Strong TypeScript Typings**: Enjoy the benefits of type safety with comprehensive TypeScript typings. The package provides detailed type definitions to enhance your development experience.
18
+
19
+ - **Fully Customizable Node Structure**: Tailor the structure of the nodes in the built tree to meet your specific requirements. You have the freedom to define data, parent, and children key names according to your application's needs. To avoid circular references parent links can be turned off which helps generating JSON data.
20
+
21
+ - **Works on Any Iterable Data Structure**: Whether you have an array, set, or any other iterable data structure, `fast-tree-builder` can process it seamlessly, making it compatible with a wide range of use cases.
22
+
23
+ - **No Sorting Required**: The package does not require your input data to be sorted, saving you preprocessing time and effort.
24
+
25
+ - **Flexible Key and Parent Key Types**: You can use any JavaScript type as keys. Items are matched by comparing `key === parentKey`.
26
+
27
+ - **Map of Nodes**: Retrieve a `Map` object containing the nodes of the built tree, enabling easy entry and access on any point of the tree.
28
+
29
+ - **Support for Multiple Root Nodes**: The package supports building trees with multiple root nodes.
30
+
31
+ - **Support for Parent Key Validation**: Enables you to validate parent keys while building the tree. When a node missing its parent, an error will be thrown.
32
+
33
+
34
+ ## Installation
35
+
36
+ To install `fast-tree-builder`, use npm:
37
+
38
+ ```sh
39
+ npm install fast-tree-builder
40
+ ```
41
+
42
+ or
43
+
44
+ ```sh
45
+ yarn add fast-tree-builder
46
+ ```
47
+
48
+
49
+ ## Usage
50
+
51
+ Here are some examples showcasing the usage of `fast-tree-builder` and their expected outputs:
52
+
53
+ ### Example 1: Basic Tree Building
54
+
55
+ ```typescript
56
+ import buildTree from 'fast-tree-builder';
57
+
58
+ const items = [
59
+ { id: 1, parent: null, name: 'Root 1' },
60
+ { id: 2, parent: null, name: 'Root 2' },
61
+ { id: 3, parent: 1, name: 'Child 1.1' },
62
+ { id: 4, parent: 1, name: 'Child 1.2' },
63
+ { id: 5, parent: 2, name: 'Child 2.1' },
64
+ ];
65
+
66
+ const { roots, nodes } = buildTree(items, {
67
+ key: 'id',
68
+ parentKey: 'parent',
69
+ nodeDataKey: 'data',
70
+ nodeParentKey: 'parent',
71
+ nodeChildrenKey: 'children',
72
+ });
73
+
74
+ console.log(roots[0].data.name);
75
+ // Expected output: Root 1
76
+
77
+ console.log(roots[0].children[1].data.name);
78
+ // Expected output: Child 1.2
79
+
80
+ console.log(roots[0].children[1].parent.data.name);
81
+ // Expected output: Root 1
82
+
83
+ console.log(roots);
84
+ // Expected output: [
85
+ // { data: { id: 1, parent: null, name: 'Root 1' }, children: [
86
+ // { data: { id: 3, parent: 1, name: 'Child 1.1' }, parent: { ... } },
87
+ // { data: { id: 4, parent: 1, name: 'Child 1.2' }, parent: { ... } }
88
+ // ] },
89
+ // { data: { id: 2, parent: null, name: 'Root 2' }, children: [
90
+ // { data: { id: 5, parent: 2, name: 'Child 2.1' }, parent: { ... } }
91
+ // ] }
92
+ // ]
93
+
94
+ console.log(nodes);
95
+ // Expected output: Map {
96
+ // 1 => { data: { id: 1, parent: null, name: 'Root 1' }, children: [
97
+ // { data: { id: 3, parent: 1, name: 'Child 1.1' }, parent: { ... } },
98
+ // { data: { id: 4, parent: 1, name: 'Child 1.2' }, parent: { ... } }
99
+ // ] },
100
+ // 2 => { data: { id: 2, parent: null, name: 'Root 2' }, children: [
101
+ // { data: { id: 5, parent: 2, name: 'Child 2.1' }, parent: { ... } }
102
+ // ] },
103
+ // 3 => { data: { id: 3, parent: 1, name: 'Child 1.1' }, parent: { ... } },
104
+ // 4 => { data: { id: 4, parent: 1, name: 'Child 1.2' }, parent: { ... } },
105
+ // 5 => { data: { id: 5, parent: 2, name: 'Child 2.1' }, parent: { ... } }
106
+ // }
107
+ ```
108
+
109
+
110
+ ### Example 2: Customized Node Structure
111
+
112
+ ```typescript
113
+ import buildTree from 'fast-tree-builder';
114
+
115
+ const items = [
116
+ { key: { n: 1 }, parentKey: null, name: 'Root 1' },
117
+ { key: { n: 2 }, parentKey: null, name: 'Root 2' },
118
+ { key: { n: 3 }, parentKey: { n: 1 }, name: 'Child 1.1' },
119
+ { key: { n: 4 }, parentKey: { n: 1 }, name: 'Child 1.2' },
120
+ { key: { n: 5 }, parentKey: { n: 2 }, name: 'Child 2.1' },
121
+ ];
122
+
123
+ const { roots, nodes } = buildTree(items, {
124
+ key(item) { return item.key?.n; },
125
+ parentKey(item) { return item.parentKey?.n; },
126
+ nodeDataKey: false, // don't store data separately on the node
127
+ nodeParentKey: 'up',
128
+ nodeChildrenKey: 'down',
129
+ mapNodeData(item) { return { title: item.name }; },
130
+ });
131
+
132
+ console.log(roots[0].title);
133
+ // Expected output: Root 1
134
+
135
+ console.log(roots[0].down[1].title);
136
+ // Expected output: Child 1.2
137
+
138
+ console.log(roots[0].down[1].up.title);
139
+ // Expected output: Root 1
140
+
141
+ console.log(roots);
142
+ // Expected output: [
143
+ // { title: 'Root 1', down: [
144
+ // { title: 'Child 1.1', up: { ... } },
145
+ // { title: 'Child 1.2', up: { ... } }
146
+ // ] },
147
+ // { title: 'Root 2', down: [
148
+ // { title: 'Child 2.1', up: { ... } }
149
+ // ] }
150
+ // ]
151
+
152
+ console.log(nodes);
153
+ // Expected output: Map {
154
+ // 1 => { title: 'Root 1', down: [
155
+ // { title: 'Child 1.1', up: { ... } },
156
+ // { title: 'Child 1.2', up: { ... } }
157
+ // ] },
158
+ // 2 => { title: 'Root 2', down: [
159
+ // { title: 'Child 2.1', up: { ... } }
160
+ // ] },
161
+ // 3 => { title: 'Child 1.1', up: { ... } },
162
+ // 4 => { title: 'Child 1.2', up: { ... } },
163
+ // 5 => { title: 'Child 2.1', up: { ... } }
164
+ // }
165
+ ```
166
+
167
+
168
+ ## Documentation
169
+
170
+ ### `buildTree(items: Iterable<T>, options: BuildTreeOptions): TreeResult<T>`
171
+
172
+ Builds a tree from the given iterable `items` using the specified `options`.
173
+
174
+ Parameters
175
+
176
+ - `items`: An iterable data structure containing the items to build the tree from.
177
+ - `options`: An object specifying the build options. It has the following properties:
178
+ - `key`: (Optional) The key used to identify items. It can be a string, number, symbol, or a function that extracts the key from an item. Defaults to `'id'`.
179
+ - `parentKey`: (Optional) The key used to identify the parent of each item. It can be a string, number, symbol, or a function that extracts the parent key from an item. Defaults to `'parent'`.
180
+ - `nodeDataKey`: (Optional) The key used to store the item's data in each node. It can be a string, number, symbol, or false if the data should be merged directly into the node. Defaults to `'data'`.
181
+ - `nodeParentKey`: (Optional) The key used to store the parent node in each node. It can be a string, number, symbol, or false if the parent node should not be included. Defaults to `'parent'`.
182
+ - `nodeChildrenKey`: (Optional) The key used to store the children nodes in each node. It can be a string, number, symbol, or false if the children nodes should not be included. Defaults to `'children'`.
183
+ - `mapNodeData`: (Optional) A function that maps an item to its corresponding node data. It allows transforming the item before assigning it to the node. Defaults to `undefined`.
184
+ - `validateParentKeys`: (Optional) An iterable containing keys that should be validated as existing parent keys. If provided, any item with a parent key not present in this iterable will cause an error to be thrown. Defaults to `undefined`.
185
+
186
+ Returns
187
+
188
+ An object with the following properties:
189
+
190
+ - `roots`: An array of the root nodes of the built tree.
191
+ - `nodes`: A `Map` object containing all nodes of the built tree, with keys corresponding to their identifiers.
192
+
193
+
194
+ ## Contributions
195
+
196
+ Contributions to `fast-tree-builder` are welcome! If you have any bug reports, feature requests, or improvements, please open an issue on the [GitHub repository](https://github.com/lionel87/fast-tree-builder).
197
+
198
+ ## License
199
+
200
+ `fast-tree-builder` is licensed under the [MIT License](https://github.com/lionel87/fast-tree-builder/blob/main/LICENSE).
package/cjs/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ type TreeNode<T, D extends string | number | symbol | false, P extends string | number | symbol | false, C extends string | number | symbol> = (D extends false ? (P extends false ? T & {
2
+ [k in C]?: TreeNode<T, D, P, C>[];
3
+ } : T & {
4
+ [k in Exclude<P, false>]?: TreeNode<T, D, P, C>;
5
+ } & {
6
+ [k in C]?: TreeNode<T, D, P, C>[];
7
+ }) : (P extends false ? {
8
+ [k in Exclude<D, false>]: T;
9
+ } & {
10
+ [k in C]?: TreeNode<T, D, P, C>[];
11
+ } : {
12
+ [k in Exclude<D, false>]: T;
13
+ } & {
14
+ [k in Exclude<P, false>]?: TreeNode<T, D, P, C>;
15
+ } & {
16
+ [k in C]?: TreeNode<T, D, P, C>[];
17
+ }));
18
+ declare function buildTree<T extends (D extends false ? object : unknown), M extends (D extends false ? object : unknown) = T, K extends unknown = unknown, D extends string | number | symbol | false = 'data', P extends string | number | symbol | false = 'parent', C extends string | number | symbol = 'children'>(items: Iterable<T>, options: {
19
+ key?: string | number | symbol | {
20
+ (item: T): K;
21
+ };
22
+ parentKey?: string | number | symbol | {
23
+ (item: T): K;
24
+ };
25
+ nodeDataKey?: D;
26
+ nodeParentKey?: P;
27
+ nodeChildrenKey?: C;
28
+ mapNodeData?: {
29
+ (item: T): M;
30
+ };
31
+ validateParentKeys?: Iterable<unknown>;
32
+ }): {
33
+ roots: TreeNode<M extends undefined ? T : M, D, P, C>[];
34
+ nodes: Map<K, TreeNode<M extends undefined ? T : M, D, P, C>>;
35
+ };
36
+ export default buildTree;
package/cjs/index.js ADDED
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function buildTree(items, options) {
4
+ var _a;
5
+ const { key = 'id', parentKey = 'parent', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validateParentKeys, } = options;
6
+ const nodes = new Map();
7
+ const danglingNodes = new Map();
8
+ for (const item of items) {
9
+ // @ts-ignore
10
+ const keyOfNode = typeof key === 'function' ? key(item) : item[key];
11
+ if (nodes.has(keyOfNode)) {
12
+ throw new Error(`Duplicate identifier detected for "${keyOfNode}"`);
13
+ }
14
+ // Current node can be new or already created by a child item as its parent
15
+ let node = danglingNodes.get(keyOfNode);
16
+ if (node) {
17
+ danglingNodes.delete(keyOfNode);
18
+ }
19
+ else {
20
+ node = {};
21
+ }
22
+ nodes.set(keyOfNode, node);
23
+ // Set the data of the node
24
+ const nodeData = typeof mapNodeData === 'function' ? mapNodeData(item) : item;
25
+ if (nodeDataKey !== false) {
26
+ node[nodeDataKey] = nodeData;
27
+ }
28
+ else {
29
+ Object.assign(node, nodeData);
30
+ }
31
+ // Link this node to its parent
32
+ // @ts-ignore
33
+ const keyOfParentNode = typeof parentKey === 'function' ? parentKey(item) : item[parentKey];
34
+ let parent = (_a = nodes.get(keyOfParentNode)) !== null && _a !== void 0 ? _a : danglingNodes.get(keyOfParentNode);
35
+ if (!parent) {
36
+ // No parent node exists yet, create as dangling node
37
+ parent = {};
38
+ // Track as dangling node, we dont know yet if it really exists
39
+ danglingNodes.set(keyOfParentNode, parent);
40
+ }
41
+ // When no children added yet
42
+ if (!parent[nodeChildrenKey]) {
43
+ parent[nodeChildrenKey] = [];
44
+ }
45
+ // Add as child
46
+ parent[nodeChildrenKey].push(node);
47
+ // Set the parent on this node
48
+ if (nodeParentKey !== false) {
49
+ node[nodeParentKey] = parent;
50
+ }
51
+ }
52
+ if (danglingNodes.size === 0) {
53
+ throw new Error(`Could not find root nodes, circular references found.`);
54
+ }
55
+ // Children of dangling nodes will become the root nodes
56
+ const roots = [];
57
+ if (validateParentKeys) {
58
+ const validParentKeys = new Set(validateParentKeys);
59
+ for (const [key, node] of danglingNodes.entries()) {
60
+ if (!validParentKeys.has(key)) {
61
+ throw new Error(`Invalid parent key "${key}" from items "${node[nodeChildrenKey].join('", "')}".`);
62
+ }
63
+ for (const root of node[nodeChildrenKey]) {
64
+ // Root nodes does not have a parent, unlink the dangling node
65
+ if (nodeParentKey !== false) {
66
+ delete root[nodeParentKey];
67
+ }
68
+ roots.push(root);
69
+ }
70
+ }
71
+ }
72
+ else {
73
+ for (const node of danglingNodes.values()) {
74
+ for (const root of node[nodeChildrenKey]) {
75
+ // Root nodes does not have a parent, unlink the dangling node
76
+ if (nodeParentKey !== false) {
77
+ delete root[nodeParentKey];
78
+ }
79
+ roots.push(root);
80
+ }
81
+ }
82
+ }
83
+ return { roots, nodes };
84
+ }
85
+ exports.default = buildTree;
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
package/esm/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ type TreeNode<T, D extends string | number | symbol | false, P extends string | number | symbol | false, C extends string | number | symbol> = (D extends false ? (P extends false ? T & {
2
+ [k in C]?: TreeNode<T, D, P, C>[];
3
+ } : T & {
4
+ [k in Exclude<P, false>]?: TreeNode<T, D, P, C>;
5
+ } & {
6
+ [k in C]?: TreeNode<T, D, P, C>[];
7
+ }) : (P extends false ? {
8
+ [k in Exclude<D, false>]: T;
9
+ } & {
10
+ [k in C]?: TreeNode<T, D, P, C>[];
11
+ } : {
12
+ [k in Exclude<D, false>]: T;
13
+ } & {
14
+ [k in Exclude<P, false>]?: TreeNode<T, D, P, C>;
15
+ } & {
16
+ [k in C]?: TreeNode<T, D, P, C>[];
17
+ }));
18
+ declare function buildTree<T extends (D extends false ? object : unknown), M extends (D extends false ? object : unknown) = T, K extends unknown = unknown, D extends string | number | symbol | false = 'data', P extends string | number | symbol | false = 'parent', C extends string | number | symbol = 'children'>(items: Iterable<T>, options: {
19
+ key?: string | number | symbol | {
20
+ (item: T): K;
21
+ };
22
+ parentKey?: string | number | symbol | {
23
+ (item: T): K;
24
+ };
25
+ nodeDataKey?: D;
26
+ nodeParentKey?: P;
27
+ nodeChildrenKey?: C;
28
+ mapNodeData?: {
29
+ (item: T): M;
30
+ };
31
+ validateParentKeys?: Iterable<unknown>;
32
+ }): {
33
+ roots: TreeNode<M extends undefined ? T : M, D, P, C>[];
34
+ nodes: Map<K, TreeNode<M extends undefined ? T : M, D, P, C>>;
35
+ };
36
+ export default buildTree;
package/esm/index.js ADDED
@@ -0,0 +1,83 @@
1
+ function buildTree(items, options) {
2
+ var _a;
3
+ const { key = 'id', parentKey = 'parent', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validateParentKeys, } = options;
4
+ const nodes = new Map();
5
+ const danglingNodes = new Map();
6
+ for (const item of items) {
7
+ // @ts-ignore
8
+ const keyOfNode = typeof key === 'function' ? key(item) : item[key];
9
+ if (nodes.has(keyOfNode)) {
10
+ throw new Error(`Duplicate identifier detected for "${keyOfNode}"`);
11
+ }
12
+ // Current node can be new or already created by a child item as its parent
13
+ let node = danglingNodes.get(keyOfNode);
14
+ if (node) {
15
+ danglingNodes.delete(keyOfNode);
16
+ }
17
+ else {
18
+ node = {};
19
+ }
20
+ nodes.set(keyOfNode, node);
21
+ // Set the data of the node
22
+ const nodeData = typeof mapNodeData === 'function' ? mapNodeData(item) : item;
23
+ if (nodeDataKey !== false) {
24
+ node[nodeDataKey] = nodeData;
25
+ }
26
+ else {
27
+ Object.assign(node, nodeData);
28
+ }
29
+ // Link this node to its parent
30
+ // @ts-ignore
31
+ const keyOfParentNode = typeof parentKey === 'function' ? parentKey(item) : item[parentKey];
32
+ let parent = (_a = nodes.get(keyOfParentNode)) !== null && _a !== void 0 ? _a : danglingNodes.get(keyOfParentNode);
33
+ if (!parent) {
34
+ // No parent node exists yet, create as dangling node
35
+ parent = {};
36
+ // Track as dangling node, we dont know yet if it really exists
37
+ danglingNodes.set(keyOfParentNode, parent);
38
+ }
39
+ // When no children added yet
40
+ if (!parent[nodeChildrenKey]) {
41
+ parent[nodeChildrenKey] = [];
42
+ }
43
+ // Add as child
44
+ parent[nodeChildrenKey].push(node);
45
+ // Set the parent on this node
46
+ if (nodeParentKey !== false) {
47
+ node[nodeParentKey] = parent;
48
+ }
49
+ }
50
+ if (danglingNodes.size === 0) {
51
+ throw new Error(`Could not find root nodes, circular references found.`);
52
+ }
53
+ // Children of dangling nodes will become the root nodes
54
+ const roots = [];
55
+ if (validateParentKeys) {
56
+ const validParentKeys = new Set(validateParentKeys);
57
+ for (const [key, node] of danglingNodes.entries()) {
58
+ if (!validParentKeys.has(key)) {
59
+ throw new Error(`Invalid parent key "${key}" from items "${node[nodeChildrenKey].join('", "')}".`);
60
+ }
61
+ for (const root of node[nodeChildrenKey]) {
62
+ // Root nodes does not have a parent, unlink the dangling node
63
+ if (nodeParentKey !== false) {
64
+ delete root[nodeParentKey];
65
+ }
66
+ roots.push(root);
67
+ }
68
+ }
69
+ }
70
+ else {
71
+ for (const node of danglingNodes.values()) {
72
+ for (const root of node[nodeChildrenKey]) {
73
+ // Root nodes does not have a parent, unlink the dangling node
74
+ if (nodeParentKey !== false) {
75
+ delete root[nodeParentKey];
76
+ }
77
+ roots.push(root);
78
+ }
79
+ }
80
+ }
81
+ return { roots, nodes };
82
+ }
83
+ export default buildTree;
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "fast-tree-builder",
3
+ "version": "0.0.1",
4
+ "description": "Efficiently construct highly customizable bi-directional tree structures from iterable data.",
5
+ "type": "module",
6
+ "main": "cjs/index.js",
7
+ "module": "esm/index.js",
8
+ "types": "esm/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "require": "./cjs/index.js",
12
+ "default": "./esm/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "prepack": "npm run build",
17
+ "clean": "rimraf esm cjs",
18
+ "build": "npm run build:esm && npm run build:cjs",
19
+ "build:esm": "tsc",
20
+ "watch:esm": "tsc --watch",
21
+ "build:cjs": "tsc --outDir cjs --module commonjs && echo { \"type\": \"commonjs\" }>cjs/package.json",
22
+ "watch:cjs": "npm run build:cjs && tsc --outDir cjs --module commonjs --watch",
23
+ "test": "node test.js"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/lionel87/fast-tree-builder.git"
28
+ },
29
+ "keywords": [
30
+ "tree builder",
31
+ "tree structure",
32
+ "iterable data",
33
+ "typescript",
34
+ "type safe",
35
+ "bi-directional traversal",
36
+ "list to tree",
37
+ "array to tree",
38
+ "unflatten tree",
39
+ "algorithm",
40
+ "navigation",
41
+ "breadcrumbs",
42
+ "descendants",
43
+ "ancestors",
44
+ "tree",
45
+ "builder",
46
+ "children",
47
+ "child",
48
+ "nested",
49
+ "list",
50
+ "validation"
51
+ ],
52
+ "author": "László BULIK",
53
+ "license": "MIT",
54
+ "bugs": {
55
+ "url": "https://github.com/lionel87/fast-tree-builder/issues"
56
+ },
57
+ "homepage": "https://github.com/lionel87/fast-tree-builder#readme",
58
+ "devDependencies": {
59
+ "rimraf": "^5.0.1",
60
+ "typescript": "^5.1.3"
61
+ }
62
+ }