context-traversal.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. 'use strict';
  2. var EventEmitter = require('events').EventEmitter;
  3. var inherits = require('util').inherits;
  4. var estraverse = require('estraverse');
  5. var forEach = require('core-js/library/fn/array/for-each');
  6. var reduce = require('core-js/library/fn/array/reduce');
  7. var locationOf = require('./location');
  8. var literalPattern = /^(?:String|Numeric|Null|Boolean|RegExp)?Literal$/;
  9. var assign = require('core-js/library/fn/object/assign');
  10. function ContextTraversal (powerAssertContext) {
  11. this.powerAssertContext = powerAssertContext;
  12. EventEmitter.call(this);
  13. }
  14. inherits(ContextTraversal, EventEmitter);
  15. ContextTraversal.prototype.traverse = function () {
  16. var _this = this;
  17. var source = _this.powerAssertContext.source;
  18. parseIfJson(source, 'ast');
  19. parseIfJson(source, 'tokens');
  20. parseIfJson(source, 'visitorKeys');
  21. _this.emit('start', this.powerAssertContext);
  22. forEach(this.powerAssertContext.args, function (capturedArgument) {
  23. onEachEsNode(capturedArgument, source, function (esNode) {
  24. _this.emit('data', esNode);
  25. });
  26. });
  27. _this.emit('end');
  28. };
  29. function parseIfJson (source, propName) {
  30. if (typeof source[propName] === 'string') {
  31. source[propName] = JSON.parse(source[propName]);
  32. }
  33. }
  34. function onEachEsNode(capturedArgument, source, callback) {
  35. var espathToValue = reduce(capturedArgument.events, function (accum, ev) {
  36. accum[ev.espath] = ev.value;
  37. return accum;
  38. }, {});
  39. var nodeStack = [];
  40. estraverse.traverse(source.ast, {
  41. keys: source.visitorKeys,
  42. enter: function (currentNode, parentNode) {
  43. var parentEsNode = (0 < nodeStack.length) ? nodeStack[nodeStack.length - 1] : null;
  44. var esNode = createEsNode(this.path(), currentNode, espathToValue, source.content, source.tokens, parentEsNode);
  45. nodeStack.push(esNode);
  46. callback(esNode);
  47. },
  48. leave: function (currentNode, parentNode) {
  49. nodeStack.pop();
  50. }
  51. });
  52. }
  53. function isLiteral (node) {
  54. return literalPattern.test(node.type);
  55. }
  56. function createEsNode (path, currentNode, espathToValue, jsCode, tokens, parent) {
  57. var espath = path ? path.join('/') : '';
  58. return {
  59. espath: espath,
  60. parent: parent,
  61. key: path ? path[path.length - 1] : null,
  62. node: currentNode,
  63. code: jsCode.slice(currentNode.range[0], currentNode.range[1]),
  64. value: isLiteral(currentNode) ? currentNode.value : espathToValue[espath],
  65. isCaptured: espathToValue.hasOwnProperty(espath),
  66. range: locationOf(currentNode, tokens)
  67. };
  68. }
  69. module.exports = ContextTraversal;