Files
zhibo/node_modules/unist-util-visit-parents/index.js
T
xiaoyu ac8f91d4d3 init
2023-05-22 14:23:20 +08:00

157 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @typedef {import('unist').Node} Node
* @typedef {import('unist').Parent} Parent
* @typedef {import('unist-util-is').Test} Test
* @typedef {import('./complex-types.js').Action} Action
* @typedef {import('./complex-types.js').Index} Index
* @typedef {import('./complex-types.js').ActionTuple} ActionTuple
* @typedef {import('./complex-types.js').VisitorResult} VisitorResult
* @typedef {import('./complex-types.js').Visitor} Visitor
*/
import {convert} from 'unist-util-is'
import {color} from './color.js'
/**
* Continue traversing as normal
*/
export const CONTINUE = true
/**
* Do not traverse this nodes children
*/
export const SKIP = 'skip'
/**
* Stop traversing immediately
*/
export const EXIT = false
/**
* Visit children of tree which pass test.
*
* @param tree
* Tree to walk
* @param [test]
* `unist-util-is`-compatible test
* @param visitor
* Function called for nodes that pass `test`.
* @param [reverse=false]
* Traverse in reverse preorder (NRL) instead of preorder (NLR) (default).
*/
export const visitParents =
/**
* @type {(
* (<Tree extends Node, Check extends Test>(tree: Tree, test: Check, visitor: import('./complex-types.js').BuildVisitor<Tree, Check>, reverse?: boolean) => void) &
* (<Tree extends Node>(tree: Tree, visitor: import('./complex-types.js').BuildVisitor<Tree>, reverse?: boolean) => void)
* )}
*/
(
/**
* @param {Node} tree
* @param {Test} test
* @param {import('./complex-types.js').Visitor<Node>} visitor
* @param {boolean} [reverse=false]
*/
function (tree, test, visitor, reverse) {
if (typeof test === 'function' && typeof visitor !== 'function') {
reverse = visitor
// @ts-expect-error no visitor given, so `visitor` is test.
visitor = test
test = null
}
const is = convert(test)
const step = reverse ? -1 : 1
factory(tree, null, [])()
/**
* @param {Node} node
* @param {number?} index
* @param {Array<Parent>} parents
*/
function factory(node, index, parents) {
/** @type {Record<string, unknown>} */
// @ts-expect-error: hush
const value = typeof node === 'object' && node !== null ? node : {}
/** @type {string|undefined} */
let name
if (typeof value.type === 'string') {
name =
typeof value.tagName === 'string'
? value.tagName
: typeof value.name === 'string'
? value.name
: undefined
Object.defineProperty(visit, 'name', {
value:
'node (' +
color(value.type + (name ? '<' + name + '>' : '')) +
')'
})
}
return visit
function visit() {
/** @type {ActionTuple} */
let result = []
/** @type {ActionTuple} */
let subresult
/** @type {number} */
let offset
/** @type {Array<Parent>} */
let grandparents
if (!test || is(node, index, parents[parents.length - 1] || null)) {
result = toResult(visitor(node, parents))
if (result[0] === EXIT) {
return result
}
}
// @ts-expect-error looks like a parent.
if (node.children && result[0] !== SKIP) {
// @ts-expect-error looks like a parent.
offset = (reverse ? node.children.length : -1) + step
// @ts-expect-error looks like a parent.
grandparents = parents.concat(node)
// @ts-expect-error looks like a parent.
while (offset > -1 && offset < node.children.length) {
// @ts-expect-error looks like a parent.
subresult = factory(node.children[offset], offset, grandparents)()
if (subresult[0] === EXIT) {
return subresult
}
offset =
typeof subresult[1] === 'number' ? subresult[1] : offset + step
}
}
return result
}
}
}
)
/**
* @param {VisitorResult} value
* @returns {ActionTuple}
*/
function toResult(value) {
if (Array.isArray(value)) {
return value
}
if (typeof value === 'number') {
return [CONTINUE, value]
}
return [value]
}