Package Exports
- @speclynx/apidom-traverse
Readme
@speclynx/apidom-traverse
@speclynx/apidom-traverse provides traversal utilities for ApiDOM structures.
Installation
You can install this package via npm CLI by running the following command:
$ npm install @speclynx/apidom-traverseUsage
traverse
The core traversal function that walks an ApiDOM tree using visitors.
import { ObjectElement } from '@speclynx/apidom-datamodel';
import { traverse } from '@speclynx/apidom-traverse';
const element = new ObjectElement({ a: 'b' });
traverse(element, {
enter(path) {
console.log('entering:', path.node.element);
},
leave(path) {
console.log('leaving:', path.node.element);
},
});traverseAsync
Async version of traverse that supports async visitors.
import { ObjectElement } from '@speclynx/apidom-datamodel';
import { traverseAsync } from '@speclynx/apidom-traverse';
const element = new ObjectElement({ a: 'b' });
await traverseAsync(element, {
async enter(path) {
await someAsyncOperation(path.node);
},
});Operations
Higher-level functions built on top of traverse for common use cases.
All operations use data-first signatures: the element comes before the predicate/options.
filter
Finds all paths whose elements match the predicate.
import { ObjectElement, isNumberElement } from '@speclynx/apidom-datamodel';
import { filter } from '@speclynx/apidom-traverse';
const element = new ObjectElement({ a: 'b', c: 2 });
const paths = filter(element, (path) => isNumberElement(path.node)); // => [Path<NumberElement<2>>]
paths[0].node; // => NumberElement<2>
paths[0].formatPath(); // => '/c'find
Finds first path whose element satisfies the provided predicate.
import { ObjectElement, isNumberElement } from '@speclynx/apidom-datamodel';
import { find } from '@speclynx/apidom-traverse';
const element = new ObjectElement({ a: 'b', c: 2 });
const path = find(element, (path) => isNumberElement(path.node)); // => Path<NumberElement<2>>
path.node; // => NumberElement<2>
path.formatPath(); // => '/c'findAtOffset
ApiDOM nodes can be associated with source maps. This function finds the path of the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.
import { findAtOffset } from '@speclynx/apidom-traverse';
const path = findAtOffset(elementWithSourceMaps, 3); // => Path of most inner node at offset 3
path.node; // => the element at that offset
path.formatPath(); // => JSON Pointer to the element
findAtOffset(elementWithSourceMaps, { offset: 3, includeRightBound: true });reject
Complement of filter. Finds all paths whose elements do NOT match the predicate.
import { ArrayElement, isNumberElement } from '@speclynx/apidom-datamodel';
import { reject } from '@speclynx/apidom-traverse';
const element = new ArrayElement([1, 'a']);
const paths = reject(element, (path) => isNumberElement(path.node)); // => [Path<ArrayElement>, Path<StringElement<'a'>>]
paths.map((p) => p.node); // => [ArrayElement, StringElement<'a'>]some
Tests whether at least one path's element passes the predicate.
import { ArrayElement, isNumberElement } from '@speclynx/apidom-datamodel';
import { some } from '@speclynx/apidom-traverse';
const element = new ArrayElement([1, 'a']);
some(element, (path) => isNumberElement(path.node)); // => trueforEach
Executes the callback on this element's path and all descendant paths.
import { ArrayElement } from '@speclynx/apidom-datamodel';
import { forEach } from '@speclynx/apidom-traverse';
const element = new ArrayElement([1, 'a']);
forEach(element, (path) => console.dir(path.node)); // => prints ArrayElement, NumberElement, StringElementThe execution of the callback can be controlled further by providing a predicate.
import { ArrayElement, isNumberElement } from '@speclynx/apidom-datamodel';
import { forEach } from '@speclynx/apidom-traverse';
const element = new ArrayElement([1, 'a']);
forEach(element, {
callback: (path) => console.dir(path.node),
predicate: (path) => isNumberElement(path.node),
}); // => prints NumberElement<1>parents
Computes upwards edges from every child to its parent.
ObjectElement example
import { ObjectElement } from '@speclynx/apidom-datamodel';
import { parents } from '@speclynx/apidom-traverse';
const element = new ObjectElement({ key: 'value' });
const memberElement = element.getMember('key');
const { key: keyElement, value: valueElement } = memberElement;
const parentEdges = parents(element); // => WeakMap<ChildElement, ParentElement>
parentEdges.get(memberElement) === element; // => true
parentEdges.get(keyElement) === memberElement; // => true
parentEdges.get(valueElement) === memberElement; // => trueArrayElement example
import { ArrayElement, StringElement } from '@speclynx/apidom-datamodel';
import { parents } from '@speclynx/apidom-traverse';
const itemElement1 = new StringElement('item1');
const itemElement2 = new StringElement('item2');
const element = new ArrayElement([itemElement1, itemElement2]);
const parentEdges = parents(element); // => WeakMap<ChildElement, ParentElement>
parentEdges.get(itemElement1) === element; // => true
parentEdges.get(itemElement2) === element; // => truePath
The Path object is passed to visitor functions and provides context about the current node.
Properties
node- The current element being visitedparent- The parent container (array or element)parentPath- The Path of the parent elementkey- The key or index in the parentindex- Numeric index if inside an array (undefined otherwise)inList- Whether the node is inside an array
Methods
skip()- Skip visiting children of this nodestop()- Stop all traversalreplaceWith(node)- Replace the current noderemove()- Remove the current node (in mutable mode)isRoot()- Check if this is the root nodegetAncestry()- Get all ancestor pathsgetAncestorNodes()- Get all ancestor nodesgetPathKeys()- Get the path from root to current nodefindParent(predicate)- Find first parent matching predicatefind(predicate)- Find self or parent matching predicate
Visitor Utilities
getNodeType
Returns the element type name for use in visitors.
import { StringElement } from '@speclynx/apidom-datamodel';
import { getNodeType } from '@speclynx/apidom-traverse';
getNodeType(new StringElement('hello')); // => 'StringElement'mergeVisitors
Merges multiple visitors into a single visitor.
import { mergeVisitors } from '@speclynx/apidom-traverse';
const visitor1 = { StringElement(path) { /* ... */ } };
const visitor2 = { NumberElement(path) { /* ... */ } };
const merged = mergeVisitors([visitor1, visitor2]);