index.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. 'use strict'
  2. module.exports = visitParents
  3. var convert = require('unist-util-is/convert')
  4. var CONTINUE = true
  5. var SKIP = 'skip'
  6. var EXIT = false
  7. visitParents.CONTINUE = CONTINUE
  8. visitParents.SKIP = SKIP
  9. visitParents.EXIT = EXIT
  10. function visitParents(tree, test, visitor, reverse) {
  11. var is
  12. if (typeof test === 'function' && typeof visitor !== 'function') {
  13. reverse = visitor
  14. visitor = test
  15. test = null
  16. }
  17. is = convert(test)
  18. one(tree, null, [])
  19. // Visit a single node.
  20. function one(node, index, parents) {
  21. var result = []
  22. var subresult
  23. if (!test || is(node, index, parents[parents.length - 1] || null)) {
  24. result = toResult(visitor(node, parents))
  25. if (result[0] === EXIT) {
  26. return result
  27. }
  28. }
  29. if (node.children && result[0] !== SKIP) {
  30. subresult = toResult(all(node.children, parents.concat(node)))
  31. return subresult[0] === EXIT ? subresult : result
  32. }
  33. return result
  34. }
  35. // Visit children in `parent`.
  36. function all(children, parents) {
  37. var min = -1
  38. var step = reverse ? -1 : 1
  39. var index = (reverse ? children.length : min) + step
  40. var result
  41. while (index > min && index < children.length) {
  42. result = one(children[index], index, parents)
  43. if (result[0] === EXIT) {
  44. return result
  45. }
  46. index = typeof result[1] === 'number' ? result[1] : index + step
  47. }
  48. }
  49. }
  50. function toResult(value) {
  51. if (value !== null && typeof value === 'object' && 'length' in value) {
  52. return value
  53. }
  54. if (typeof value === 'number') {
  55. return [CONTINUE, value]
  56. }
  57. return [value]
  58. }