|
|
|
"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 });
|