'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 }