1 | 'use strict';
|
2 |
|
3 | var estraverse = require('estraverse');
|
4 | var parser = require('acorn');
|
5 | require('acorn-es7-plugin')(parser);
|
6 | var EventEmitter = require('events').EventEmitter;
|
7 | var inherits = require('util').inherits;
|
8 | var EsNode = require('./esnode');
|
9 | var forEach = require('array-foreach');
|
10 | var reduce = require('array-reduce');
|
11 |
|
12 | function ContextTraversal (context) {
|
13 | this.context = context;
|
14 | EventEmitter.call(this);
|
15 | }
|
16 | inherits(ContextTraversal, EventEmitter);
|
17 |
|
18 | ContextTraversal.prototype.traverse = function () {
|
19 | var _this = this;
|
20 | forEach(this.context.args, function (arg) {
|
21 | onEachEsNode(arg, _this.context.source, function (esNode) {
|
22 | _this.emit('esnode', esNode);
|
23 | });
|
24 | });
|
25 | };
|
26 |
|
27 | function onEachEsNode(arg, source, callback) {
|
28 | var parseResult = parse(source);
|
29 | var tokens = parseResult.tokens;
|
30 | var espathToValue = reduce(arg.events, function (accum, ev) {
|
31 | accum[ev.espath] = ev.value;
|
32 | return accum;
|
33 | }, {});
|
34 | var nodeStack = [];
|
35 | estraverse.traverse(parseResult.expression, {
|
36 | enter: function (currentNode, parentNode) {
|
37 | var esNode = new EsNode(this.path(), currentNode, parentNode, espathToValue, source.content, tokens);
|
38 | if (1 < nodeStack.length) {
|
39 | esNode.setParent(nodeStack[nodeStack.length - 1]);
|
40 | }
|
41 | nodeStack.push(esNode);
|
42 | callback(esNode);
|
43 | },
|
44 | leave: function (currentNode, parentNode) {
|
45 | nodeStack.pop();
|
46 | }
|
47 | });
|
48 | }
|
49 |
|
50 | function parserOptions(tokens) {
|
51 | return {
|
52 | sourceType: 'module',
|
53 | ecmaVersion: 7,
|
54 | locations: true,
|
55 | ranges: true,
|
56 | onToken: tokens,
|
57 | plugins: {asyncawait: true}
|
58 | };
|
59 | }
|
60 |
|
61 | function wrappedInGenerator(jsCode) {
|
62 | return 'function *wrapper() {\n' + jsCode + '\n}';
|
63 | }
|
64 |
|
65 | function wrappedInAsync(jsCode) {
|
66 | return 'async function wrapper() {\n' + jsCode + '\n}';
|
67 | }
|
68 |
|
69 | function parse(source) {
|
70 | var ast;
|
71 | var tokens = [];
|
72 |
|
73 | function doParse(wrapper) {
|
74 | var content = wrapper ? wrapper(source.content) : source.content;
|
75 | ast = parser.parse(content, parserOptions(tokens));
|
76 | if (wrapper) {
|
77 | ast = ast.body[0].body;
|
78 | }
|
79 | }
|
80 |
|
81 | if (source.async) {
|
82 | doParse(wrappedInAsync);
|
83 | } else if (source.generator) {
|
84 | doParse(wrappedInGenerator);
|
85 | } else {
|
86 | doParse();
|
87 | }
|
88 |
|
89 | return {
|
90 | tokens: tokens,
|
91 | expression: ast.body[0].expression
|
92 | };
|
93 | }
|
94 |
|
95 | module.exports = ContextTraversal;
|