feat: add circular reference to parents of nodes

pull/4377/head
Arman Ozak 5 years ago
parent 66111b9afa
commit c72bcf48f4

@ -1,4 +1,4 @@
import { createTreeFromList, TreeNode } from '../utils/tree-utils'; import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils';
const LIST_1 = [ const LIST_1 = [
{ id: 1, pid: null }, { id: 1, pid: null },
@ -46,23 +46,32 @@ describe('Tree Utils', () => {
${LIST_2} | ${TREE_2} ${LIST_2} | ${TREE_2}
${LIST_3} | ${TREE_3} ${LIST_3} | ${TREE_3}
`('should return $expected when given $list', ({ list, expected }: TestCreateTreeFromList) => { `('should return $expected when given $list', ({ list, expected }: TestCreateTreeFromList) => {
expect( const tree = createTreeFromList(
createTreeFromList( list,
list, x => x.id,
x => x.id, x => x.pid,
x => x.pid, x => BaseTreeNode.create(x),
), );
).toEqual(expected);
expect(removeParents(tree)).toEqual(expected);
}); });
}); });
}); });
function removeParents(tree: TreeNode<Model>[]) {
return tree.map(v => {
const { parent, ...node } = v;
node.children = removeParents(node.children);
return node;
});
}
interface TestCreateTreeFromList { interface TestCreateTreeFromList {
list: ModelA[]; list: Model[];
expected: TreeNode<ModelA>[]; expected: TreeNode<Model>[];
} }
interface ModelA { interface Model {
id: 1; id: 1;
pid: null; pid: null;
} }

@ -1,19 +1,20 @@
export class TreeNodeFactory<T extends object> { export class BaseTreeNode<T extends object> {
children: TreeNode<T>[] = []; children: TreeNode<T>[] = [];
isLeaf = true; isLeaf = true;
parent: TreeNode<T>;
constructor(props: T) { constructor(props: T) {
Object.assign(this, props); Object.assign(this, props);
} }
static create<T extends object>(props: T) { static create<T extends object>(props: T) {
return new TreeNodeFactory<T>(props) as TreeNode<T>; return new BaseTreeNode<T>(props) as TreeNode<T>;
} }
} }
export function createTreeFromList<T extends object, R extends unknown>( export function createTreeFromList<T extends object, R extends unknown>(
list: T[], list: T[],
keySelector: (item: T) => number | string | Symbol, keySelector: (item: T) => number | string | symbol,
parentKeySelector: typeof keySelector, parentKeySelector: typeof keySelector,
valueMapper: (item: T) => R, valueMapper: (item: T) => R,
) { ) {
@ -27,8 +28,10 @@ export function createTreeFromList<T extends object, R extends unknown>(
if (parentId) { if (parentId) {
const parent = map.get(parentId); const parent = map.get(parentId);
if (!parent) return;
(parent as any).children.push(node); (parent as any).children.push(node);
(parent as any).isLeaf = false; (parent as any).isLeaf = false;
(node as any).parent = parent;
} else { } else {
tree.push(node); tree.push(node);
} }
@ -39,7 +42,7 @@ export function createTreeFromList<T extends object, R extends unknown>(
export function createMapFromList<T extends object, R extends unknown>( export function createMapFromList<T extends object, R extends unknown>(
list: T[], list: T[],
keySelector: (item: T) => number | string | Symbol, keySelector: (item: T) => number | string | symbol,
valueMapper: (item: T) => R, valueMapper: (item: T) => R,
) { ) {
type Key = ReturnType<typeof keySelector>; type Key = ReturnType<typeof keySelector>;
@ -54,6 +57,7 @@ export type TreeNode<T extends object> = {
} & { } & {
children: TreeNode<T>[]; children: TreeNode<T>[];
isLeaf: boolean; isLeaf: boolean;
parent?: TreeNode<T>;
}; };
type NodeValue<T extends object, F extends (...args: any) => any> = F extends undefined type NodeValue<T extends object, F extends (...args: any) => any> = F extends undefined

Loading…
Cancel
Save