UNPKG

3.38 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 (options.__keepScope__) {
92 return;
93 }
94
95 if (path.isThisExpression()) {
96 var scope = path.scope;
97
98 while ((!scope.path.node.id || scope.path.node.id.name !== uid2) && scope.path.isArrowFunctionExpression()) {
99 scope = scope.parent;
100 }
101
102 if (scope.path.node.id && scope.path.node.id.name === uid2) {
103 if (
104 path.parentPath
105 && path.parentPath.isMemberExpression()
106 && !path.parent.computed
107 && isOuterVar(path.parent.property.name)
108 ) {
109 used[path.parent.property.name] = true;
110 }
111
112 path.replaceWith(t.identifier(uid));
113 }
114 }
115
116 if (
117 path.isIdentifier()
118 && path.isExpression()
119 && !path.isPure()
120 && path.node.name !== uid
121 && options.globalVars.indexOf(path.node.name) === -1
122 ) {
123 if (isOuterVar(path.node.name)) {
124 used[path.node.name] = true;
125 }
126
127 path.replaceWith(
128 t.memberExpression(
129 t.identifier(uid),
130 t.identifier(path.node.name)
131 )
132 );
133 }
134 }
135 });
136
137 var generated = generate(ast, {}, newCode).code;
138
139 return {
140 vars: used,
141 js: generated,
142 original: code
143 };
144};
145
146function isOuterVar(variable) {
147 return (
148 variable !== 'args'
149 && variable !== 'globals'
150 && variable !== '$$'
151 );
152}