UNPKG

3.57 kBJavaScriptView Raw
1var babylon = require('babylon');
2var traverse = require('babel-traverse').default;
3var generate = require('babel-generator').default;
4var t = require('babel-types');
5
6exports.tryToParseJS = function (code, options) {
7 try {
8 babylon.parseExpression(code, {
9 plugins: [
10 'objectRestSpread',
11 'functionBind'
12 ]
13 });
14
15 return null;
16 } catch (err) {
17 var pos = err.pos;
18
19 if (typeof pos !== 'number') {
20 throw err;
21 }
22
23 if (code[pos] !== '}') {
24 throw new Error('Syntax error in expression: ' + JSON.stringify(code) + ' at pos: ' + pos);
25 }
26
27 var parsed = parseJS(code.slice(0, pos), options);
28
29 return {
30 vars: parsed.vars,
31 js: parsed.js,
32 original: parsed.original,
33 rest: code.slice(pos + 1)
34 };
35 }
36};
37
38var parseJS = exports.parseJS = function (code, options) {
39 var newCode = '(' + code + ')';
40
41 try {
42 var ast = babylon.parse(newCode, {
43 plugins: [
44 'objectRestSpread',
45 'functionBind'
46 ]
47 });
48 } catch (err) {
49 var pos = err.pos;
50
51 if (typeof pos !== 'number') {
52 throw err;
53 }
54
55 throw new Error('Syntax error in expression: ' + JSON.stringify(code) + ' at pos: ' + (pos - 1));
56 }
57
58 var uid;
59 var uid2;
60 var used = {};
61
62 traverse(ast, {
63 enter: function (path) {
64 if (path.isProgram()) {
65 uid = path.scope.generateUid('$');
66 uid2 = path.scope.generateUid('_');
67
68 return;
69 }
70
71 if (
72 path.parentPath
73 && path.parentPath.parentPath
74 && path.parentPath.isExpressionStatement()
75 && path.parentPath.parentPath.isProgram()
76 && (!path.node.id || path.node.id.name !== uid2)
77 ) {
78 path.replaceWith(
79 t.functionExpression(
80 t.identifier(uid2),
81 [
82 t.identifier(uid)
83 ],
84 t.blockStatement([
85 t.returnStatement(path.node)
86 ])
87 )
88 );
89 }
90
91 if (path.isThisExpression()) {
92 var scope = path.scope;
93
94 while ((!scope.path.node.id || scope.path.node.id.name !== uid2) && scope.path.isArrowFunctionExpression()) {
95 scope = scope.parent;
96 }
97
98 if (scope.path.node.id && scope.path.node.id.name === uid2) {
99 if (
100 path.parentPath
101 && path.parentPath.isMemberExpression()
102 && !path.parent.computed
103 && isOuterVar(path.parent.property.name)
104 ) {
105 used[path.parent.property.name] = true;
106 }
107
108 path.replaceWith(t.identifier(
109 options.__keepScope__
110 ? options.__thisUid__
111 : uid
112 ));
113 }
114 }
115
116 if (options.__keepScope__) {
117 return;
118 }
119
120 if (
121 path.isIdentifier()
122 && (path.isExpression() || (path.parentPath.isAssignmentExpression() && path.parentPath.node.left === path.node))
123 && !path.isPure()
124 && path.node.name !== uid
125 && options.globalVars.indexOf(path.node.name) === -1
126 ) {
127 if (isOuterVar(path.node.name)) {
128 used[path.node.name] = true;
129 }
130
131 path.replaceWith(
132 t.memberExpression(
133 t.identifier(uid),
134 t.identifier(path.node.name)
135 )
136 );
137 }
138 }
139 });
140
141 var generated = generate(ast, {}, newCode).code;
142
143 return {
144 vars: used,
145 js: generated,
146 original: code
147 };
148};
149
150function isOuterVar(variable) {
151 return (
152 variable !== 'args'
153 && variable !== 'globals'
154 && variable !== '$$'
155 );
156}