0.0.32 • Published 4 years ago

treelike v0.0.32

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

Treelike

treelike logo

treelike is a small set of functions that helps you converting a JS object into tree structure.

For example:

concept behind treelike

Quick Example

More details on the functions used in the Quick Example can be found in the section Available Functions.

import {
  treeOf,
  traverse,
  parentTraverser
  TraverseCallbackFn,
} from 'treelike';

const myObject = {
  a: 1,
  b: 'a string',
  c: false,
  d: {
    aa: 123,
    bb: 'another string',
  },
  e: [{}, 2, true],
};

// creates a tree of myObject and returns the root node
const rootNode = treeOf(myObject);

// traverses the tree (starting from the node given, rootNode in this example)
// and calls the callback function for each node being traversed:
traverse(rootNode, (node: ObjectTreeNode) => console.log(node.name));

// you can also change the traversing strategy, e.g. traverse bottom up:
traverse(rootNode, (node: ObjectTreeNode) => console.log(node.name), parentTraverser);

Available Functions

treeOf

treeOf(value: any, childSelector?: SelectorFn, parent?: ObjectTreeNode): ObjectTreeNode

Converts a value into a tree like structure and returns the root node of the created tree.

ParameterTypeDescription
valueanyThe value to convert into a treelike structure.
childSelectorSelectorFn(Optional) A function recursively receiving and filtering the value's child-values (such as properties, or items of child-arrays).
parentObjectTreeNode(Optional) An ObjectTreeNode to be used as parent for the tree (tree concatenation).
returnsObjectTreeNodeThe ObjectTreeNode representing the value passed in.

Example

const obj = { a: 1, b: false, c: [{}, 'str'] };
const rootNode = treeOf(obj);

toValue

toValue(node: ObjectTreeNode, selectChild?: SelectorFn<ObjectTreeNode>): any

The toValue function is the opposite of treeOf, as it converts a treelike structure back into the value it represents.

ParameterTypeDescription
nodeObjectTreeNodeThe node to convert back into the value it represents.
childSelectorSelectorFn(Optional) A function recursively receiving and filtering the node's child-nodes.
returnsanyThe value that the original ObjectTreeNode formerly represented.

Example

const obj = { a: 1, b: false, c: [{}, 'str'] };

const rootNode = treeOf(obj);
const value = toValue(rootNode);
// => { a: 1, b: false, c: [{}, 'str'] }

traverse

traverse(startNode: ObjectTreeNode, callback: TraverseCallbackFn, strategy?: TraverserFn): void

Traverses the tree from the given startNode and calls the callback function for each node being traversed. You can also set the traverse strategy, which can be either one of the built-in strategies or a custom one:

ParameterTypeDescription
startNodeObjectTreeNodeThe node to begin traversion on.
callbackTraverseCallbackFnA callback function receiving each ObjectTreeNode being traversed.
strategyTraverserFn(Optional) A function receiving an ObjectTreeNode and returning another based ont the given input.

Built-in TraverseStrategies

  • treeTraverser: runs down from the given startNode from top to down and left to right (used by default):

            ((1)) StartNode
            /   \
          (2)   (3)
         /   \     \
       (4)   (5)   (9)
      /     /   \
    (6)   (7)   (8)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
  • childTraverser: recursively iterates over all children first, then recursing over these children the same way:

            ((9)) StartNode
            /   \
          (1)   (2)
         /   \     \
       (3)   (4)   (8)
      /     /   \
    (5)   (5)   (7)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
  • parentTraverser: recursively iterates over all parents of the startNode and their siblings:

                        (5)
                       /   \
                     (3)   (4)
                    /   \     \
                  (1)   (2)   (x)
                 /     /   \
    StartNode ((x))  (x)   (x)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
    (x): tree-node, not being passed to callback functon.
  • siblingTraverser: iterates over all siblings of the startNode, but not the startNode itself:

                   ( x )
                  /  |  \
    StartNode ((x)) (1)  (2)
                   /   \   \
                 (x)   (x)  (x)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
    (x): tree-node, not being passed to callback functon.

    Also it does not iterate over any children of the siblings.

  • siblingAndSelfTraverser: iterates over all siblings of the startingNode including the startingNode itself:

                   ( x )
                  /  |  \
    StartNode ((1)) (2)  (3)
                   /   \   \
                 (x)   (x)  (x)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
    (x): tree-node, not being passed to callback functon.
  • siblingWithChildrenTraverser: iterates over all siblings of the startNode, but not the startNode itself. Also recursively finds and iterates all children of the siblings (level by level):

                   ( x )
                  /  |  \
    StartNode ((x)) (1)  (2)
                   /   \   \
                 (3)   (4)  (5)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
    (x): tree-node, not being passed to callback functon.
  • siblingAndSelfWithChildrenTraverser: iterates over all siblings of the startNode including the startNode itself. Also recursively finds and iterates all children of the siblings and the startNode (level by level):

                   ( x )
                  /  |  \
    StartNode ((1)) (2)  (3)
                   /   \   \
                 (4)   (5)  (6)
                /   \        |
              (7)   (8)     (9)
    
    (n): tree-node, where the number indicates the order in which they are passed to the callback function.
    (x): tree-node, not being passed to callback functon.

Example Usage of a Built-in TraverseStrategy

import { treeOf, traverse, childTraverser } from 'treelike';

const rootNode = treeOf(someObj);
// third parameter of traverse is the strategy, here we use childTraverser:
traverse(rootNode, node => console.log(node), childTraverser);

Write your Custom TraverseStrategy

import { treeOf, traverse, ObjectTreeNode, TraverserCallbackFn } from 'treelike';

// node will be the startNode, use it as entry point to traverse.
function myCustomTraverser(node: ObjectTreeNode, onNext: TraverserCallbackFn): void {
  if (node !== undefined) {
    // send next node to user:
    onNext(node);
  }

  // recursively climb up the parents:
  if (node.parent !== undefined) {
    myCustomTraverser(node.parent, onNext);
  }
}

// then use it:
const rootNode = treeOf(someObj);
traverse(rootNode, node => console.log(node), myCustomTraverser);

Info: While the traversers should never have any side effects on the tree, the given onNext-callback argument can manupulate the tree nodes.


findNode

findNode(root: ObjectTreeNode, condition: ConditionFn, strategy = treeTraverser): ObjectTreeNode | undefined

Tries to find a node within the given tree-root, that satisfies the condition specified by a ConditionFn. Additionally accepts a TraverserFn, defining how to traverse the given tree. It returns the first match being found.

ParameterTypeDescription
rootObjectTreeNodeA root-node representing the tree to find the specified node on.
conditionConditionFnThe function deciding which ObjectTreeNode matches the search criteria.
strategyTraverserFn.(Optional) The strategy to use for traversing the given tree.
returnsObjectTreeNode | undefinedThe first ObjectTreeNode matching the search criteria.

Example

const tree = treeOf({
  a: true,
  b: 42,
  c: ['str', null],
});

const nodeA = findNode(tree, node => node.name === 'a');
// => finds node for property "a"
const nodeB = findNode(tree, node => node.value === 42);
// => finds node for property "b"

const nodeSecondItem = findNode(tree, node => {
  // index 1 = second item of an array
  const isSecondItem = node.name === 1;
  const isChildOfC = node.parent && node.parent.name === 'c';

  return isChildOfC && isSecondItem;
}); // => finds node for property "c[1]"

findNodes

findNodes(root: ObjectTreeNode, condition: ConditionFn, strategy = treeTraverser): ObjectTreeNode[]

Tries to find nodes within the given tree-root, that satisfy the condition specified by a ConditionFn. Additionally accepts a TraverserFn, defining how to traverse the given tree. It returns all matches being found.

ParameterTypeDescription
rootObjectTreeNodeA root-node representing the tree to find the specified nodes on.
conditionConditionFnThe function deciding which ObjectTreeNodes match the search criteria.
strategyTraverserFn.(Optional) The strategy to use for traversing the given tree.
returnsObjectTreeNode[]All ObjectTreeNodes matching the search criteria.

Example

const tree = treeOf({
  a: true,
  b: 42,
  c: ['str', null],
});

const nodeSecondItem = findNode(tree, node => {
  const isNumber = typeof node.value === 'number';
  // index 1 = second item of an array
  const isSecondItem = node.name === 1;

  return isNumber || isSecondItem;
}); // => finds node for  "b" and "c[1]"

createNode

createNode(name: string, value: any, children?: ObjectTreeNode[], parent?: ObjectTreeNode): ObjectTreeNode

Creates a new ObjectTreeNode with the specified properties. When using this method the type-property on the created node gets autmatically inferred from the value-argument that was passed in.

ParameterTypeDescription
namestringThe name describing the property name of the node when passed to toValue.
valueanyThe value that the node represents.
childrenObjectTreeNode(Optional) The children (representing items or properties) the node should have. Defaults to [].
parentObjectTreeNode(Optional) The parent of the node. Defaults to undefined.
returnsObjectTreeNodeA new ObjectTreeNode instance having your custom properties.

About the type property

The type-property reflects the type of the node's value. Valid values for the type-property are: 'object', 'array' and 'value'.


Please Note: When manually changing the value of a node, the type-property does not get automatically updated. You can use the nodeTypeOf function for this.

Example: nodeTypeOf

const obj = {
  a: [],
  b: {},
  c: 1,
  d: true,
  e: 'str',
  f: () => {},
};

const root = treeOf(obj);

nodeTypeOf(findNode(root, n => n.name === 'a')); // 'array'
nodeTypeOf(findNode(root, n => n.name === 'b')); // 'object'
nodeTypeOf(findNode(root, n => n.name === 'c')); // 'value'
nodeTypeOf(findNode(root, n => n.name === 'd')); // 'value'
nodeTypeOf(findNode(root, n => n.name === 'e')); // 'value'
nodeTypeOf(findNode(root, n => n.name === 'f')); // 'value'

nodeTypeOf

nodeTypeOf(value: any): ObjectTreeNodeType

Returns the ObjectTreeNodeType for the specified value.


addChild

addChild(node: ObjectTreeNode, toNode: ObjectTreeNode): void

Adds the specified node to the children of the toNode argument and updates the nodes' parent and child properties.

ParameterTypeDescription
nodeObjectTreeNodeThe ObjectTreeNode to add as a child.
toNodeObjectTreeNodeThe node that should receive the child.

Example

const parent: ObjectTreeNode = createNode('parentName', []);
const newChild: ObjectTreeNode = createNode('childName', {});

addChild(newChild, parent);
// this will add 'newChild' to 'parent.children', and set 'parent' as 'newChild.parent'

addChildren

addChildren(nodes: ObjectTreeNode[], toNode: ObjectTreeNode): void

Adds the specified array of nodes to the node specified as toNode argument and updates the nodes' parent and child properties.

ParameterTypeDescription
nodesObjectTreeNode[]The ObjectTreeNode to add as a children.
toNodeObjectTreeNodeThe node that should receive the child.

Example

const parent: ObjectTreeNode = createNode('parentName', []);
const child1: ObjectTreeNode = createNode('child1', {});
const child2: ObjectTreeNode = createNode('child2', {});

const childCollection = [child1, child2];
addChildren(childCollection, parent);
// this will add 'child1' and 'child2' to 'parent.children', and set 'parent' on both of these child nodes to the 'parent' node

addNewChild

addNewChild(toNode: ObjectTreeNode, name: string, value: any, children?: ObjectTreeNode[]): void

Creates a new node and adds it as a child to the specified toNode argument. Meant as a shortcut for a combination of createNode and addNode, like this:

ParameterTypeDescription
toNodeObjectTreeNodeThe ObjectTreeNode to add as a children.
namestringThe name of the node to create. The name represents the node's item-index or property-name when processed by toValue
valuestringThe value of the node.
childrenObjectTreeNode[](Optional) The node's children representing items or properties of the node's value.

Example

// more explicit way:
const parent = createNode('parentName', null);
const child = createNode('childName', null);
addChild(child, parent);

// shortcut with 'addNewChild'
const parent = createNode('parentName', null);
addNewChild(parent, 'childName', null);

remove

remove(node: ObjectTreeNode, parent?: ObjectTreeNode): number

Removes the specified node from the children array of a given node and returns the former index of the removed node. If the parent-argument is not set, its defaults to the parent-property of the given node-argument.

Please Note: the method will not throw if the node is not found in the parent-node's children array. Instead the index -1 is returned and nothing gets changed on the children array of the parent.

ParameterTypeDescription
nodeObjectTreeNodeThe ObjectTreeNode to remove from children.
parentObjectTreeNode(Optional) The parent node to remove the node from. Defaults to node.parent

replace

replace(node: ObjectTreeNode, withNode: ObjectTreeNode, onNode?: ObjectTreeNode): void

Replaces the specified node with another node in the children array of the onNode-argument. If the onNode-argument is undefined, its value defaults to the parent-property of the node-argument.

ParameterTypeDescription
nodeObjectTreeNodeThe ObjectTreeNode to remove from children.
withNodeObjectTreeNodeThe ObjectTreeNode to add in place to the children.
onNodeObjectTreeNode(Optional) The node containing the given node. Defaults to node.parent

Example

const parent = createNode('parentName', null);
const child1 = createNode('child1', null);
addChild(child1, parent);

// now replace child1 with child2
const child2 = createNode('child2', null);
replace(child1, child2, parent);

// or: shorter way, since we know that child1.parent === parent, we can omit the third argument:
replace(child1, child2);

Types and Interfaces

ObjectTreeNodeType

Defines possible types of ObjectTreeNodes. The type gets deduced by the type of an ObjectTreeNode's value.

type ObjectTreeNodeType = 'object' | 'array' | 'value';

Important: When changing the value of an ObjectTreeNode, the type-property does not automatically get updated. This is a responsibility of the value-changing code.


ObjectTreeNode<T>

The interface describing a node as produced by treeOf function.

interface ObjectTreeNode<T = any> {
  parent?: ObjectTreeNode<any>;
  name: string | number;
  type: ObjectTreeNodeType;
  children: ObjectTreeNode<any>[];
  isRecursionRoot: boolean;
  value: T;
}
PropertyTypeDescription
namestring | numberThe name of the node. Represents an item index or property name, based on the node.type-property
valueT defaults to anyThe value that the node represents.
typeObjectTreeNodeTypeThe node's ObjectTreeNodeType. It reflects the type of node.value.
parentObjectTreeNodeThe node's parent node. If undefined, the node is the root node of a tree.
childrenObjectTreeNode[]The node's child nodes.
isRecursionRootbooleanWhether the node is the root-node of a recursive (sub)-tree.

TraverserFn

A function that receives an ObjectTreeNode, traverses it and calls a `TraverseCallbackFn´ for each traversed node.

type TraverserFn = (node: ObjectTreeNode, onNext: TraverseCallbackFn) => void


TraverseCallbackFn

A callback function that receives every node being traversed.

type TraverseCallbackFn = (node: ObjectTreeNode) => void


SelectorFn<T>

A function that receives an input (of type any for treeOf and ObjectTreeNode for toValue) and computes values that should be used as children (in node context).

type SelectorFn<T = any> = (input: T) => T


ConditionFn

A function that receives an input of type ObjectTreeNode and computes a boolean value from it. It represents a condition that is based ont a ObjectTreeNode.

type ConditionFn = (node: ObjectTreeNode) => boolean

0.0.32

4 years ago

0.0.31

4 years ago

0.0.30

4 years ago

0.0.27

4 years ago

0.0.28

4 years ago

0.0.29

4 years ago

0.0.26

4 years ago

0.0.25

4 years ago

0.0.23

4 years ago

0.0.24

4 years ago

0.0.22

4 years ago

0.0.21

4 years ago

0.0.20

4 years ago

0.0.19

4 years ago

0.0.16

4 years ago

0.0.17

4 years ago

0.0.18

4 years ago

0.0.15

4 years ago

0.0.14

4 years ago

0.0.13

4 years ago

0.0.11

4 years ago

0.0.12

4 years ago

0.0.1

4 years ago