index.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. 'use strict'
  2. module.exports = visitParents
  3. var convert = require('unist-util-is/convert')
  4. var color = require('./color')
  5. var CONTINUE = true
  6. var SKIP = 'skip'
  7. var EXIT = false
  8. visitParents.CONTINUE = CONTINUE
  9. visitParents.SKIP = SKIP
  10. visitParents.EXIT = EXIT
  11. function visitParents(tree, test, visitor, reverse) {
  12. var step
  13. var is
  14. if (typeof test === 'function' && typeof visitor !== 'function') {
  15. reverse = visitor
  16. visitor = test
  17. test = null
  18. }
  19. is = convert(test)
  20. step = reverse ? -1 : 1
  21. factory(tree, null, [])()
  22. function factory(node, index, parents) {
  23. var value = typeof node === 'object' && node !== null ? node : {}
  24. var name
  25. if (typeof value.type === 'string') {
  26. name =
  27. typeof value.tagName === 'string'
  28. ? value.tagName
  29. : typeof value.name === 'string'
  30. ? value.name
  31. : undefined
  32. visit.displayName =
  33. 'node (' + color(value.type + (name ? '<' + name + '>' : '')) + ')'
  34. }
  35. return visit
  36. function visit() {
  37. var grandparents = parents.concat(node)
  38. var result = []
  39. var subresult
  40. var offset
  41. if (!test || is(node, index, parents[parents.length - 1] || null)) {
  42. result = toResult(visitor(node, parents))
  43. if (result[0] === EXIT) {
  44. return result
  45. }
  46. }
  47. if (node.children && result[0] !== SKIP) {
  48. offset = (reverse ? node.children.length : -1) + step
  49. while (offset > -1 && offset < node.children.length) {
  50. subresult = factory(node.children[offset], offset, grandparents)()
  51. if (subresult[0] === EXIT) {
  52. return subresult
  53. }
  54. offset =
  55. typeof subresult[1] === 'number' ? subresult[1] : offset + step
  56. }
  57. }
  58. return result
  59. }
  60. }
  61. }
  62. function toResult(value) {
  63. if (value !== null && typeof value === 'object' && 'length' in value) {
  64. return value
  65. }
  66. if (typeof value === 'number') {
  67. return [CONTINUE, value]
  68. }
  69. return [value]
  70. }