1 |
|
2 | (function() {
|
3 | var escodegen, esprima, estools, noopDef, noopExpression, tools, wrapLogic, wrapPred, _;
|
4 |
|
5 | _ = require('underscore');
|
6 |
|
7 | estools = require('./estools');
|
8 |
|
9 | tools = require('./tools');
|
10 |
|
11 | esprima = require('esprima');
|
12 |
|
13 | escodegen = require('escodegen');
|
14 |
|
15 | noopDef = function(name) {
|
16 | return {
|
17 | kind: 'var',
|
18 | type: 'VariableDeclaration',
|
19 | declarations: [
|
20 | {
|
21 | type: 'VariableDeclarator',
|
22 | id: {
|
23 | type: 'Identifier',
|
24 | name: name
|
25 | },
|
26 | init: {
|
27 | type: 'FunctionExpression',
|
28 | id: null,
|
29 | params: [],
|
30 | defaults: [],
|
31 | body: {
|
32 | type: 'BlockStatement',
|
33 | body: [
|
34 | {
|
35 | type: 'ReturnStatement',
|
36 | argument: {
|
37 | type: 'Literal',
|
38 | value: null
|
39 | }
|
40 | }
|
41 | ]
|
42 | }
|
43 | },
|
44 | rest: null,
|
45 | generator: false,
|
46 | expression: false
|
47 | }
|
48 | ]
|
49 | };
|
50 | };
|
51 |
|
52 | noopExpression = function(name) {
|
53 | return {
|
54 | type: 'ExpressionStatement',
|
55 | expression: {
|
56 | "arguments": [],
|
57 | type: 'CallExpression',
|
58 | callee: {
|
59 | type: 'Identifier',
|
60 | name: name
|
61 | }
|
62 | }
|
63 | };
|
64 | };
|
65 |
|
66 | wrapPred = function(test, left, right) {
|
67 | return {
|
68 | type: 'CallExpression',
|
69 | "arguments": [
|
70 | {
|
71 | type: 'ThisExpression'
|
72 | }, {
|
73 | type: 'Identifier',
|
74 | name: 'arguments'
|
75 | }
|
76 | ],
|
77 | callee: {
|
78 | type: 'MemberExpression',
|
79 | computed: false,
|
80 | property: {
|
81 | type: 'Identifier',
|
82 | name: 'call'
|
83 | },
|
84 | object: {
|
85 | type: 'FunctionExpression',
|
86 | id: null,
|
87 | rest: null,
|
88 | generator: false,
|
89 | expression: false,
|
90 | params: [
|
91 | {
|
92 | type: 'Identifier',
|
93 | name: 'arguments'
|
94 | }
|
95 | ],
|
96 | defaults: [],
|
97 | body: {
|
98 | type: 'BlockStatement',
|
99 | body: [
|
100 | {
|
101 | type: 'IfStatement',
|
102 | test: test,
|
103 | consequent: {
|
104 | type: 'ReturnStatement',
|
105 | argument: left
|
106 | },
|
107 | alternate: {
|
108 | type: 'ReturnStatement',
|
109 | argument: right
|
110 | }
|
111 | }
|
112 | ]
|
113 | }
|
114 | }
|
115 | }
|
116 | };
|
117 | };
|
118 |
|
119 | wrapLogic = function(isAnd, left, right, tmpvar) {
|
120 | var l, r, res;
|
121 | l = isAnd ? right : {
|
122 | type: 'Identifier',
|
123 | name: tmpvar
|
124 | };
|
125 | r = !isAnd ? right : {
|
126 | type: 'Identifier',
|
127 | name: tmpvar
|
128 | };
|
129 | res = wrapPred({
|
130 | type: 'Identifier',
|
131 | name: tmpvar
|
132 | }, l, r);
|
133 | res.callee.object.body.body = [
|
134 | {
|
135 | kind: 'var',
|
136 | type: 'VariableDeclaration',
|
137 | declarations: [
|
138 | {
|
139 | type: 'VariableDeclarator',
|
140 | id: {
|
141 | type: 'Identifier',
|
142 | name: tmpvar
|
143 | },
|
144 | init: left
|
145 | }
|
146 | ]
|
147 | }
|
148 | ].concat(res.callee.object.body.body);
|
149 | return res;
|
150 | };
|
151 |
|
152 | exports.expand = function(ast) {
|
153 | var addNoop;
|
154 | if (typeof ast === 'string') {
|
155 | return escodegen.generate(exports.expand(esprima.parse(ast, {
|
156 | loc: false
|
157 | })), {
|
158 | indent: " "
|
159 | });
|
160 | }
|
161 | addNoop = false;
|
162 | estools.traverse(ast, ['IfStatement'], function(node) {
|
163 | if (node.alternate == null) {
|
164 | addNoop = true;
|
165 | return node.alternate = noopExpression('__noop__');
|
166 | }
|
167 | });
|
168 | estools.traverse(ast, ['LogicalExpression'], function(node) {
|
169 | if (node.operator === '&&' || node.operator === '||') {
|
170 | if (node.left.type === 'Literal' || node.left.type === 'Identifier') {
|
171 | if (node.operator === '&&') {
|
172 | tools.replaceProperties(node, wrapPred(node.left, node.right, node.left));
|
173 | } else {
|
174 | tools.replaceProperties(node, wrapPred(node.left, node.left, node.right));
|
175 | }
|
176 | } else {
|
177 | tools.replaceProperties(node, wrapLogic(node.operator === '&&', node.left, node.right, '__lhs__'));
|
178 | }
|
179 | delete node.operator;
|
180 | delete node.left;
|
181 | return delete node.right;
|
182 | }
|
183 | });
|
184 | estools.traverse(ast, ['ConditionalExpression'], function(node) {
|
185 | tools.replaceProperties(node, wrapPred(node.test, node.consequent, node.alternate));
|
186 | delete node.test;
|
187 | delete node.consequent;
|
188 | return delete node.alternate;
|
189 | });
|
190 | if (addNoop) {
|
191 | estools.traverse(ast, ['Program'], function(node) {
|
192 | return node.body = [noopDef('__noop__')].concat(node.body);
|
193 | });
|
194 | }
|
195 | return ast;
|
196 | };
|
197 |
|
198 | }).call(this);
|