fast-tree-builder 0.1.3 → 0.1.4
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/README.md +11 -13
- package/{cjs/index.js → index.cjs} +1 -4
- package/{cjs/index.d.ts → index.d.ts} +5 -8
- package/{esm/index.js → index.js} +1 -4
- package/package.json +25 -26
- package/cjs/package.json +0 -1
- package/esm/index.d.ts +0 -37
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/lionel87/fast-tree-builder/actions/workflows/build.yaml)
|
|
4
4
|
[](https://coveralls.io/github/lionel87/fast-tree-builder?branch=master)
|
|
5
5
|

|
|
6
|
-

|
|
7
7
|
|
|
8
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
9
|
|
|
@@ -15,23 +15,23 @@
|
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
|
-
- **Efficient Tree Building**: The package utilizes an optimized algorithm to construct trees efficiently in `O(n)` time,
|
|
18
|
+
- **Efficient Tree Building**: The package utilizes an optimized algorithm to construct trees efficiently in `O(n)` time, while maintaining good performance.
|
|
19
19
|
|
|
20
20
|
- **Bi-Directional Tree Traversal**: Traverse the built tree in both directions, enabling easy navigation between parent and child nodes.
|
|
21
21
|
|
|
22
|
-
- **
|
|
22
|
+
- **Robust TypeScript Type Definitions**: Leverage type safety through extensive TypeScript type definitions. The package includes precise type annotations to improve code reliability and developer workflow.
|
|
23
23
|
|
|
24
24
|
- **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.
|
|
25
25
|
|
|
26
|
-
- **Works on Any Iterable Data
|
|
26
|
+
- **Works on Any Iterable Data**: Designed to handle arrays, sets, and other iterable data structures efficiently, ensuring broad applicability.
|
|
27
27
|
|
|
28
|
-
- **No Sorting Required**: The
|
|
28
|
+
- **No Sorting Required**: The algorithm does not require your input data to be sorted, saving you preprocessing time and effort.
|
|
29
29
|
|
|
30
|
-
- **Flexible Key and Parent Key Types**: You can use any JavaScript value for identifying items. Relations checked with `key === parentKey` comparison.
|
|
30
|
+
- **Flexible Key and Parent Key Types**: You can use any JavaScript value for identifying items. Relations checked with strict (`key === parentKey`) comparison.
|
|
31
31
|
|
|
32
|
-
- **
|
|
32
|
+
- **Multiple Root Nodes**: Can efficiently construct trees with multiple root nodes, accommodating scenarios that necessitate distinct, separate tree structures within the same dataset.
|
|
33
33
|
|
|
34
|
-
- **
|
|
34
|
+
- **Map of Nodes**: Beside the root nodes you can retrieve a `Map` object containing the nodes of the built tree, enabling easy entry on any point of the tree.
|
|
35
35
|
|
|
36
36
|
- **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.
|
|
37
37
|
|
|
@@ -225,7 +225,7 @@ Parameters
|
|
|
225
225
|
- `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'`.
|
|
226
226
|
- `nodeChildrenKey`: (Optional) The key used to store the children nodes in each node. It can be a string, number, symbol. Defaults to `'children'`.
|
|
227
227
|
- `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`.
|
|
228
|
-
- `validateParentKeys`: (Optional) An iterable containing
|
|
228
|
+
- `validateParentKeys`: (Optional) An iterable containing parent key values that can be accepted as root nodes. If provided, any item with a parent key not present in this iterable will cause an error to be thrown. Defaults to `undefined`.
|
|
229
229
|
- `validateTree`: (Optional) A boolean flag that determines whether to validate the resulting data structure. If the structure is a cyclic graph, an `Error` will be thrown. Requires additional `O(n)` time to compute. Defaults to `false`.
|
|
230
230
|
|
|
231
231
|
Returns
|
|
@@ -243,11 +243,9 @@ Throws `Error` when:
|
|
|
243
243
|
|
|
244
244
|
## Comparison with other tree building libraries
|
|
245
245
|
|
|
246
|
-
The package aims to be feature complete and highly customizable, which usually opposes with performance. There are other packages that may be more
|
|
247
|
-
|
|
248
|
-
I can imagine extreme cases with huge trees where this package can be slower, but you should write your own tree building implementation optimized for that exact case anyway.
|
|
246
|
+
The package aims to be feature complete and highly customizable, which usually opposes with performance. There are other packages that may be more *performant* but lacks features that I really needed in my daily coding. In standard scenarios this package should perform more than enough and nearly as good as other packages.
|
|
249
247
|
|
|
250
|
-
|
|
248
|
+
For scenarios where performance is critical, consider implementing a tailored, optimized algorithm. It could be as simple as:
|
|
251
249
|
```js
|
|
252
250
|
const roots = [];
|
|
253
251
|
const nodes = new Map();
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
function buildTree(items, options = {}) {
|
|
4
|
-
var _a;
|
|
5
4
|
const { key = 'id', parentKey = 'parent', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validateParentKeys, validateTree = false, } = options;
|
|
6
5
|
const nodes = new Map();
|
|
7
6
|
const danglingNodes = new Map();
|
|
8
7
|
for (const item of items) {
|
|
9
|
-
// @ts-ignore
|
|
10
8
|
const keyOfNode = typeof key === 'function' ? key(item) : item[key];
|
|
11
9
|
if (nodes.has(keyOfNode)) {
|
|
12
10
|
throw new Error(`Duplicate identifier detected for "${keyOfNode}"`);
|
|
@@ -29,9 +27,8 @@ function buildTree(items, options = {}) {
|
|
|
29
27
|
Object.assign(node, nodeData);
|
|
30
28
|
}
|
|
31
29
|
// Link this node to its parent
|
|
32
|
-
// @ts-ignore
|
|
33
30
|
const keyOfParentNode = typeof parentKey === 'function' ? parentKey(item) : item[parentKey];
|
|
34
|
-
let parent =
|
|
31
|
+
let parent = nodes.get(keyOfParentNode) ?? danglingNodes.get(keyOfParentNode);
|
|
35
32
|
if (!parent) {
|
|
36
33
|
// No parent node exists yet, create as dangling node
|
|
37
34
|
parent = {};
|
|
@@ -15,13 +15,10 @@ type TreeNode<T, D extends string | number | symbol | false, P extends string |
|
|
|
15
15
|
} & {
|
|
16
16
|
[k in C]?: TreeNode<T, D, P, C>[];
|
|
17
17
|
}));
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
parentKey?: string | number | symbol | {
|
|
23
|
-
(item: T): K;
|
|
24
|
-
};
|
|
18
|
+
type KeyReturnType<T, P extends keyof T | ((item: T) => any)> = P extends ((item: T) => infer R) ? R : P extends keyof T ? T[P] : never;
|
|
19
|
+
declare function buildTree<T extends (D extends false ? object : unknown), K extends keyof T | ((item: T) => any), M extends (D extends false ? object : unknown) = T, D extends string | number | symbol | false = 'data', P extends string | number | symbol | false = 'parent', C extends string | number | symbol = 'children'>(items: Iterable<T>, options?: {
|
|
20
|
+
key?: K;
|
|
21
|
+
parentKey?: keyof T | ((item: T) => KeyReturnType<T, K>);
|
|
25
22
|
nodeDataKey?: D;
|
|
26
23
|
nodeParentKey?: P;
|
|
27
24
|
nodeChildrenKey?: C;
|
|
@@ -32,6 +29,6 @@ declare function buildTree<T extends (D extends false ? object : unknown), M ext
|
|
|
32
29
|
validateTree?: boolean;
|
|
33
30
|
}): {
|
|
34
31
|
roots: TreeNode<M extends undefined ? T : M, D, P, C>[];
|
|
35
|
-
nodes: Map<
|
|
32
|
+
nodes: Map<KeyReturnType<T, K>, TreeNode<M extends undefined ? T : M, D, P, C>>;
|
|
36
33
|
};
|
|
37
34
|
export default buildTree;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
function buildTree(items, options = {}) {
|
|
2
|
-
var _a;
|
|
3
2
|
const { key = 'id', parentKey = 'parent', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validateParentKeys, validateTree = false, } = options;
|
|
4
3
|
const nodes = new Map();
|
|
5
4
|
const danglingNodes = new Map();
|
|
6
5
|
for (const item of items) {
|
|
7
|
-
// @ts-ignore
|
|
8
6
|
const keyOfNode = typeof key === 'function' ? key(item) : item[key];
|
|
9
7
|
if (nodes.has(keyOfNode)) {
|
|
10
8
|
throw new Error(`Duplicate identifier detected for "${keyOfNode}"`);
|
|
@@ -27,9 +25,8 @@ function buildTree(items, options = {}) {
|
|
|
27
25
|
Object.assign(node, nodeData);
|
|
28
26
|
}
|
|
29
27
|
// Link this node to its parent
|
|
30
|
-
// @ts-ignore
|
|
31
28
|
const keyOfParentNode = typeof parentKey === 'function' ? parentKey(item) : item[parentKey];
|
|
32
|
-
let parent =
|
|
29
|
+
let parent = nodes.get(keyOfParentNode) ?? danglingNodes.get(keyOfParentNode);
|
|
33
30
|
if (!parent) {
|
|
34
31
|
// No parent node exists yet, create as dangling node
|
|
35
32
|
parent = {};
|
package/package.json
CHANGED
|
@@ -1,33 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-tree-builder",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Efficiently construct highly customizable bi-directional tree structures from iterable data.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"types": "
|
|
6
|
+
"module": "./index.js",
|
|
7
|
+
"main": "./index.cjs",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"import": "./index.js",
|
|
12
|
+
"require": "./index.cjs",
|
|
13
|
+
"types": "./index.d.ts"
|
|
13
14
|
}
|
|
14
15
|
},
|
|
15
16
|
"scripts": {
|
|
16
17
|
"prepack": "npm run build && npm run test",
|
|
17
18
|
"postversion": "git push && git push --tags",
|
|
18
|
-
"clean": "rimraf
|
|
19
|
-
"build": "
|
|
20
|
-
"
|
|
21
|
-
"watch:esm": "tsc --watch",
|
|
22
|
-
"build:cjs": "tsc --outDir cjs --module commonjs && echo { \"type\": \"commonjs\" }>cjs/package.json",
|
|
23
|
-
"watch:cjs": "npm run build:cjs && tsc --outDir cjs --module commonjs --watch",
|
|
19
|
+
"clean": "rimraf --glob \"!(.*).{d.ts,js,cjs,mjs}\" build coverage",
|
|
20
|
+
"build": "node scripts/build-esm.js && node scripts/build-cjs.js",
|
|
21
|
+
"watch": "node scripts/watch.js",
|
|
24
22
|
"test": "mocha",
|
|
25
|
-
"coverage": "c8 -r text -r text-summary -r lcov npm test"
|
|
23
|
+
"coverage": "c8 -r text -r text-summary -r lcov --include \"*.js\" npm test"
|
|
26
24
|
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"c8": "^8.0.0",
|
|
27
|
+
"chokidar": "^3.5.3",
|
|
28
|
+
"mocha": "^10.2.0",
|
|
29
|
+
"rimraf": "^5.0.1",
|
|
30
|
+
"typescript": "^5.1.3"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/lionel87/fast-tree-builder#readme",
|
|
27
33
|
"repository": {
|
|
28
34
|
"type": "git",
|
|
29
35
|
"url": "git+https://github.com/lionel87/fast-tree-builder.git"
|
|
30
36
|
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/lionel87/fast-tree-builder/issues"
|
|
39
|
+
},
|
|
40
|
+
"author": "László BULIK",
|
|
41
|
+
"license": "MIT",
|
|
31
42
|
"keywords": [
|
|
32
43
|
"tree builder",
|
|
33
44
|
"tree structure",
|
|
@@ -50,17 +61,5 @@
|
|
|
50
61
|
"nested",
|
|
51
62
|
"list",
|
|
52
63
|
"validation"
|
|
53
|
-
]
|
|
54
|
-
"author": "László BULIK",
|
|
55
|
-
"license": "MIT",
|
|
56
|
-
"bugs": {
|
|
57
|
-
"url": "https://github.com/lionel87/fast-tree-builder/issues"
|
|
58
|
-
},
|
|
59
|
-
"homepage": "https://github.com/lionel87/fast-tree-builder#readme",
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"c8": "^8.0.0",
|
|
62
|
-
"mocha": "^10.2.0",
|
|
63
|
-
"rimraf": "^5.0.1",
|
|
64
|
-
"typescript": "^5.1.3"
|
|
65
|
-
}
|
|
64
|
+
]
|
|
66
65
|
}
|
package/cjs/package.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "type": "commonjs" }
|
package/esm/index.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
validateTree?: boolean;
|
|
33
|
-
}): {
|
|
34
|
-
roots: TreeNode<M extends undefined ? T : M, D, P, C>[];
|
|
35
|
-
nodes: Map<K, TreeNode<M extends undefined ? T : M, D, P, C>>;
|
|
36
|
-
};
|
|
37
|
-
export default buildTree;
|