You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.1 KiB
JavaScript

"use strict";
const defaultValue = require("default-value");
const asExpression = require("as-expression");
const ensureObject = require("./ensure-object");
// FIXME: Move to stand-alone package, clearly document that it is not order-sensitive
module.exports = function createNamedTreeBuilder(options = {}) {
let parentKey = options.parentKey;
let childrenKey = options.childrenKey;
let treatRootAsParent = defaultValue(options.treatRootAsParent, true);
let root = {};
let done = false;
return {
add: function (path, item) {
if (done === true) {
throw new Error(`done() was called on the builder; no further modifications are possible`);
} else {
let lastItem = root;
for (let i = 0; i < path.length; i++) {
let segment = path[i];
// eslint-disable-next-line no-loop-func
let childrenContainer = asExpression(() => {
if (childrenKey != null) {
ensureObject(lastItem, childrenKey);
return lastItem[childrenKey];
} else {
return lastItem;
}
});
ensureObject(childrenContainer, segment);
let child = childrenContainer[segment];
let setParent = (
parentKey != null
&& child[parentKey] == null
&& (treatRootAsParent || i >= 1)
);
if (setParent) {
child[parentKey] = lastItem;
}
if (i === path.length - 1) {
// Last segment, this is where we want to put the item data
child = childrenContainer[segment] = {
... item,
... child
};
}
lastItem = child;
}
}
},
done: function () {
done = true;
return root;
}
};
};
// let builder = module.exports({ childrenKey: "children", parentKey: "parent" });
// builder.add([], { description: "root" });
// builder.add(["a"], { description: "root -> a" });
// builder.add(["b", "c"], { description: "root -> b -> c" });
// builder.add(["b"], { description: "root -> b" });
// builder.add(["a", "c"], { description: "root -> a -> c" });
// builder.add(["a", "c", "d"], { description: "root -> a -> c -> d" });
// console.dir(builder.done(), { depth: null });