Skip to content

riexn/tree-handler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NPM
GitHub Workflow Status (branch) codecov Known Vulnerabilities npm version

Tree Handler

tree-handler is a module to easily manipulate tree structures.

API

Parse tree

import treeHandler from 'tree-handler';
const model = {
  id: 'root',
  children: [
    { id: 'A', children: [] },
    { id: 'B', children: [] },
  ],
};
const tree = treeHandler.parse(model);

Parse with a custom children property

import treeHandler from 'tree-handler';
const model = {
  id: 'root',
  subtasks: [
    { id: 'A', subtasks: [] },
    { id: 'B', subtasks: [] },
  ],
};
const tree = treeHandler.parse(model, { childrenProperty: 'subtasks' });

Find a single node that matches a criteria

tree.findOne((node) => node.model.id === 'A');

Find many nodes that match a criteria

tree.find((node) => node.model.type === 'cake');

Add a new node as an object

tree.addChild({ id: '123', type: 'chocolate', children: [] });

Add a new node as a node

const newNode = treeHandler.parse({
  id: '123',
  type: 'chocolate',
  children: [],
});
tree.addChild(newNode);

Delete a node

const node = tree.findOne((node) => node.model.id === 'A');
node.delete();

Move a node under a new parent

const modelA = {
  id: 'A',
  children: [
    { id: 'B', children: [{ id: 'B1', children: [] }] },
    {
      id: 'C',
      children: [
        { id: 'C1', children: [] },
        { id: 'C2', children: [] },
      ],
    },
  ],
};

const tree = treeHandler.parse(modelA);

tree.moveUnderParnet({
  node: (node) => node.model.id === 'B1',
  toParent: (node) => node.model.id === 'C',
  atIndex: 1,
});

Move a node next to a sibling

tree.moveToSibling({
  node: (node) => node.model.id === 'B1',
  toSibling: (node) => node.model.id === 'C2',
  at: 'BEFORE', // options: BEFORE, AFTER
});

Filter Tree Nodes

the filter function will return to us new TreeNode classes based on the filter conditions. There are two modes to filter a tree structure.

Remove Children Mode (Default)

this one is the "expected" way of filtering a tree structure's nodes. If a node should be filtered out, then that node along its children will be removed.

const dataTree = {
  id: '1',
  tag: 'pending',
  subtasks: [
    {
      id: '2',
      tag: 'pending',
      subtasks: [
        { id: '4', tag: 'complete', subtasks: [] },
        { id: '46', tag: 'in progress', subtasks: [] },
      ],
    },
    {
      id: '3',
      tag: 'in progress',
      subtasks: [
        {
          id: '4',
          tag: 'pending',
          subtasks: [
            {
              id: '6',
              tag: 'complete',
              subtasks: [
                {
                  id: '10',
                  tag: 'pending',
                  subtasks: [{ id: '11', tag: 'complete', subtasks: [] }],
                },
              ],
            },
            {
              id: '7',
              tag: 'complete',
              subtasks: [{ id: '74', tag: 'in progress', subtasks: [] }],
            },
          ],
        },
        { id: '5', tag: 'pending', subtasks: [] },
      ],
    },
    { id: '4', tag: 'complete', subtasks: [] },
  ],
};

const tree = treeHandler.parse(dataTree, {
  childrenProperty: 'subtasks',
});
const newTree = tree.filter((node) => node.tag !== 'in progress');

console.log(newTree);

result:

{
  id: '1',
  tag: 'pending',
  subtasks: [
    {
      id: '2',
      tag: 'pending',
      subtasks: [{ id: '4', tag: 'complete', subtasks: [] }],
    },
    { id: '4', tag: 'complete', subtasks: [] },
  ],
};

Merge Children Mode

this filtering method is unique. What it does is that it filtering out each node indiviually. Meaning if a node should be filtered out, and if it has children that should not be filtered out, then those children will be moved to the same depth level and starting index number of their parent.

const dataTree = {
  id: '1',
  tag: 'pending',
  subtasks: [
    { id: '2', tag: 'pending', subtasks: [] },
    {
      id: '3',
      tag: 'in progress',
      subtasks: [
        {
          id: '4',
          tag: 'pending',
          subtasks: [
            {
              id: '6',
              tag: 'complete',
              subtasks: [
                {
                  id: '10',
                  tag: 'pending',
                  subtasks: [{ id: '10', tag: 'complete', subtasks: [] }],
                },
              ],
            },
            { id: '7', tag: 'complete', subtasks: [] },
          ],
        },
        { id: '5', tag: 'pending', subtasks: [] },
      ],
    },
    { id: '4', tag: 'complete', subtasks: [] },
  ],
};

const treeResult =
const tree = treeHandler.parse(dataTree, { childrenProperty: 'subtasks' });
const newTrees = tree.filter(
  (node) => node.tag !== 'in progress',
  'mergeChildren'
);

console.log(newTrees)

result:

[
  {
    id: '1',
    tag: 'pending',
    subtasks: [
      { id: '2', tag: 'pending', subtasks: [] },
      {
        id: '4',
        tag: 'pending',
        subtasks: [
          {
            id: '6',
            tag: 'complete',
            subtasks: [
              {
                id: '10',
                tag: 'pending',
                subtasks: [{ id: '10', tag: 'complete', subtasks: [] }],
              },
            ],
          },
          { id: '7', tag: 'complete', subtasks: [] },
        ],
      },
      { id: '5', tag: 'pending', subtasks: [] },
      { id: '4', tag: 'complete', subtasks: [] },
    ],
  },
];

Flatten tree to array of nodes

tree.flatten();

Loop across every node in the tree

tree.forEach((node) => {
  console.log(node);
});

Credits

Heavily inspired by tree-model

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published