@suchipi/traverse v5.1.1
@suchipi/traverse
Basic traverse function for deeply iterating over objects/arrays/etc.
Features
- Only searches through an object's own properties
- Can handle mutation/deletion during traversal
- Provides your visitor callback a path to the current value (in addition to the value itself)
- Avoids traversing over already-traversed values, to avoid cycles
Usage
import { traverse } from "@suchipi/traverse";
// It can traverse any JSON-compatible structure.
const tree = {
type: "Root",
left: {
type: "Left",
children: [1, 2, 3],
},
right: {
type: "Right",
children: [4, 5, 6],
},
};
traverse(tree, {
// If you provide an `after` callback, it will be called on the way *up*
// the traversal stack; this is equivalent to a depth-first search.
after: (value, path) => {
console.log(`At '.${path.join(".")}':`, value);
},
});
// Output:
//
// At '.type': 'Root'
// At '.left.type': 'Left'
// At '.left.children.0': 1
// At '.left.children.1': 2
// At '.left.children.2': 3
// At '.left.children': [ 1, 2, 3 ]
// At '.left': { type: 'Left', children: [ 1, 2, 3 ] }
// At '.right.type': 'Right'
// At '.right.children.0': 4
// At '.right.children.1': 5
// At '.right.children.2': 6
// At '.right.children': [ 4, 5, 6 ]
// At '.right': { type: 'Right', children: [ 4, 5, 6 ] }
// At '.': {
// type: 'Root',
// left: { type: 'Left', children: [ 1, 2, 3 ] },
// right: { type: 'Right', children: [ 4, 5, 6 ] }
// }
traverse(tree, {
// If you provide a `before` callback, it will be called on the way *down*
// the traversal stack; this is equivalent to a breadth-first search.
before: (value, path) => {
console.log(`At '.${path.join(".")}':`, value);
},
});
// Output:
//
// At '.': {
// type: 'Root',
// left: { type: 'Left', children: [ 1, 2, 3 ] },
// right: { type: 'Right', children: [ 4, 5, 6 ] }
// }
// At '.type': Root
// At '.left': { type: 'Left', children: [ 1, 2, 3 ] }
// At '.left.type': Left
// At '.left.children': [ 1, 2, 3 ]
// At '.left.children.0': 1
// At '.left.children.1': 2
// At '.left.children.2': 3
// At '.right': { type: 'Right', children: [ 4, 5, 6 ] }
// At '.right.type': Right
// At '.right.children': [ 4, 5, 6 ]
// At '.right.children.0': 4
// At '.right.children.1': 5
// At '.right.children.2': 6API
This module has two named exports:
- A function named
traverse - A Symbol named
stop
traverse
The traverse function has the following type signature:
function traverse(
tree: any,
callbacks?: {
before?: (value: any, path: Array<string | number>) => void | typeof stop;
after?: (value: any, path: Array<string | number>) => void;
},
): void;Pass in any JSON-compatible value (the tree parameter) and callback function(s) (the callbacks parameter). Your tree will be searched through, and callbacks.before and callbacks.after will be called for each descendant in the tree.
When callbacks.before or callbacks.after gets called, it will be called with two arguments:
- The value of the current descendant (could be an object, an array, a string, a number, etc)
- The property path from the initially-passed
treeobject to this descendant (an array of strings or numbers)
stop
You can return stop from a before callback passed into traverse to stop traversing downwards beyond the current object's children.
Tips
The
pathArray your callback receives is suitable for use in lodash'ssetandgetfunctions. As such, you can use lodash'ssetfunction to mutate a tree while you traverse over it.If you want to create a new tree instead of mutating the existing one, you can combine lodash's
setfunction with immer.
Troubleshooting
If you're expecting an object property to be visited by
traverse, but it isn't, make sure the property is an "own," "enumerable" property. For instance, class methods found on an instance of a class are not "own" properties, sotraversewon't visit them. See MDN's article on 'Enumerability and ownership of properties' for more info.The contents of
MapandSetobjects won't be visited bytraverse, because it's only designed with JSON-compatible values in mind. However, theMap/Setitself will be visited. As such, if you want to inspect the contents of aMap/Set, you can do so from within your callback. Alternatively, you can convertMaps/Sets in your tree into Objects or Arrays prior to passing your tree intotraverse.
License
MIT