Browse Source

feat: add tree utils to core

pull/4377/head
Arman Ozak 6 years ago
parent
commit
ed41a884bc
  1. 68
      npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts
  2. 1
      npm/ng-packs/packages/core/src/lib/utils/index.ts
  3. 51
      npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

68
npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts

@ -0,0 +1,68 @@
import { createTreeFromList, TreeNode } from '../utils/tree-utils';
const LIST_1 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
];
const LIST_2 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 1 },
];
const LIST_3 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 2 },
];
const TREE_1 = [
{ id: 1, pid: null, isLeaf: false, children: [{ id: 2, pid: 1, isLeaf: true, children: [] }] },
];
const TREE_2 = [
{
id: 1,
pid: null,
isLeaf: false,
children: [
{ id: 2, pid: 1, isLeaf: true, children: [] },
{ id: 3, pid: 1, isLeaf: true, children: [] },
],
},
];
const TREE_3 = [
{
id: 1,
pid: null,
isLeaf: false,
children: [
{ id: 2, pid: 1, isLeaf: false, children: [{ id: 3, pid: 2, isLeaf: true, children: [] }] },
],
},
];
describe('Tree Utils', () => {
describe('createTreeFromList', () => {
test.each`
list | expected
${LIST_1} | ${TREE_1}
${LIST_2} | ${TREE_2}
${LIST_3} | ${TREE_3}
`('should return $expected when given $list', ({ list, expected }: TestCreateTreeFromList) => {
expect(
createTreeFromList(
list,
x => x.id,
x => x.pid,
),
).toEqual(expected);
});
});
});
interface TestCreateTreeFromList {
list: ModelA[];
expected: TreeNode<ModelA>[];
}
interface ModelA {
id: 1;
pid: null;
}

1
npm/ng-packs/packages/core/src/lib/utils/index.ts

@ -9,3 +9,4 @@ export * from './localization-utils';
export * from './number-utils';
export * from './route-utils';
export * from './rxjs-utils';
export * from './tree-utils';

51
npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

@ -0,0 +1,51 @@
export class TreeNode<T extends any> {
children: TreeNode<T>[] = [];
isLeaf = true;
constructor(props: T) {
Object.assign(this, props);
}
}
export function createTreeFromList<T extends object, R extends BranchOrLeaf<T>>(
list: T[],
keySelector: (item: T) => NodeKey,
parentKeySelector: (item: T) => NodeKey,
valueMapper = (item: T) => new TreeNode(item) as R,
) {
const map = createMapFromList(list, keySelector, valueMapper);
const tree: ReturnType<typeof valueMapper>[] = [];
list.forEach(row => {
const id = keySelector(row);
const parentId = parentKeySelector(row);
const node = map.get(id);
if (parentId) {
const parent = map.get(parentId);
parent.children.push(node);
parent.isLeaf = false;
} else {
tree.push(node);
}
});
return tree;
}
export function createMapFromList<T extends object, R extends BranchOrLeaf<T>>(
list: T[],
keySelector: (item: T) => NodeKey,
valueMapper = (item: T) => new TreeNode(item) as R,
) {
const map = new Map<ReturnType<typeof keySelector>, ReturnType<typeof valueMapper>>();
list.forEach(row => map.set(keySelector(row), valueMapper(row)));
return map;
}
type NodeKey = number | string | Symbol;
interface BranchOrLeaf<T> {
children: BranchOrLeaf<T>[];
isLeaf: boolean;
}
Loading…
Cancel
Save