UNPKG

2.58 kBJavaScriptView Raw
1'use strict';
2
3var estraverse = require('estraverse');
4var esprima = require('esprima');
5var EventEmitter = require('events').EventEmitter;
6var inherits = require('util').inherits;
7var EsNode = require('./esnode');
8var forEach = require('array-foreach');
9var reduce = require('array-reduce');
10
11function ContextTraversal (context) {
12 this.context = context;
13 EventEmitter.call(this);
14}
15inherits(ContextTraversal, EventEmitter);
16
17ContextTraversal.prototype.traverse = function () {
18 var _this = this;
19 forEach(this.context.args, function (arg) {
20 onEachEsNode(arg, _this.context.source.content, function (esNode) {
21 _this.emit('esnode', esNode);
22 });
23 });
24};
25
26function onEachEsNode(arg, jsCode, callback) {
27 var parseResult = parse(jsCode);
28 var tokens = parseResult.tokens;
29 var espathToValue = reduce(arg.events, function (accum, ev) {
30 accum[ev.espath] = ev.value;
31 return accum;
32 }, {});
33 var nodeStack = [];
34 estraverse.traverse(parseResult.expression, {
35 enter: function (currentNode, parentNode) {
36 var esNode = new EsNode(this.path(), currentNode, parentNode, espathToValue, jsCode, tokens);
37 if (1 < nodeStack.length) {
38 esNode.setParent(nodeStack[nodeStack.length - 1]);
39 }
40 nodeStack.push(esNode);
41 callback(esNode);
42 },
43 leave: function (currentNode, parentNode) {
44 nodeStack.pop();
45 }
46 });
47}
48
49function parserOptions() {
50 return {sourceType: 'module', tolerant: true, loc: true, tokens: true, raw: true};
51}
52
53function wrappedInGenerator(jsCode) {
54 return 'function *wrapper() {\n' + jsCode + '\n}';
55}
56
57function parse(jsCode) {
58 var ast;
59 var top;
60 try {
61 // Try parsing the raw line of code, without wrapping.
62 top = ast = esprima.parse(jsCode, parserOptions());
63 } catch (e) {
64 // Esprima will throw an error if YieldExpressions are not inside a generator function.
65 // Since we only have a single line of code to work with; wrap it with a dummy generator function;
66 // then unwrap the original code from the resulting AST.
67 ast = esprima.parse(wrappedInGenerator(jsCode), parserOptions());
68 top = ast.body[0].body;
69 }
70 return {
71 tokens: ast.tokens,
72 expression: extractExpressionFrom(top)
73 };
74}
75
76function extractExpressionFrom (tree) {
77 var expressionStatement = tree.body[0];
78 var expression = expressionStatement.expression;
79 return expression;
80}
81
82module.exports = ContextTraversal;