UNPKG

@taml/ast

Version:

Abstract Syntax Tree types and utilities for TAML (Terminal ANSI Markup Language)

235 lines 14.2 kB
/** * 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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