UNPKG

unist-utils-core

Version:

A collection of commonly used (albeit enhanced) algorithms based on unist and unist-util-xxx

98 lines 3.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.visit = exports.vistorResultToTuple = exports.visitorResultToTuple = exports.PostTraversalIndex = exports.PreTraversalIndex = exports.EXIT = exports.SKIP = exports.CONTINUE = void 0; const test_1 = require("./test"); /** * Continue traversing as normal. */ exports.CONTINUE = true; /** * Do not traverse this node’s children */ exports.SKIP = 'skip'; /** * Stop traversing immediately */ exports.EXIT = false; exports.PreTraversalIndex = Number.MIN_SAFE_INTEGER; exports.PostTraversalIndex = Number.MAX_SAFE_INTEGER; function visitorResultToTuple(value) { if (value !== null && typeof value === 'object' && 'length' in value) return value; if (typeof value === 'number') return [exports.CONTINUE, value]; return [value]; } exports.visitorResultToTuple = visitorResultToTuple; // Backwards compatible fix of spelling error. exports.vistorResultToTuple = visitorResultToTuple; /** * Visit nodes (inclusive descendants of tree), with ancestral information. Optionally filtering nodes. Optionally in reverse, Optionally wrapping child visitation with pre/post visits. * This algorithm performs depth-first tree traversal in preorder (NLR), or if reverse is given, in reverse preorder (NRL). * * @param tree Tree to traverse (this may be a Node, or an array of Nodes). * @param tst (optional) 'is-compatible' test (such as a type). * @param visitor Function invoked when a node is found that passes test @see Visitor * @param options Options for controlling the visit @see VisitOptions. If you pass a boolean, it is used for {VisitOptions.reverse}. default is false */ function visit(tree, tst, visitor, options) { if (typeof tst === 'function' && typeof visitor !== 'function') { options = visitor; visitor = tst; tst = null; } let opts; if (typeof options === 'boolean') opts = { reverse: options }; else if (!options) opts = {}; else opts = options; let is = (0, test_1.test)(tst); // Visit a single node. function one(node, index, parents) { let result = []; let subResult; if (!tst || is(node, index, parents[parents.length - 1] || null)) { let aResult = visitor(node, index, parents, opts.context); result = visitorResultToTuple(aResult); if (result[0] === exports.EXIT) return result; } if (result[0] !== exports.SKIP) { let c = node.children; if (c) { let aSubResult = all(c, parents.concat(node)); subResult = visitorResultToTuple(aSubResult); return subResult[0] === exports.EXIT ? subResult : result; } } return result; } // Visit children in `parent`. function all(children, parents) { let min = -1; let step = opts.reverse ? -1 : 1; let index = (opts.reverse ? children.length : min) + step; let result; if (opts.preTraverse) visitor(undefined, exports.PreTraversalIndex, parents, opts.context); while (index > min && index < children.length) { result = one(children[index], index, parents); if (result[0] === exports.EXIT) break; index = typeof result[1] === 'number' ? result[1] : index + step; } if (opts.postTraverse) visitor(undefined, exports.PostTraversalIndex, parents, opts.context); if (result) return result; } // Begin if (Array.isArray(tree)) return all(tree, []); else return one(tree, null, []); } exports.visit = visit; //# sourceMappingURL=visit.js.map