fast-tree-builder 1.0.0-alpha.0 → 1.0.0-alpha.2

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 CHANGED
@@ -251,6 +251,7 @@ Parameters
251
251
  - `nodeChildrenKey`: (Optional) The key used to store the children nodes in each node. It can be a `string`, `number`, `symbol`. Defaults to `'children'`.
252
252
  - `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`.
253
253
  - `validRootKeys`: (Optional) An iterable containing key values that can be accepted as root nodes. If provided, any item with a key not present in this iterable will cause an error to be thrown. Defaults to `undefined`.
254
+ - `validRootParentKeys`: (Optional) Only available when `mode` is set to `parent`. An iterable containing key values that can be accepted the parent field values of root nodes. If provided, any root node with a parent key not present in this iterable will cause an error to be thrown. Defaults to `undefined`.
254
255
  - `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`.
255
256
 
256
257
  Returns
@@ -263,7 +264,8 @@ An object with the following properties:
263
264
  Throws `Error` when:
264
265
 
265
266
  - A duplicate identifier is recieved,
266
- - or `validRootKeys` is set and an invalid parent key is recieved,
267
+ - or `validRootKeys` is set and an invalid key is recieved,
268
+ - or `validRootParentKeys` is set and an invalid parent key is recieved,
267
269
  - or `validateTree` is set to `true` and a cyclic graph is the result.
268
270
 
269
271
  ## Comparison with other tree building libraries
package/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  function buildTree(items, options = {}) {
4
- const { mode = 'parent', key = 'id', parentKey = 'parent', childrenKey = 'children', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validRootKeys, validateTree = false, } = options;
4
+ const { mode = 'parent', key = 'id', parentKey = 'parent', childrenKey = 'children', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validRootKeys, validRootParentKeys, validateTree = false, } = options;
5
5
  const roots = [];
6
6
  const nodes = new Map();
7
7
  const danglingNodes = new Map();
@@ -49,11 +49,11 @@ function buildTree(items, options = {}) {
49
49
  }
50
50
  }
51
51
  // Children of dangling nodes will become the root nodes
52
- if (validRootKeys) {
53
- const validParentKeys = new Set(validRootKeys);
54
- for (const [key, node] of danglingNodes.entries()) {
55
- if (!validParentKeys.has(key)) {
56
- throw new Error(`Invalid parent key "${key}"`);
52
+ if (validRootParentKeys) {
53
+ const validParentKeys = new Set(validRootParentKeys);
54
+ for (const [parentKey, node] of danglingNodes.entries()) {
55
+ if (!validParentKeys.has(parentKey)) {
56
+ throw new Error(`Invalid parent key "${parentKey}" found for a root node.`);
57
57
  }
58
58
  for (const root of node[nodeChildrenKey]) {
59
59
  // Root nodes does not have a parent, unlink the dangling node
@@ -75,8 +75,21 @@ function buildTree(items, options = {}) {
75
75
  }
76
76
  }
77
77
  }
78
+ // TODO: this could be optimized
79
+ if (validRootKeys) {
80
+ const rootsSet = new Set(roots);
81
+ const validKeys = new Set(validRootKeys);
82
+ for (const [key, node] of nodes) {
83
+ if (rootsSet.has(node) && !validKeys.has(key)) {
84
+ throw new Error(`A root node has an invalid key "${key}"`);
85
+ }
86
+ }
87
+ }
78
88
  }
79
89
  else {
90
+ if (validRootParentKeys) {
91
+ throw new Error(`Option "validRootParentKeys" cannot be used when mode is set to "children".`);
92
+ }
80
93
  const knownNodes = new Set();
81
94
  const incompleteNodes = new Set();
82
95
  for (const item of items) {
@@ -134,10 +147,10 @@ function buildTree(items, options = {}) {
134
147
  throw new Error(`Some nodes miss their referenced children (${incompleteNodes.size}).`);
135
148
  }
136
149
  if (validRootKeys) {
137
- const validParentKeys = new Set(validRootKeys);
150
+ const validKeys = new Set(validRootKeys);
138
151
  for (const [key, node] of danglingNodes.entries()) {
139
- if (!validParentKeys.has(key)) {
140
- throw new Error(`Invalid parent key "${key}"`);
152
+ if (!validKeys.has(key)) {
153
+ throw new Error(`A root node has an invalid key "${key}"`);
141
154
  }
142
155
  roots.push(node);
143
156
  nodes.set(key, node);
package/index.d.ts CHANGED
@@ -28,6 +28,7 @@ declare function buildTree<T extends (D extends false ? object : unknown), K ext
28
28
  (item: T): M;
29
29
  };
30
30
  validRootKeys?: Iterable<unknown>;
31
+ validRootParentKeys?: Iterable<unknown>;
31
32
  validateTree?: boolean;
32
33
  }): {
33
34
  roots: TreeNode<M extends undefined ? T : M, D, P, C>[];
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  function buildTree(items, options = {}) {
2
- const { mode = 'parent', key = 'id', parentKey = 'parent', childrenKey = 'children', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validRootKeys, validateTree = false, } = options;
2
+ const { mode = 'parent', key = 'id', parentKey = 'parent', childrenKey = 'children', nodeDataKey = 'data', nodeParentKey = 'parent', nodeChildrenKey = 'children', mapNodeData, validRootKeys, validRootParentKeys, validateTree = false, } = options;
3
3
  const roots = [];
4
4
  const nodes = new Map();
5
5
  const danglingNodes = new Map();
@@ -47,11 +47,11 @@ function buildTree(items, options = {}) {
47
47
  }
48
48
  }
49
49
  // Children of dangling nodes will become the root nodes
50
- if (validRootKeys) {
51
- const validParentKeys = new Set(validRootKeys);
52
- for (const [key, node] of danglingNodes.entries()) {
53
- if (!validParentKeys.has(key)) {
54
- throw new Error(`Invalid parent key "${key}"`);
50
+ if (validRootParentKeys) {
51
+ const validParentKeys = new Set(validRootParentKeys);
52
+ for (const [parentKey, node] of danglingNodes.entries()) {
53
+ if (!validParentKeys.has(parentKey)) {
54
+ throw new Error(`Invalid parent key "${parentKey}" found for a root node.`);
55
55
  }
56
56
  for (const root of node[nodeChildrenKey]) {
57
57
  // Root nodes does not have a parent, unlink the dangling node
@@ -73,8 +73,21 @@ function buildTree(items, options = {}) {
73
73
  }
74
74
  }
75
75
  }
76
+ // TODO: this could be optimized
77
+ if (validRootKeys) {
78
+ const rootsSet = new Set(roots);
79
+ const validKeys = new Set(validRootKeys);
80
+ for (const [key, node] of nodes) {
81
+ if (rootsSet.has(node) && !validKeys.has(key)) {
82
+ throw new Error(`A root node has an invalid key "${key}"`);
83
+ }
84
+ }
85
+ }
76
86
  }
77
87
  else {
88
+ if (validRootParentKeys) {
89
+ throw new Error(`Option "validRootParentKeys" cannot be used when mode is set to "children".`);
90
+ }
78
91
  const knownNodes = new Set();
79
92
  const incompleteNodes = new Set();
80
93
  for (const item of items) {
@@ -132,10 +145,10 @@ function buildTree(items, options = {}) {
132
145
  throw new Error(`Some nodes miss their referenced children (${incompleteNodes.size}).`);
133
146
  }
134
147
  if (validRootKeys) {
135
- const validParentKeys = new Set(validRootKeys);
148
+ const validKeys = new Set(validRootKeys);
136
149
  for (const [key, node] of danglingNodes.entries()) {
137
- if (!validParentKeys.has(key)) {
138
- throw new Error(`Invalid parent key "${key}"`);
150
+ if (!validKeys.has(key)) {
151
+ throw new Error(`A root node has an invalid key "${key}"`);
139
152
  }
140
153
  roots.push(node);
141
154
  nodes.set(key, node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-tree-builder",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Efficiently construct highly customizable bi-directional tree structures from iterable data.",
5
5
  "type": "module",
6
6
  "module": "./index.js",