Skip to content
Snippets Groups Projects
Select Git revision
  • 395e54bd27c7a6bd911688fb65f9c555bbab6eaf
  • master default protected
  • 1.31
  • 4.37.2
  • 4.37.1
  • 4.37.0
  • 4.36.0
  • 4.35.0
  • 4.34.1
  • 4.34.0
  • 4.33.1
  • 4.33.0
  • 4.32.2
  • 4.32.1
  • 4.32.0
  • 4.31.0
  • 4.30.1
  • 4.30.0
  • 4.29.1
  • 4.29.0
  • 4.28.0
  • 4.27.0
  • 4.26.0
23 results

Makefile

Blame
  • buildtree.mjs 2.84 KiB
    /**
     * Copyright schukai GmbH and contributors 2023. All Rights Reserved.
     * Node module: @schukai/monster
     * This file is licensed under the AGPLv3 License.
     * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
     */
    
    import { isArray, isObject } from "../types/is.mjs";
    import { Node } from "../types/node.mjs";
    import { NodeList } from "../types/nodelist.mjs";
    import { assembleParts } from "./buildmap.mjs";
    import { extend } from "./extend.mjs";
    
    export { buildTree };
    
    /**
     * @private
     * @type {symbol}
     */
    const parentSymbol = Symbol("parent");
    
    /**
     * @private
     * @type {symbol}
     */
    const rootSymbol = Symbol("root");
    
    /**
     * @typedef {Object} buildTreeOptions
     * @property {array} options.rootReferences=[null, undefined] defines the values for elements without parents
     * @property {Monster.Data~exampleFilterCallback} options.filter filtering of the values
     * @memberOf Monster.Data
     */
    
    /**
     * With the help of the function `buildTree()`, nodes can be easily created from data objects.
     *
     * @param {*} subject
     * @param {string|Monster.Data~exampleSelectorCallback} selector
     * @param {string} idKey
     * @param {string} parentIDKey
     * @param {buildTreeOptions} [options]
     * @return {*}
     * @memberOf Monster.Data
     * @throws {TypeError} value is neither a string nor a function
     * @throws {TypeError} the selector callback must return a map
     * @throws {Error} the object has no value for the specified id
     * @license AGPLv3
     * @since 1.26.0
     */
    function buildTree(subject, selector, idKey, parentIDKey, options) {
        const nodes = new Map();
    
        if (!isObject(options)) {
            options = {};
        }
    
        options = extend(
            {},
            {
                rootReferences: [null, undefined],
                filter: undefined,
            },
            options,
        );
    
        const filter = options?.filter;
        let rootReferences = options.rootReferences;
        if (!isArray(rootReferences)) {
            rootReferences = [rootReferences];
        }
    
        const childMap = assembleParts(subject, selector, filter, function (o, k, m) {
            const key = o?.[idKey];
            let ref = o?.[parentIDKey];
            if (rootReferences.indexOf(ref) !== -1) ref = rootSymbol;
    
            if (key === undefined) {
                throw new Error("the object has no value for the specified id");
            }
    
            o[parentSymbol] = ref;
    
            const node = new Node(o);
            this.has(ref) ? this.get(ref).add(node) : this.set(ref, new NodeList().add(node));
            nodes.set(key, node);
        });
    
        nodes.forEach((node) => {
            let id = node?.["value"]?.[idKey];
    
            if (childMap.has(id)) {
                node.childNodes = childMap.get(id);
                childMap.delete(id);
            }
        });
    
        const list = new NodeList();
    
        childMap.forEach((s) => {
            if (s instanceof Set) {
                s.forEach((n) => {
                    list.add(n);
                });
            }
        });
    
        return list;
    }