Efficient tree and linked list data structure using ES6 Symbols for DOM tree backing
—
Insert, append, and remove objects with constant-time operations.
Insert an object as the last child of a parent.
/**
* Insert object as the last child of the reference object
* Time Complexity: O(1)
* @param {Object} referenceObject - Parent object
* @param {Object} newObject - Object to insert as last child
* @returns {Object} The inserted newObject
* @throws {Error} If newObject is already present in this SymbolTree
*/
appendChild(referenceObject: Object, newObject: Object): Object;Insert an object as the first child of a parent.
/**
* Insert object as the first child of the reference object
* Time Complexity: O(1)
* @param {Object} referenceObject - Parent object
* @param {Object} newObject - Object to insert as first child
* @returns {Object} The inserted newObject
* @throws {Error} If newObject is already present in this SymbolTree
*/
prependChild(referenceObject: Object, newObject: Object): Object;Insert an object before a reference object (as a sibling).
/**
* Insert object before the reference object as a sibling
* Time Complexity: O(1)
* @param {Object} referenceObject - Reference object
* @param {Object} newObject - Object to insert before reference
* @returns {Object} The inserted newObject
* @throws {Error} If newObject is already present in this SymbolTree
*/
insertBefore(referenceObject: Object, newObject: Object): Object;Insert an object after a reference object (as a sibling).
/**
* Insert object after the reference object as a sibling
* Time Complexity: O(1)
* @param {Object} referenceObject - Reference object
* @param {Object} newObject - Object to insert after reference
* @returns {Object} The inserted newObject
* @throws {Error} If newObject is already present in this SymbolTree
*/
insertAfter(referenceObject: Object, newObject: Object): Object;Remove an object from the tree.
/**
* Remove object from the tree
* Time Complexity: O(1)
* @param {Object} removeObject - Object to remove
* @returns {Object} The removed object (same as removeObject)
*/
remove(removeObject: Object): Object;const SymbolTree = require("symbol-tree");
const tree = new SymbolTree();
// Create DOM-like structure
const html = { tag: "html" };
const head = { tag: "head" };
const body = { tag: "body" };
const title = { tag: "title", text: "My Page" };
const h1 = { tag: "h1", text: "Welcome" };
const p = { tag: "p", text: "Hello world" };
// Build the tree structure
tree.appendChild(html, head);
tree.appendChild(html, body);
tree.appendChild(head, title);
tree.appendChild(body, h1);
tree.appendChild(body, p);
console.log(tree.firstChild(html) === head); // true
console.log(tree.lastChild(body) === p); // trueconst tree = new SymbolTree();
const parent = { name: "parent" };
const child1 = { name: "child1" };
const child2 = { name: "child2" };
const child3 = { name: "child3" };
// Add children in order
tree.appendChild(parent, child2);
tree.prependChild(parent, child1); // child1 is now first
tree.insertAfter(child2, child3); // child3 comes after child2
// Final order: child1 -> child2 -> child3
let current = tree.firstChild(parent);
while (current) {
console.log(current.name);
current = tree.nextSibling(current);
}
// Output: child1, child2, child3
// Rearrange - move child3 to the beginning
tree.remove(child3);
tree.prependChild(parent, child3);
// New order: child3 -> child1 -> child2const tree = new SymbolTree();
// Create nodes
const nodes = [
{ id: 1, value: "first" },
{ id: 2, value: "second" },
{ id: 3, value: "third" },
{ id: 4, value: "fourth" }
];
// Build linked list using insertAfter
let current = nodes[0];
for (let i = 1; i < nodes.length; i++) {
tree.insertAfter(current, nodes[i]);
current = nodes[i];
}
// Or build using insertBefore
const moreNodes = [
{ id: 5, value: "fifth" },
{ id: 6, value: "sixth" }
];
tree.insertBefore(nodes[0], moreNodes[1]); // sixth -> first -> ...
tree.insertBefore(moreNodes[1], moreNodes[0]); // fifth -> sixth -> first -> ...const tree = new SymbolTree();
function createNode(name, children = []) {
const node = { name };
for (const childName of children) {
const child = createNode(childName);
tree.appendChild(node, child);
}
return node;
}
// Create initial tree
const root = createNode("root", ["branch1", "branch2"]);
// Add more nodes dynamically
const newBranch = createNode("branch3", ["leaf1", "leaf2"]);
tree.appendChild(root, newBranch);
// Insert between existing branches
const middleBranch = createNode("branch1.5");
const branch2 = tree.lastChild(tree.firstChild(root)); // Navigate to branch2
tree.insertBefore(branch2, middleBranch);
// Remove and reorganize
const branch1 = tree.firstChild(root);
tree.remove(branch1);
tree.prependChild(newBranch, branch1); // Move branch1 under branch3All insertion methods will throw an Error if the object being inserted is already present in the tree:
const tree = new SymbolTree();
const parent = { name: "parent" };
const child = { name: "child" };
tree.appendChild(parent, child);
try {
// This will throw an error
tree.appendChild(parent, child);
} catch (error) {
console.log(error.message);
// "Given object is already present in this SymbolTree, remove it first"
}
// To move an object, remove it first
tree.remove(child);
tree.prependChild(parent, child); // Now this worksInstall with Tessl CLI
npx tessl i tessl/npm-symbol-tree