flattenTree.mjs

import get from 'lodash-es/get.js'
import size from 'lodash-es/size.js'
import treeObj from './treeObj.mjs'
import isestr from './isestr.mjs'
import isarr from './isarr.mjs'
import isobj from './isobj.mjs'
import isobj0 from './isobj0.mjs'


/**
 * 展平樹狀物件或陣列
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/flattenTree.test.mjs Github}
 * @memberOf wsemi
 * @param {Array|Object} data 輸入樹狀物件或陣列
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {String} [bindKey='id'] 輸入節點物件識別用欄位字串,預設'id'
 * @param {String} [bindChildren='children'] 輸入節點物件內存放子節點欄位字串,預設'children'
 * @returns {Array} 回傳節點物件陣列
 * @example
 *
 * let obj = {
 *     id: 1,
 *     data: '1-abc',
 *     children: [
 *         {
 *             id: 2,
 *             data: '2-def',
 *         },
 *         {
 *             id: 3,
 *             data: '3-ghi',
 *             children: [
 *                 {
 *                     id: 4,
 *                     data: '4-jkl',
 *                 },
 *             ],
 *         },
 *         {
 *             id: 5,
 *             data: '5-mno',
 *         },
 *     ],
 * }
 * let crobj = flattenTree(obj)
 * console.log(JSON.stringify(crobj))
 * // => {"id":1,"data":"1-abc","children":[{"id":2,"data":"2-def"},{"id":3,"data":"3-ghi","children":[{"id":4,"data":"4-jkl"}]},{"id":5,"data":"5-mno"}],"level":0,"nk":[0]}
 *
 * let arr = [
 *     {
 *         id: 1,
 *         text: '1x',
 *     },
 *     {
 *         id: 2,
 *         text: '2y',
 *         children: [
 *             {
 *                 id: 3,
 *                 text: '3z',
 *             },
 *         ],
 *     },
 *     {
 *         id: 4,
 *         text: 'empty',
 *     },
 * ]
 * let crarr = flattenTree(arr)
 * console.log(JSON.stringify(crarr))
 * // => [{"id":1,"text":"1x","level":0,"nk":[0]},{"id":2,"text":"2y","children":[{"id":3,"text":"3z"}],"level":0,"nk":[1]},{"id":3,"text":"3z","level":1,"nk":[1,"children",0]},{"id":4,"text":"empty","level":0,"nk":[2]}]
 *
 */
function flattenTree(data, opt = {}) {

    //check
    if (isarr(data)) {
        if (data.length === 0) {
            return []
        }
    }
    else if (isobj(data)) {
        if (isobj0(data)) {
            return []
        }
    }
    else {
        return []
    }

    //bindKey
    let bindKey = get(opt, 'bindKey', null)
    if (!isestr(bindKey)) {
        bindKey = 'id'
    }

    //bindChildren
    let bindChildren = get(opt, 'bindChildren', null)
    if (!isestr(bindChildren)) {
        bindChildren = 'children'
    }

    //data
    let toArr = false
    if (isobj(data)) {
        toArr = true
        data = [data]
    }

    function getNk(nk) {
        //將nk內插入bindChildren, 因主節點為array, 各節點內的子節點也為array
        let r = [nk[0]]
        for (let i = 1; i < nk.length; i++) {
            let k = nk[i]
            r.push(bindChildren)
            r.push(k)
        }
        return r
    }

    //nodes
    let nodes = []
    treeObj(data, (value, key, nk) => {
        //console.log({ value, key, nk })

        //pk
        let pk = get(value, bindKey, null)

        //children
        let children = get(value, bindChildren, null)

        //push
        if (pk) {
            let nkt = getNk([...nk, key])
            nodes.push({
                ...value,
                level: (size(nkt) - 1) / 2,
                nk: nkt,
                // key,
            })
            if (children) {
                return children
            }
        }

    })

    //toArr
    if (toArr) {
        nodes = nodes[0]
    }

    return nodes
}


export default flattenTree