Skip to content
Snippets Groups Projects
Select Git revision
  • daf062b2d5e5f6abff2c38a4d993eaaca94020e7
  • master default protected
  • 1.31
  • 4.38.6
  • 4.38.5
  • 4.38.4
  • 4.38.3
  • 4.38.2
  • 4.38.1
  • 4.38.0
  • 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
23 results

buildtree.mjs

Blame
  • Volker Schukai's avatar
    daf062b2
    History
    buildtree.mjs 2.78 KiB
    /**
     * Copyright schukai GmbH and contributors 2022. 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;
    }