111 lines
2.1 KiB
JavaScript
111 lines
2.1 KiB
JavaScript
'use strict'
|
|
|
|
module.exports = visitParents
|
|
|
|
var convert = require('unist-util-is/convert')
|
|
var color = require('./color')
|
|
|
|
var CONTINUE = true
|
|
var SKIP = 'skip'
|
|
var EXIT = false
|
|
|
|
visitParents.CONTINUE = CONTINUE
|
|
visitParents.SKIP = SKIP
|
|
visitParents.EXIT = EXIT
|
|
|
|
function visitParents(tree, test, visitor, reverse) {
|
|
var is
|
|
|
|
if (func(test) && !func(visitor)) {
|
|
reverse = visitor
|
|
visitor = test
|
|
test = null
|
|
}
|
|
|
|
is = convert(test)
|
|
|
|
one(tree, null, [])()
|
|
|
|
function one(child, index, parents) {
|
|
var value = object(child) ? child : {}
|
|
var name
|
|
|
|
if (string(value.type)) {
|
|
name = string(value.tagName)
|
|
? value.tagName
|
|
: string(value.name)
|
|
? value.name
|
|
: undefined
|
|
|
|
node.displayName =
|
|
'node (' + color(value.type + (name ? '<' + name + '>' : '')) + ')'
|
|
}
|
|
|
|
return node
|
|
|
|
function node() {
|
|
var result = []
|
|
var subresult
|
|
|
|
if (!test || is(child, index, parents[parents.length - 1] || null)) {
|
|
result = toResult(visitor(child, parents))
|
|
|
|
if (result[0] === EXIT) {
|
|
return result
|
|
}
|
|
}
|
|
|
|
if (!child.children || result[0] === SKIP) {
|
|
return result
|
|
}
|
|
|
|
subresult = toResult(children(child.children, parents.concat(child)))
|
|
return subresult[0] === EXIT ? subresult : result
|
|
}
|
|
}
|
|
|
|
// Visit children in `parent`.
|
|
function children(children, parents) {
|
|
var min = -1
|
|
var step = reverse ? -1 : 1
|
|
var index = (reverse ? children.length : min) + step
|
|
var child
|
|
var result
|
|
|
|
while (index > min && index < children.length) {
|
|
child = children[index]
|
|
result = one(child, index, parents)()
|
|
|
|
if (result[0] === EXIT) {
|
|
return result
|
|
}
|
|
|
|
index = typeof result[1] === 'number' ? result[1] : index + step
|
|
}
|
|
}
|
|
}
|
|
|
|
function toResult(value) {
|
|
if (object(value) && 'length' in value) {
|
|
return value
|
|
}
|
|
|
|
if (typeof value === 'number') {
|
|
return [CONTINUE, value]
|
|
}
|
|
|
|
return [value]
|
|
}
|
|
|
|
function func(d) {
|
|
return typeof d === 'function'
|
|
}
|
|
|
|
function string(d) {
|
|
return typeof d === 'string'
|
|
}
|
|
|
|
function object(d) {
|
|
return typeof d === 'object' && d !== null
|
|
}
|