@taml/ast
Version:
Abstract Syntax Tree types and utilities for TAML (Terminal ANSI Markup Language)
235 lines • 14.2 kB
JavaScript
/**
* Tree traversal utilities for TAML AST
*/
import { isDocumentNode, isElementNode, isTextNode } from "./nodes.js";
/**
* Walk through all nodes in the tree (depth-first, pre-order)
*/
export function walk(node, callback) {
callback(node);
if (isDocumentNode(node) || isElementNode(node)) {
for (const child of node.children) {
walk(child, callback);
}
}
}
/**
* Walk through all nodes asynchronously
*/
export async function walkAsync(node, callback) {
await callback(node);
if (isDocumentNode(node) || isElementNode(node)) {
for (const child of node.children) {
await walkAsync(child, callback);
}
}
}
/**
* Find all nodes that match a predicate
*/
export function findAll(root, predicate) {
const results = [];
walk(root, (node) => {
if (predicate(node)) {
results.push(node);
}
});
return results;
}
/**
* Find the first node that matches a predicate
*/
export function findFirst(root, predicate) {
let result = null;
try {
walk(root, (node) => {
if (predicate(node)) {
result = node;
throw new Error("Found"); // Break out of walk
}
});
}
catch {
// Expected when we find a match
}
return result;
}
/**
* Filter nodes by predicate (alias for findAll)
*/
export function filter(root, predicate) {
return findAll(root, predicate);
}
/**
* Get all text content from a node and its descendants
*/
export function getAllText(root) {
const textParts = [];
walk(root, (node) => {
if (isTextNode(node)) {
textParts.push(node.content);
}
});
return textParts.join("");
}
/**
* Get all element nodes with a specific tag name
*/
export function getElementsWithTag(root, tagName) {
return findAll(root, (node) => isElementNode(node) && node.tagName === tagName);
}
/**
* Get all text nodes
*/
export function getTextNodes(root) {
return findAll(root, isTextNode);
}
/**
* Get all element nodes
*/
export function getElementNodes(root) {
return findAll(root, isElementNode);
}
/**
* Check if a node contains another node
*/
export function contains(ancestor, descendant) {
if (ancestor === descendant) {
return true;
}
if (isDocumentNode(ancestor) || isElementNode(ancestor)) {
for (const child of ancestor.children) {
if (contains(child, descendant)) {
return true;
}
}
}
return false;
}
/**
* Get the common ancestor of two nodes
*/
export function getCommonAncestor(node1, node2) {
// Get all ancestors of node1
const ancestors1 = new Set();
let current = node1;
while (current) {
ancestors1.add(current);
current = current.parent;
}
// Find first common ancestor in node2's ancestry
current = node2;
while (current) {
if (ancestors1.has(current)) {
return current;
}
current = current.parent;
}
return null;
}
/**
* Get siblings of a node (nodes with the same parent)
*/
export function getSiblings(node) {
if (!node.parent ||
(!isDocumentNode(node.parent) && !isElementNode(node.parent))) {
return [];
}
return node.parent.children.filter((child) => child !== node);
}
/**
* Get the previous sibling of a node
*/
export function getPreviousSibling(node) {
if (!node.parent ||
(!isDocumentNode(node.parent) && !isElementNode(node.parent))) {
return null;
}
const index = node.parent.children.indexOf(node);
return index > 0 ? (node.parent.children[index - 1] ?? null) : null;
}
/**
* Get the next sibling of a node
*/
export function getNextSibling(node) {
if (!node.parent ||
(!isDocumentNode(node.parent) && !isElementNode(node.parent))) {
return null;
}
const index = node.parent.children.indexOf(node);
return index < node.parent.children.length - 1
? (node.parent.children[index + 1] ?? null)
: null;
}
/**
* Check if a node is empty (has no children or only empty text)
*/
export function isEmpty(node) {
if (isTextNode(node)) {
return node.content.trim() === "";
}
if (isDocumentNode(node) || isElementNode(node)) {
return (node.children.length === 0 ||
node.children.every((child) => isEmpty(child)));
}
return false;
}
/**
* Count nodes by type
*/
export function countNodes(root) {
const counts = { document: 0, element: 0, text: 0 };
walk(root, (node) => {
if (isDocumentNode(node)) {
counts.document++;
}
else if (isElementNode(node)) {
counts.element++;
}
else if (isTextNode(node)) {
counts.text++;
}
});
return counts;
}
/**
* Get the maximum depth of the tree
*/
export function getMaxDepth(root) {
let maxDepth = 0;
function traverse(node, depth) {
maxDepth = Math.max(maxDepth, depth);
if (isDocumentNode(node) || isElementNode(node)) {
for (const child of node.children) {
traverse(child, depth + 1);
}
}
}
traverse(root, 0);
return maxDepth;
}
/**
* Flatten the tree into an array of nodes (depth-first order)
*/
export function flatten(root) {
const nodes = [];
walk(root, (node) => nodes.push(node));
return nodes;
}
/**
* Create a map from node to its depth in the tree
*/
export function createDepthMap(root) {
const depthMap = new Map();
function traverse(node, depth) {
depthMap.set(node, depth);
if (isDocumentNode(node) || isElementNode(node)) {
for (const child of node.children) {
traverse(child, depth + 1);
}
}
}
traverse(root, 0);
return depthMap;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhdmVyc2FsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdHJhdmVyc2FsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBR0gsT0FBTyxFQUFFLGNBQWMsRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBR3ZFOztHQUVHO0FBQ0gsTUFBTSxVQUFVLElBQUksQ0FBQyxJQUFjLEVBQUUsUUFBa0M7SUFDckUsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWYsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDaEQsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztRQUN4QixDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsU0FBUyxDQUM3QixJQUFjLEVBQ2QsUUFBMkM7SUFFM0MsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFckIsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDaEQsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEMsTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FDckIsSUFBYyxFQUNkLFNBQXNDO0lBRXRDLE1BQU0sT0FBTyxHQUFlLEVBQUUsQ0FBQztJQUUvQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUU7UUFDbEIsSUFBSSxTQUFTLENBQUMsSUFBSSxD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