declarative-tree
v1.0.2
Published
Generalized way to convert a string to tree, and vice versa. Useful for creating declarative tree tests.
Downloads
3
Maintainers
Readme
Table of contents
- Table of contents
- Installation
- Description
- Code coverage
- Examples
- Documentation
- Motivation
- Contributing
- Changelog
- License
Installation
npm install declarative-tree
Description
Generalized way to convert a string to tree, and vice versa. Useful for creating declarative tree tests.
Code coverage
The testing code coverage is around 90%.
Examples
The following examples deal with converting an AVL tree string representation to tree data structure and vice versa. Here is the code that defines the AVL tree:
class AvlTreeBaseNode {
left: null | AvlTreeNode;
right: null | AvlTreeNode;
id: number;
constructor(_: AvlTreeBaseNode) {
const { id, left, right } = _;
this.id = id;
this.left = left;
this.right = right;
}
}
export class AvlTreeRootNode extends AvlTreeBaseNode {
parent: null;
constructor(_: AvlTreeRootNode) {
const { id, left, right } = _;
super({
id,
left,
right,
});
this.parent = null;
}
}
export class AvlTreeNode extends AvlTreeBaseNode {
parent: AvlTreeNode | AvlTreeRootNode;
constructor(_: AvlTreeNode) {
const { parent, right, left, id } = _;
super({
id,
left,
right,
});
this.parent = parent;
}
}
export class AvlTree {
root: AvlTreeRootNode;
constructor(_: { root: AvlTreeRootNode }) {
const { root } = _;
this.root = root;
}
}
/**
* @description
* The tree looks like this:
* ```
* 20
* |_ 25
* |_ 10
* |_ 5
* ```
*/
export const mockAvlTree: AvlTree = (() => {
const root: AvlTreeRootNode = new AvlTreeRootNode({
id: 20,
left: null, //lazy setted
parent: null,
right: null, //lazy setted
});
const tree: AvlTree = new AvlTree({
root,
});
const left: AvlTreeNode = new AvlTreeNode({
id: 10,
left: null, //lazy setted
parent: root,
right: null,
});
const leftLeft: AvlTreeNode = new AvlTreeNode({
id: 5,
left: null,
parent: left,
right: null,
});
const right: AvlTreeNode = new AvlTreeNode({
id: 25,
left: null,
parent: root,
right: null,
});
root.left = left;
root.right = right;
left.left = leftLeft;
return tree;
})();
tree to string
import { treeToStringHorizontalFactory } from "..";
import { AvlTree, AvlTreeNode, AvlTreeRootNode, mockAvlTree } from "./mockTree";
describe(treeToStringHorizontalFactory.name, () => {
it(`
returns a function that converts a tree to string, according to the
instructions the factory has been provided
`, () => {
const avlTreeToString = treeToStringHorizontalFactory<
AvlTreeNode | AvlTreeRootNode,
AvlTree
>({
getChildren: ({ treeNode }) => {
const children: AvlTreeNode[] = [];
const { left, right } = treeNode;
if (left !== null) children.push(left);
if (right !== null) children.push(right);
return children.reverse();
},
getRoot: ({ tree }) => tree.root,
nodeToString: ({ treeNodeMetadata }) =>
String(treeNodeMetadata.treeNode.id),
});
//prettier-ignore
expect(avlTreeToString({ tree: mockAvlTree })).toBe(
`20\n`+
`|_ 25\n`+
`|_ 10\n`+
` |_ 5`
);
});
});
string to tree horizontal
import { stringToTreeHorizontalFactory } from "..";
import { AvlTree, AvlTreeNode, AvlTreeRootNode, mockAvlTree } from "./mockTree";
describe(stringToTreeHorizontalFactory.name, () => {
it(`
returns a function that converts a string to tree, according to the
instructions the factory has been provided
`, () => {
const stringToAVLTree = stringToTreeHorizontalFactory<
number,
AvlTreeNode | AvlTreeRootNode,
AvlTree
>({
strategy: (parameters) => {
const root: AvlTreeRootNode = new AvlTreeRootNode({
id: parameters.treeNodeMetadataInLevelOrder[0]
.placeholderValue,
left: null,
parent: null,
right: null,
});
const avlTree: AvlTree = new AvlTree({ root });
/**
* @description
* The main idea here is to iterate the tree node metadata, and
* use the information they provide to create the tree nodes.
* When you create a tree node, set it as the `treeNode`
* property of the tree node metadata it corresponds. The sole
* reason for that is that maybe you will need to access that
* node from other nodes.
*/
parameters.treeNodeMetadataInLevelOrder.forEach(
(treeNodeMetadata, i) => {
if (i === 0) {
treeNodeMetadata.treeNode = root;
return;
}
if (i !== 0) {
const parentTreeNodeMetadata =
treeNodeMetadata.parent;
if (parentTreeNodeMetadata === null) {
throw Error(
"only the parent tree node metadata of" +
"the root node can be null"
);
}
const parent = parentTreeNodeMetadata.treeNode;
const currentNode: AvlTreeNode = new AvlTreeNode({
id: treeNodeMetadata.placeholderValue,
left: null,
right: null,
parent,
});
treeNodeMetadata.treeNode = currentNode;
/**
* @description
* Here I connect the parent node with its child
* node. The only way to understand whether the
* child node is a left or right child, is through
* the brach that connects them.
* You are free to use the character that you see
* fit for branches. In this example I choose to use
* `⏝` for left branch and `⏜` for right branch.
* The branch character that you use has to be used
* in the tag function that is returned by the
* factory. Take a look at the test assertion a few
* lines bellow where the tag function is used.
*/
if (treeNodeMetadata.branchTop === "⏝") {
parent.left = currentNode;
return;
}
if (treeNodeMetadata.branchTop === "⏜") {
parent.right = currentNode;
return;
}
throw Error(
`encountered branch that is not "⏝" or "⏜"`
);
}
throw Error("case not accounted for");
}
);
return avlTree;
},
});
expect(stringToAVLTree`
${20}
|⏜ ${25}
|⏝ ${10}
|⏝ ${5}
`).toEqual(mockAvlTree);
});
});
string to tree vertical
import { stringToTreeVerticalFactory } from "..";
import { AvlTree, AvlTreeNode, AvlTreeRootNode, mockAvlTree } from "./mockTree";
describe(stringToTreeVerticalFactory.name, () => {
it(`
returns a function that converts a string to tree, according to the
instructions the factory has been provided
`, () => {
const stringToAvlTree = stringToTreeVerticalFactory<
number,
AvlTreeNode | AvlTreeRootNode,
AvlTree
>({
strategy: (parameters) => {
const root: AvlTreeRootNode = new AvlTreeRootNode({
id: parameters.treeNodeMetadataInLevelOrder[0]
.placeholderValue,
left: null,
parent: null,
right: null,
});
const avlTree: AvlTree = new AvlTree({ root });
/**
* @description
* The main idea here is to iterate the tree node metadata, and
* use the information they provide to create the tree nodes.
* When you create a tree node, set it as the `treeNode`
* property of the tree node metadata it corresponds. The sole
* reason for that is that maybe you will need to access that
* node from other nodes.
*/
parameters.treeNodeMetadataInLevelOrder.forEach(
(treeNodeMetadata, i) => {
if (i === 0) {
treeNodeMetadata.treeNode = root;
return;
}
if (i !== 0) {
const parentTreeNodeMetadata =
treeNodeMetadata.parent;
if (parentTreeNodeMetadata === null) {
throw Error(
"only the parent tree node metadata of " +
"the root node can be null"
);
}
const parent = parentTreeNodeMetadata.treeNode;
const currentNode: AvlTreeNode = new AvlTreeNode({
id: treeNodeMetadata.placeholderValue,
left: null,
right: null,
parent,
});
treeNodeMetadata.treeNode = currentNode;
/**
* @description
* Here I connect the parent node with its child
* node. The only way to understand whether the
* child node is a left or right child, is through
* the brach that connects them.
* You are free to use the character that you see
* fit for branches. In this example I choose to use
* `(` for left branch and `)` for right branch. The
* branch character that you use has to be used in
* the tag function that is returned by the factory.
* Take a look at the test assertion a few lines
* bellow where the tag function is used.
*/
if (treeNodeMetadata.branchTop === "(") {
parent.left = currentNode;
return;
}
if (treeNodeMetadata.branchTop === ")") {
parent.right = currentNode;
return;
}
throw Error(
`encountered branch that is not "(" or ")"`
);
}
throw Error("case not accounted for");
}
);
return avlTree;
},
});
/**
* @description
* You have to add dots. They define where the children group ends. You
* do no need to do that in the last row of the tree. For example in the
* following tree the tree node with id `20` has `10` and `25` as
* children group. The group ends at `25` and hence the dot in the
* branch above `25`. The tree node with id `10` has children group that
* consist only of the tree node with id `5` and hence the dot on its
* branch. The tree node with id `25` has no children so it has a dot
* with no branches.
*/
expect(stringToAvlTree`
${20}
( ).
${10} ${25}
(. .
${5}
`).toEqual(mockAvlTree);
});
});
Documentation
/**
* @description
* Returns a tag function that converts template literals to tree data
* structures, in accordance to the instructions you have provided to the
* factory.
*/
export declare const stringToTreeHorizontalFactory: IStringToTreeFactory;
export declare type IStringToTreeFactory = <placeholder, treeNode, tree>(parameters: {
/**
* @description
* This function is used by the tag function the factory returns, to
* convert template literals to tree data structures.
*/
strategy: (parameters: {
/**
* @description
* The tree node metadata in level order (i.e. as encountered in breadth
* first search).
*/
treeNodeMetadataInLevelOrder: ITreeNodeMetadataStringToTree<placeholder, treeNode>[];
}) => tree;
}) => IStringToTree<placeholder, tree>;
export interface ITreeNodeMetadataStringToTree<placeholderType, treeNode>
extends ITreeNodeMetadataBase<ITreeNodeMetadataStringToTree<placeholderType, treeNode>> {
/**
* @description
* Returns the branch that connects the context tree node to its parent tree
* node.
*
* The following tree has the `branchTop` values next to their corresponding
* placeholders:
*
* ```ts
* `
* ${1} null
* ( ).
* ${2} "(" ${3} ")"
* . ( ).
* ${4} "(" ${5} ")"
* `
* ```
*/
readonly branchTop: string | null;
/**
* @description
* Returns the branches that connect the context tree node to its children.
*
* The following tree has the `branchesBottom` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} ["(",")"]
* ( ).
* ${2} [] ${3} [")"]
* . ).
* ${5} []
* `
* ```
*/
readonly branchesBottom: string[];
/**
* @description
* Returns the placeholder of the template literal that corresponds to the
* context node.
*/
readonly placeholderValue: placeholderType;
/**
* @description
* The tree node that corresponds to the context tree node metadata. It
* throws error when you get without having set before.
*/
treeNode: treeNode;
}
export declare type ITreeNodeMetadataBase<IExtendedTreeNodeMetadata> = {
/**
* @description
* The height of the subtree of the context tree node.
*
* The following tree has the `subTreeHeight` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 4
* ( ).
* ${-2} 2 ${7} 3
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 2
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeHeight: number;
/**
* @description
* The number of nodes of the subtree of the context node.
*
* The following tree has the `subTreeLength` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 9
* ( ).
* ${-2} 3 ${7} 5
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 3
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeLength: number;
/**
* @description
* The tree node metadata of the parent tree node of the context node.
*/
readonly parent: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling of the context. For horizontal
* tree you can treat it as bottom sibling.
*
* The following tree has the `leftSibling` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} -2
* ( ). ( ).
* ${-3} null ${-1} -3 ${6} null ${10} 6
* . . . ( ).
* ${8} null ${11} 8
* `
* ```
*/
readonly leftSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the right sibling of the context. For
* horizontal tree you can treat it as top sibling.
*
* The following tree has the `rightSibling` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} 7 ${7} null
* ( ). ( ).
* ${-3} -1 ${-1} null ${6} 10 ${10} null
* . . . ( ).
* ${8} 11 ${11} null
* `
* ```
*/
readonly rightSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling group of the context. For
* horizontal tree you can treat it as bot sibling group.
*
* The following tree has the `leftSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} null ${-1} null ${6} [-3,-1] ${10} [-3,-1]
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly leftSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the right sibling group of the context. For
* horizontal tree you can treat it as top sibling group.
*
* The following tree has the `rightSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} [6,10] ${-1} [6,10] ${6} null ${10} null
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly rightSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the sibling group of the context.
*
* The following tree has the `currentSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} [1]
* ( ).
* ${-2} [-2,7] ${7} [-2,7]
* ( ). ( ).
* ${-3} [-3,-1] ${-1} [-3,-1] ${6} [6,10] ${10} [6,10]
* . . . ( ).
* ${8} [8,11] ${11} [8,11]
* `
* ```
*/
readonly currentSiblingGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* The tree node metadata of the children group of the context.
*
* The following tree has the `childrenGroup` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} [-2,7]
* ( ).
* ${-2} [-3,-1] ${7} [6,10]
* ( ). ( ).
* ${-3} [] ${-1} [] ${6} [] ${10} [8,11]
* . . . ( ).
* ${8} [] ${11} []
* `
* ```
*/
readonly childrenGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* Tree node metadata in level order.
*/
readonly all: IExtendedTreeNodeMetadata[];
};
export declare type IStringToTree<placeholder, tree> = (strings: TemplateStringsArray, ...placeholders: placeholder[]) => tree;
/**
* @description
* Returns a tag function that converts template literals to tree data
* structures, in accordance to the instructions you have provided to the
* factory.
*/
export declare const stringToTreeVerticalFactory: IStringToTreeFactory;
export declare type IStringToTreeFactory = <placeholder, treeNode, tree>(parameters: {
/**
* @description
* This function is used by the tag function the factory returns, to
* convert template literals to tree data structures.
*/
strategy: (parameters: {
/**
* @description
* The tree node metadata in level order (i.e. as encountered in breadth
* first search).
*/
treeNodeMetadataInLevelOrder: ITreeNodeMetadataStringToTree<placeholder, treeNode>[];
}) => tree;
}) => IStringToTree<placeholder, tree>;
export interface ITreeNodeMetadataStringToTree<placeholderType, treeNode>
extends ITreeNodeMetadataBase<ITreeNodeMetadataStringToTree<placeholderType, treeNode>> {
/**
* @description
* Returns the branch that connects the context tree node to its parent tree
* node.
*
* The following tree has the `branchTop` values next to their corresponding
* placeholders:
*
* ```ts
* `
* ${1} null
* ( ).
* ${2} "(" ${3} ")"
* . ( ).
* ${4} "(" ${5} ")"
* `
* ```
*/
readonly branchTop: string | null;
/**
* @description
* Returns the branches that connect the context tree node to its children.
*
* The following tree has the `branchesBottom` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} ["(",")"]
* ( ).
* ${2} [] ${3} [")"]
* . ).
* ${5} []
* `
* ```
*/
readonly branchesBottom: string[];
/**
* @description
* Returns the placeholder of the template literal that corresponds to the
* context node.
*/
readonly placeholderValue: placeholderType;
/**
* @description
* The tree node that corresponds to the context tree node metadata. It
* throws error when you get without having set before.
*/
treeNode: treeNode;
}
export declare type ITreeNodeMetadataBase<IExtendedTreeNodeMetadata> = {
/**
* @description
* The height of the subtree of the context tree node.
*
* The following tree has the `subTreeHeight` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 4
* ( ).
* ${-2} 2 ${7} 3
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 2
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeHeight: number;
/**
* @description
* The number of nodes of the subtree of the context node.
*
* The following tree has the `subTreeLength` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 9
* ( ).
* ${-2} 3 ${7} 5
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 3
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeLength: number;
/**
* @description
* The tree node metadata of the parent tree node of the context node.
*/
readonly parent: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling of the context. For horizontal
* tree you can treat it as bottom sibling.
*
* The following tree has the `leftSibling` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} -2
* ( ). ( ).
* ${-3} null ${-1} -3 ${6} null ${10} 6
* . . . ( ).
* ${8} null ${11} 8
* `
* ```
*/
readonly leftSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the right sibling of the context. For
* horizontal tree you can treat it as top sibling.
*
* The following tree has the `rightSibling` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} 7 ${7} null
* ( ). ( ).
* ${-3} -1 ${-1} null ${6} 10 ${10} null
* . . . ( ).
* ${8} 11 ${11} null
* `
* ```
*/
readonly rightSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling group of the context. For
* horizontal tree you can treat it as bot sibling group.
*
* The following tree has the `leftSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} null ${-1} null ${6} [-3,-1] ${10} [-3,-1]
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly leftSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the right sibling group of the context. For
* horizontal tree you can treat it as top sibling group.
*
* The following tree has the `rightSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} [6,10] ${-1} [6,10] ${6} null ${10} null
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly rightSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the sibling group of the context.
*
* The following tree has the `currentSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} [1]
* ( ).
* ${-2} [-2,7] ${7} [-2,7]
* ( ). ( ).
* ${-3} [-3,-1] ${-1} [-3,-1] ${6} [6,10] ${10} [6,10]
* . . . ( ).
* ${8} [8,11] ${11} [8,11]
* `
* ```
*/
readonly currentSiblingGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* The tree node metadata of the children group of the context.
*
* The following tree has the `childrenGroup` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} [-2,7]
* ( ).
* ${-2} [-3,-1] ${7} [6,10]
* ( ). ( ).
* ${-3} [] ${-1} [] ${6} [] ${10} [8,11]
* . . . ( ).
* ${8} [] ${11} []
* `
* ```
*/
readonly childrenGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* Tree node metadata in level order.
*/
readonly all: IExtendedTreeNodeMetadata[];
};
export declare type IStringToTree<placeholder, tree> = (strings: TemplateStringsArray, ...placeholders: placeholder[]) => tree;
/**
* @description
* Returns a function that converts tree data structures to horizontal tree
* string representations, in accordance to the instructions you have provided
* to the factory.
*/
export declare const treeToStringHorizontalFactory: ITreeToStringHorizontalFactory;
export declare type ITreeToStringHorizontalFactory = <treeNodeOrTreeRootNode, tree>(strategy: {
/**
* @description
* A function that given a node from the tree, returns its immediate
* children.
*/
getChildren: IGetChildren<treeNodeOrTreeRootNode>;
/**
* @description
* A function that given the tree returns its root node.
*/
getRoot: IGetRoot<tree, treeNodeOrTreeRootNode>;
/**
* @description
* Function that converts a tree node to string.
*/
nodeToString: (parameters: { treeNodeMetadata: ITreeNodeMetadataTreeToString<treeNodeOrTreeRootNode> }) => string;
}) => ITreeToString<tree>;
export declare type IGetChildren<treeNodeOrTreeRootNode> = (parameters: {
/**
* @description
* The tree node from which you want to get the children.
*/
treeNode: treeNodeOrTreeRootNode;
}) => treeNodeOrTreeRootNode[];
export declare type IGetRoot<tree, treeNode> = (parameters: {
/**
* @description
* The tree from which you want to get the root.
*/
tree: tree;
}) => treeNode;
export interface ITreeNodeMetadataTreeToString<treeNode> extends ITreeNodeMetadataBase<ITreeNodeMetadataTreeToString<treeNode>> {
/**
* @description
* The user defined string representation of the context tree node.
*/
treeNodeStringRepresentation?: string;
/**
* @description
* The tree node that corresponds to the context metadata.
*/
readonly treeNode: treeNode;
}
export declare type ITreeNodeMetadataBase<IExtendedTreeNodeMetadata> = {
/**
* @description
* The height of the subtree of the context tree node.
*
* The following tree has the `subTreeHeight` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 4
* ( ).
* ${-2} 2 ${7} 3
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 2
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeHeight: number;
/**
* @description
* The number of nodes of the subtree of the context node.
*
* The following tree has the `subTreeLength` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} 9
* ( ).
* ${-2} 3 ${7} 5
* ( ). ( ).
* ${-3} 1 ${-1} 1 ${6} 1 ${10} 3
* . . . ( ).
* ${8} 1 ${11} 1
* `
* ```
*/
readonly subTreeLength: number;
/**
* @description
* The tree node metadata of the parent tree node of the context node.
*/
readonly parent: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling of the context. For horizontal
* tree you can treat it as bottom sibling.
*
* The following tree has the `leftSibling` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} -2
* ( ). ( ).
* ${-3} null ${-1} -3 ${6} null ${10} 6
* . . . ( ).
* ${8} null ${11} 8
* `
* ```
*/
readonly leftSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the right sibling of the context. For
* horizontal tree you can treat it as top sibling.
*
* The following tree has the `rightSibling` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} 7 ${7} null
* ( ). ( ).
* ${-3} -1 ${-1} null ${6} 10 ${10} null
* . . . ( ).
* ${8} 11 ${11} null
* `
* ```
*/
readonly rightSibling: IExtendedTreeNodeMetadata | null;
/**
* @description
* The tree node metadata of the left sibling group of the context. For
* horizontal tree you can treat it as bot sibling group.
*
* The following tree has the `leftSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} null ${-1} null ${6} [-3,-1] ${10} [-3,-1]
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly leftSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the right sibling group of the context. For
* horizontal tree you can treat it as top sibling group.
*
* The following tree has the `rightSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} null
* ( ).
* ${-2} null ${7} null
* ( ). ( ).
* ${-3} [6,10] ${-1} [6,10] ${6} null ${10} null
* . . . ( ).
* ${8} null ${11} null
* `
* ```
*/
readonly rightSiblingGroup: IExtendedTreeNodeMetadata[] | null;
/**
* @description
* The tree node metadata of the sibling group of the context.
*
* The following tree has the `currentSiblingGroup` values next to their
* corresponding placeholders:
* ```ts
* `
* ${1} [1]
* ( ).
* ${-2} [-2,7] ${7} [-2,7]
* ( ). ( ).
* ${-3} [-3,-1] ${-1} [-3,-1] ${6} [6,10] ${10} [6,10]
* . . . ( ).
* ${8} [8,11] ${11} [8,11]
* `
* ```
*/
readonly currentSiblingGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* The tree node metadata of the children group of the context.
*
* The following tree has the `childrenGroup` values next to their
* corresponding placeholders:
*
* ```ts
* `
* ${1} [-2,7]
* ( ).
* ${-2} [-3,-1] ${7} [6,10]
* ( ). ( ).
* ${-3} [] ${-1} [] ${6} [] ${10} [8,11]
* . . . ( ).
* ${8} [] ${11} []
* `
* ```
*/
readonly childrenGroup: IExtendedTreeNodeMetadata[];
/**
* @description
* Tree node metadata in level order.
*/
readonly all: IExtendedTreeNodeMetadata[];
};
declare type ITreeToString<tree> = (parameters: {
/**
* @description
* Tree to convert to string.
*/
tree: tree;
}) => string;
Motivation
I just wanted to create declarative tree tests for any kind of tree. No packages in npm could do that, so I decided to create my own.
Contributing
I am open to suggestions/pull request to improve this program.
You will find the following commands useful:
Clones the github repository of this project:
git clone https://github.com/lillallol/declarative-tree
Installs the node modules (nothing will work without them):
npm install
Tests the code and generates code coverage:
npm run test
The generated code coverage is saved in
./coverage
.Lints the source folder using typescript and eslint:
npm run lint
Builds the typescript code from the
./src
folder to javascript code in./dist
:npm run build-ts
Injects in place the generated toc and imported files to
README.md
:npm run build-md
Checks the project for spelling mistakes:
npm run spell-check
Take a look at the related configuration
./cspell.json
.Checks
./src
for dead typescript files:npm run dead-files
Take a look at the related configuration
./unimportedrc.json
.Logs which node modules can be updated:
npm run check-updates
Updates the node modules to their latest version (even if they introduce breaking changes):
npm run update
Formats all the typescript files in the
./src
folder:npm run format
Changelog
1.0.2
Bugs fixed
Placeholders groups were being over flattened. For example the following template literal:
` ${""} |_ ${"p"} |_ ${"a"} |_ ${"t"} |_ ${"h"} |_ ${["prop1", -1, "=>", 1]} `
would wrongly have as placeholders:
["","p","a","t","h",...["prop1", -1, "=>", 1]]
instead of:
["","p","a","t","h",["prop1", -1, "=>", 1]]
1.0.1
- Fixed some mistakes in the examples.
- Minor internal changes.
1.0.0
- Published the package.
License
MIT