index.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. var assert = require('assert')
  2. module.exports = dashAst
  3. /**
  4. * Call `cb` on each node in `ast`. If `cb` is an object, `cb.enter` is called before processing a Node's children,
  5. * and `cb.leave` is called after processing a Node's children.
  6. */
  7. function dashAst (ast, cb) {
  8. assert(ast && typeof ast === 'object' && typeof ast.type === 'string',
  9. 'dash-ast: ast must be an AST node')
  10. if (typeof cb === 'object') {
  11. assert(typeof cb.enter === 'function' || typeof cb.leave === 'function',
  12. 'dash-ast: visitor must be an object with enter/leave functions')
  13. walk(ast, null, cb.enter || undefined, cb.leave || undefined)
  14. } else {
  15. assert(cb && typeof cb === 'function',
  16. 'dash-ast: callback must be a function')
  17. walk(ast, null, cb, undefined)
  18. }
  19. }
  20. /**
  21. * Call `cb` on each node in `ast`. Each node will have a `.parent` property.
  22. */
  23. dashAst.withParent = function dashAstParent (ast, cb) {
  24. assert(ast && typeof ast === 'object' && typeof ast.type === 'string',
  25. 'dash-ast.withParent: ast must be an AST node')
  26. if (typeof cb === 'object') {
  27. assert(typeof cb.enter === 'function' || typeof cb.leave === 'function',
  28. 'dash-ast.withParent: visitor must be an object with enter/leave functions')
  29. var enter = cb.enter
  30. var leave = cb.leave
  31. walk(ast, null, function (node, parent) {
  32. node.parent = parent
  33. if (enter !== undefined) return enter(node)
  34. }, leave ? function (node) { leave(node) } : undefined)
  35. } else {
  36. assert(cb && typeof cb === 'function',
  37. 'dash-ast.withParent: callback must be a function')
  38. walk(ast, null, function (node, parent) {
  39. node.parent = parent
  40. return cb(node)
  41. }, undefined)
  42. }
  43. }
  44. function walk (node, parent, enter, leave) {
  45. var cont = enter !== undefined ? enter(node, parent) : undefined
  46. if (cont === false) return
  47. for (var k in node) {
  48. if (has(node, k)) {
  49. if (k === 'parent') continue
  50. if (isNode(node[k])) {
  51. walk(node[k], node, enter, leave)
  52. } else if (Array.isArray(node[k])) {
  53. walkArray(node[k], node, enter, leave)
  54. }
  55. }
  56. }
  57. if (leave !== undefined) leave(node, parent)
  58. }
  59. function walkArray (nodes, parent, enter, leave) {
  60. for (var i = 0; i < nodes.length; i++) {
  61. if (isNode(nodes[i])) walk(nodes[i], parent, enter, leave)
  62. }
  63. }
  64. function isNode (node) {
  65. return typeof node === 'object' && node && typeof node.type === 'string'
  66. }
  67. function has (obj, prop) {
  68. return Object.prototype.hasOwnProperty.call(obj, prop)
  69. }