Version: 2.0.6 Status: Stable & Production Ready Last Updated: 2025-11-16
The Navigation API provides iteration and tree traversal capabilities for TONL documents.
Iterate over [key, value] pairs at the root level.
for (const [key, value] of doc.entries()) {
console.log(`${key}: ${JSON.stringify(value)}`);
}Iterate over keys at the root level.
for (const key of doc.keys()) {
console.log(key);
}Iterate over values at the root level.
for (const value of doc.values()) {
console.log(value);
}Recursively iterate over all [path, value] pairs.
for (const [path, value] of doc.deepEntries()) {
console.log(`${path}: ${value}`);
}
// Output:
// user: { name: 'Alice', age: 30 }
// user.name: Alice
// user.age: 30
// users: [...]
// users[0]: { id: 1, name: 'Bob' }
// users[0].id: 1
// users[0].name: BobRecursively iterate over all paths.
const allPaths = Array.from(doc.deepKeys());
// ['user', 'user.name', 'user.age', 'users', 'users[0]', ...]Recursively iterate over all values.
for (const value of doc.deepValues()) {
if (typeof value === 'string') {
console.log(value);
}
}Walk the tree with a callback function.
doc.walk((path, value, depth) => {
console.log(`[Depth ${depth}] ${path}: ${value}`);
});Callback Signature:
type WalkCallback = (
path: string,
value: any,
depth: number
) => void | boolean;Return false to stop traversal early.
Options:
interface WalkOptions {
maxDepth?: number; // Default: 100
filter?: (value: any) => boolean;
strategy?: 'depth-first' | 'breadth-first';
order?: 'pre-order' | 'post-order';
includeRoot?: boolean;
}Examples:
// Depth-first (default)
doc.walk((path, value) => {
console.log(path);
}, { strategy: 'depth-first' });
// Breadth-first
doc.walk((path, value) => {
console.log(path);
}, { strategy: 'breadth-first' });
// With filter
doc.walk((path, value) => {
console.log(path, value);
}, {
filter: (v) => typeof v === 'number'
});
// Early termination
doc.walk((path, value) => {
if (value === 'STOP') {
return false; // Stop walking
}
});
// Post-order traversal
doc.walk((path, value, depth) => {
console.log(`Visited ${path} after children`);
}, { order: 'post-order' });Find the first value matching a predicate.
const user = doc.find((value, path) => {
return value.email === 'alice@example.com';
});Find all values matching a predicate.
const numbers = doc.findAll((value) => {
return typeof value === 'number';
});Check if any value matches a predicate.
const hasAdmins = doc.some((value) => {
return value.role === 'admin';
});Check if all values match a predicate.
const allActive = doc.every((value, path) => {
return path.includes('active') ? value === true : true;
});Count total nodes in the document.
const nodeCount = doc.countNodes(); // e.g., 156const emails = doc.findAll((value) => {
return typeof value === 'string' && value.includes('@');
});const ids: number[] = [];
doc.walk((path, value) => {
if (path.endsWith('.id') && typeof value === 'number') {
ids.push(value);
}
});const pathMap = new Map();
for (const [path, value] of doc.deepEntries()) {
pathMap.set(path, value);
}const typeCounts = { strings: 0, numbers: 0, booleans: 0 };
doc.walk((_, value) => {
const type = typeof value;
if (type === 'string') typeCounts.strings++;
if (type === 'number') typeCounts.numbers++;
if (type === 'boolean') typeCounts.booleans++;
});- Iterators: Lazy evaluation, memory efficient
- Deep iteration: O(n) where n = total nodes
- Walk: O(n) with early termination support
- Search utilities: O(n), stops on first match for find()