Skip to content

Commit

Permalink
feat: Add obj._array2tree and obj._tree2array helper methods
Browse files Browse the repository at this point in the history
  • Loading branch information
AxiosLeo committed Feb 23, 2024
1 parent 235c1d0 commit 4f657c7
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
62 changes: 62 additions & 0 deletions src/helper/obj.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,71 @@ function _deep_clone(obj) {
return copy;
}

function _array2tree(data, options = {}) {
if (!is.array(data)) {
throw new Error('data must be an array');
}
const c = _assign({
parent_index: 'parent_id',
data_index: 'id',
child_name: 'child'
}, options);

const items = [];
data.forEach(d => {
if (typeof d[c.child_name] === 'undefined') {
d[c.child_name] = [];
} else {
throw new Error('child name "' + c.child_name + '" is reserved for child data, please use another name');
}
items[d[c.data_index]] = d;
if (typeof d[c.parent_index] === 'undefined' || typeof d[c.data_index] === 'undefined') {
throw new Error('data must have "' + c.parent_index + '" and "' + c.data_index + '"');
}
});

const tree = [];
let n = 0;
data.forEach(item => {
if (items[item[c.parent_index]]) {
items[item[c.parent_index]][c.child_name].push(items[item[c.data_index]]);
} else {
tree[n++] = items[item[c.data_index]];
}
});
return tree;
}

function _tree2array(tree, options = {}) {
if (!is.array(tree)) {
tree = [tree];
}
const c = _assign({
parent_index: 'parent_id',
data_index: 'id',
child_name: 'child'
}, options);
const res = [];
function recurse(data, parent_id) {
data.forEach(d => {
const child = d[c.child_name].map(i => i);
delete d[c.child_name];
d[c.parent_index] = parent_id || 0;
res.push(d);
if (child.length) {
recurse(child, d[c.data_index]);
}
});
}
recurse(tree, 0);
return res;
}

module.exports = {
_assign,
_flatten,
_unflatten,
_array2tree,
_tree2array,
_deep_clone
};
66 changes: 65 additions & 1 deletion tests/obj.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const expect = require('chai').expect;
const { Configuration } = require('..');
const { _deep_clone, _flatten, _unflatten } = require('../src/helper/obj');
const { _deep_clone, _flatten, _unflatten, _array2tree, _tree2array } = require('../src/helper/obj');

describe('obj test case', function () {
it('flatten', function () {
Expand Down Expand Up @@ -66,4 +66,68 @@ describe('obj test case', function () {
expect(complexObj.a.b.c.d.length).to.be.equal(1);
expect(complexObj.a.b.c.d[0].x).to.be.equal('1');
});
it('array2tree', function () {
const data = [
{ id: 1, parent_id: 0 },
{ id: 2, parent_id: 3 },
{ id: 3, parent_id: 1 },
{ id: 4, parent_id: 2 },
{ id: 5, parent_id: 6 },
{ id: 6, parent_id: 7 },
{ id: 7, parent_id: 5 }
];
const res = _array2tree(data, { parent_index: 'parent_id', data_index: 'id', child_name: 'child' });
expect(res.length).to.be.equal(1);
expect(res[0].id).to.be.equal(1);
expect(res[0].child.length).to.be.equal(1);
expect(res[0].child[0].id).to.be.equal(3);
expect(res[0].child[0].child.length).to.be.equal(1);
expect(res[0].child[0].child[0].id).to.be.equal(2);
expect(res[0].child[0].child[0].child.length).to.be.equal(1);
expect(res[0].child[0].child[0].child[0].id).to.be.equal(4);
expect(res[0].child[0].child[0].child[0].child.length).to.be.equal(0);
expect(res[0].child[0].child[0].child[0].parent_id).to.be.equal(2);

// throw error when data is not array
expect(() => _array2tree(null)).to.throw('data must be an array');
expect(() => _array2tree([{ id: 1 }])).to.throw('data must have "parent_id" and "id"');
expect(() => _array2tree([{ id: 1, parent_id: 0, child: [] }])).to.throw('child name "child" is reserved for child data, please use another name');
});

it('tree2array', function () {
const data = [
{
'id': 1,
'parent_id': 0,
'child': [
{
'id': 3,
'parent_id': 1,
'child': [
{
'id': 2,
'parent_id': 3,
'child': [
{
'id': 4,
'parent_id': 2,
'child': []
}
]
}
]
}
]
}
];
let res = _tree2array(data, { parent_index: 'parent_id', data_index: 'id', child_name: 'child' });
expect(JSON.stringify(_array2tree(res))).to.equal(JSON.stringify(data));

const data2 = _deep_clone(data);
delete data2[0].parent_id;
delete data2[0].child[0].parent_id;
delete data2[0].child[0].child[0].parent_id;
res = _tree2array(data2[0]);
expect(JSON.stringify(_array2tree(res))).to.equal(JSON.stringify(data));
});
});

0 comments on commit 4f657c7

Please sign in to comment.