js-confuser 1.5.9 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +55 -0
- package/README.md +346 -165
- package/dist/constants.js +6 -2
- package/dist/index.js +9 -21
- package/dist/obfuscator.js +19 -31
- package/dist/options.js +5 -5
- package/dist/order.js +1 -3
- package/dist/presets.js +6 -7
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +3 -3
- package/dist/templates/es5.js +18 -0
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +8 -4
- package/dist/transforms/es5/antiDestructuring.js +2 -0
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +229 -148
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +35 -88
- package/dist/transforms/identifier/renameVariables.js +124 -59
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +60 -57
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +139 -247
- package/dist/transforms/stack.js +128 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +12 -19
- package/dist/traverse.js +24 -10
- package/dist/util/gen.js +17 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +35 -4
- package/dist/util/random.js +15 -0
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +5 -5
- package/src/constants.ts +3 -0
- package/src/index.ts +2 -2
- package/src/obfuscator.ts +19 -31
- package/src/options.ts +14 -103
- package/src/order.ts +1 -5
- package/src/presets.ts +6 -7
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +15 -19
- package/src/templates/es5.ts +131 -0
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +9 -4
- package/src/transforms/es5/antiDestructuring.ts +2 -0
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
- package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
- package/src/transforms/flatten.ts +357 -300
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +49 -102
- package/src/transforms/identifier/renameVariables.ts +149 -78
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +91 -75
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +213 -405
- package/src/transforms/stack.ts +156 -36
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +39 -9
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +21 -23
- package/src/traverse.ts +23 -4
- package/src/types.ts +2 -1
- package/src/util/gen.ts +28 -3
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +38 -3
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +146 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/index.test.ts +2 -1
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +22 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +20 -1
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/flatten.test.ts +399 -86
- package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
- package/test/transforms/identifier/renameVariables.test.ts +119 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +104 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +261 -381
- package/test/transforms/stack.test.ts +143 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +82 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { reservedKeywords } from "../../constants";
|
|
2
|
+
import { Location, Node } from "../../util/gen";
|
|
3
|
+
import { getIdentifierInfo } from "../../util/identifiers";
|
|
4
|
+
import Transform from "../transform";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Global Analysis is responsible for finding all the global variables used in the code.
|
|
8
|
+
*
|
|
9
|
+
* A 'global variable' is one that is:
|
|
10
|
+
* - Referenced
|
|
11
|
+
* - Never defined or overridden
|
|
12
|
+
*/
|
|
13
|
+
export default class GlobalAnalysis extends Transform {
|
|
14
|
+
notGlobals: Set<string>;
|
|
15
|
+
globals: { [name: string]: Location[] };
|
|
16
|
+
|
|
17
|
+
constructor(o) {
|
|
18
|
+
super(o);
|
|
19
|
+
|
|
20
|
+
this.globals = Object.create(null);
|
|
21
|
+
this.notGlobals = new Set();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
match(object: Node, parents: Node[]) {
|
|
25
|
+
return object.type == "Identifier" && !reservedKeywords.has(object.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
transform(object: Node, parents: Node[]) {
|
|
29
|
+
// no touching `import()` or `import x from ...`
|
|
30
|
+
var importIndex = parents.findIndex(
|
|
31
|
+
(x) => x.type == "ImportExpression" || x.type == "ImportDeclaration"
|
|
32
|
+
);
|
|
33
|
+
if (importIndex !== -1) {
|
|
34
|
+
if (
|
|
35
|
+
parents[importIndex].source === (parents[importIndex - 1] || object)
|
|
36
|
+
) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var info = getIdentifierInfo(object, parents);
|
|
42
|
+
if (!info.spec.isReferenced) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Cannot be defined or overridden
|
|
47
|
+
if (info.spec.isDefined || info.spec.isModified) {
|
|
48
|
+
delete this.globals[object.name];
|
|
49
|
+
|
|
50
|
+
this.notGlobals.add(object.name);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Add to globals
|
|
55
|
+
if (!this.notGlobals.has(object.name)) {
|
|
56
|
+
if (!this.globals[object.name]) {
|
|
57
|
+
this.globals[object.name] = [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.globals[object.name].push([object, parents]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var assignmentIndex = parents.findIndex(
|
|
64
|
+
(x) => x.type == "AssignmentExpression"
|
|
65
|
+
);
|
|
66
|
+
var updateIndex = parents.findIndex((x) => x.type == "UpdateExpression");
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
(assignmentIndex != -1 &&
|
|
70
|
+
parents[assignmentIndex].left ===
|
|
71
|
+
(parents[assignmentIndex - 1] || object)) ||
|
|
72
|
+
updateIndex != -1
|
|
73
|
+
) {
|
|
74
|
+
var memberIndex = parents.findIndex((x) => x.type == "MemberExpression");
|
|
75
|
+
if (
|
|
76
|
+
memberIndex == -1 ||
|
|
77
|
+
memberIndex > (assignmentIndex == -1 ? assignmentIndex : updateIndex)
|
|
78
|
+
) {
|
|
79
|
+
delete this.globals[object.name];
|
|
80
|
+
|
|
81
|
+
this.notGlobals.add(object.name);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -16,88 +16,15 @@ import {
|
|
|
16
16
|
VariableDeclarator,
|
|
17
17
|
FunctionExpression,
|
|
18
18
|
ExpressionStatement,
|
|
19
|
-
SequenceExpression,
|
|
20
19
|
AssignmentExpression,
|
|
21
20
|
VariableDeclaration,
|
|
22
21
|
BreakStatement,
|
|
23
22
|
} from "../../util/gen";
|
|
24
23
|
import { append, prepend } from "../../util/insert";
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { reservedIdentifiers, reservedKeywords } from "../../constants";
|
|
24
|
+
import { chance, getRandomInteger } from "../../util/random";
|
|
25
|
+
import { reservedIdentifiers } from "../../constants";
|
|
28
26
|
import { ComputeProbabilityMap } from "../../probability";
|
|
29
|
-
|
|
30
|
-
class GlobalAnalysis extends Transform {
|
|
31
|
-
notGlobals: Set<string>;
|
|
32
|
-
globals: { [name: string]: Location[] };
|
|
33
|
-
|
|
34
|
-
constructor(o) {
|
|
35
|
-
super(o);
|
|
36
|
-
|
|
37
|
-
this.globals = Object.create(null);
|
|
38
|
-
this.notGlobals = new Set();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
match(object: Node, parents: Node[]) {
|
|
42
|
-
return object.type == "Identifier" && !reservedKeywords.has(object.name);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
transform(object: Node, parents: Node[]) {
|
|
46
|
-
// no touching `import()` or `import x from ...`
|
|
47
|
-
var importIndex = parents.findIndex(
|
|
48
|
-
(x) => x.type == "ImportExpression" || x.type == "ImportDeclaration"
|
|
49
|
-
);
|
|
50
|
-
if (importIndex !== -1) {
|
|
51
|
-
if (
|
|
52
|
-
parents[importIndex].source === (parents[importIndex - 1] || object)
|
|
53
|
-
) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
var info = getIdentifierInfo(object, parents);
|
|
59
|
-
if (!info.spec.isReferenced) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Add to globals
|
|
64
|
-
if (!this.notGlobals.has(object.name)) {
|
|
65
|
-
if (!this.globals[object.name]) {
|
|
66
|
-
this.globals[object.name] = [];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
this.globals[object.name].push([object, parents]);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (info.spec.isDefined || info.spec.isModified) {
|
|
73
|
-
delete this.globals[object.name];
|
|
74
|
-
|
|
75
|
-
this.notGlobals.add(object.name);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
var assignmentIndex = parents.findIndex(
|
|
79
|
-
(x) => x.type == "AssignmentExpression"
|
|
80
|
-
);
|
|
81
|
-
var updateIndex = parents.findIndex((x) => x.type == "UpdateExpression");
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
(assignmentIndex != -1 &&
|
|
85
|
-
parents[assignmentIndex].left ===
|
|
86
|
-
(parents[assignmentIndex - 1] || object)) ||
|
|
87
|
-
updateIndex != -1
|
|
88
|
-
) {
|
|
89
|
-
var memberIndex = parents.findIndex((x) => x.type == "MemberExpression");
|
|
90
|
-
if (
|
|
91
|
-
memberIndex == -1 ||
|
|
92
|
-
memberIndex > (assignmentIndex == -1 ? assignmentIndex : updateIndex)
|
|
93
|
-
) {
|
|
94
|
-
delete this.globals[object.name];
|
|
95
|
-
|
|
96
|
-
this.notGlobals.add(object.name);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
27
|
+
import GlobalAnalysis from "./globalAnalysis";
|
|
101
28
|
|
|
102
29
|
/**
|
|
103
30
|
* Global Concealing hides global variables being accessed.
|
|
@@ -141,12 +68,10 @@ export default class GlobalConcealing extends Transform {
|
|
|
141
68
|
}
|
|
142
69
|
});
|
|
143
70
|
|
|
144
|
-
// this.log(Object.keys(globals).join(', '))
|
|
145
|
-
|
|
146
71
|
if (Object.keys(globals).length > 0) {
|
|
147
72
|
var used = new Set();
|
|
148
73
|
|
|
149
|
-
//
|
|
74
|
+
// Make getter function
|
|
150
75
|
|
|
151
76
|
// holds "window" or "global"
|
|
152
77
|
var globalVar = this.getPlaceholder();
|
|
@@ -157,6 +82,8 @@ export default class GlobalConcealing extends Transform {
|
|
|
157
82
|
// "window" or "global" in node
|
|
158
83
|
var global =
|
|
159
84
|
this.options.globalVariables.values().next().value || "window";
|
|
85
|
+
var alternateGlobal = global === "window" ? "global" : "window";
|
|
86
|
+
|
|
160
87
|
var getGlobalVariableFnName = this.getPlaceholder();
|
|
161
88
|
var getThisVariableFnName = this.getPlaceholder();
|
|
162
89
|
|
|
@@ -164,7 +91,7 @@ export default class GlobalConcealing extends Transform {
|
|
|
164
91
|
var getGlobalVariableFn = Template(`
|
|
165
92
|
var ${getGlobalVariableFnName} = function(){
|
|
166
93
|
try {
|
|
167
|
-
return ${global};
|
|
94
|
+
return ${global} || ${alternateGlobal} || (new Function("return this"))();
|
|
168
95
|
} catch (e){
|
|
169
96
|
return ${getThisVariableFnName}["call"](this);
|
|
170
97
|
}
|
|
@@ -182,7 +109,7 @@ export default class GlobalConcealing extends Transform {
|
|
|
182
109
|
// 2. Replace old accessors
|
|
183
110
|
var globalFn = this.getPlaceholder();
|
|
184
111
|
|
|
185
|
-
var newNames = Object.create(null);
|
|
112
|
+
var newNames: { [globalVarName: string]: number } = Object.create(null);
|
|
186
113
|
|
|
187
114
|
Object.keys(globals).forEach((name) => {
|
|
188
115
|
var locations: Location[] = globals[name];
|
|
@@ -195,26 +122,10 @@ export default class GlobalConcealing extends Transform {
|
|
|
195
122
|
newNames[name] = state;
|
|
196
123
|
|
|
197
124
|
locations.forEach(([node, parents]) => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
parents[0].type == "ClassDeclaration" ||
|
|
203
|
-
parents[0].type == "ClassExpression" ||
|
|
204
|
-
parents[0].type == "FunctionExpression" ||
|
|
205
|
-
parents[0].type == "FunctionDeclaration"
|
|
206
|
-
) {
|
|
207
|
-
if (parents[0].id === node) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
this.replace(
|
|
214
|
-
node,
|
|
215
|
-
CallExpression(Identifier(globalFn), [Literal(state)])
|
|
216
|
-
);
|
|
217
|
-
}
|
|
125
|
+
this.replace(
|
|
126
|
+
node,
|
|
127
|
+
CallExpression(Identifier(globalFn), [Literal(state)])
|
|
128
|
+
);
|
|
218
129
|
});
|
|
219
130
|
});
|
|
220
131
|
|
|
@@ -224,7 +135,7 @@ export default class GlobalConcealing extends Transform {
|
|
|
224
135
|
var state;
|
|
225
136
|
do {
|
|
226
137
|
state = getRandomInteger(
|
|
227
|
-
|
|
138
|
+
0,
|
|
228
139
|
1000 + used.size + this.options.globalVariables.size * 100
|
|
229
140
|
);
|
|
230
141
|
} while (used.has(state));
|
|
@@ -259,7 +170,7 @@ export default class GlobalConcealing extends Transform {
|
|
|
259
170
|
)
|
|
260
171
|
),
|
|
261
172
|
];
|
|
262
|
-
if (
|
|
173
|
+
if (chance(50)) {
|
|
263
174
|
body = [
|
|
264
175
|
ExpressionStatement(
|
|
265
176
|
AssignmentExpression(
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import Transform from "../transform";
|
|
2
|
-
import { isBlock
|
|
2
|
+
import { isBlock } from "../../traverse";
|
|
3
3
|
import {
|
|
4
|
-
Location,
|
|
5
4
|
ExpressionStatement,
|
|
6
|
-
SequenceExpression,
|
|
7
5
|
AssignmentExpression,
|
|
8
6
|
Identifier,
|
|
9
7
|
Node,
|
|
10
8
|
VariableDeclarator,
|
|
11
|
-
VariableDeclaration,
|
|
12
9
|
} from "../../util/gen";
|
|
13
|
-
import {
|
|
10
|
+
import { isForInitialize, prepend } from "../../util/insert";
|
|
14
11
|
import { ok } from "assert";
|
|
15
12
|
import { ObfuscateOrder } from "../../order";
|
|
16
|
-
import { getIdentifierInfo } from "../../util/identifiers";
|
|
17
|
-
import { isLoop } from "../../util/compare";
|
|
18
|
-
import { reservedIdentifiers } from "../../constants";
|
|
19
|
-
import { isLexicalScope, getLexicalScope } from "../../util/scope";
|
|
20
13
|
|
|
21
14
|
/**
|
|
22
15
|
* Defines all the names at the top of every lexical block.
|
|
@@ -27,114 +20,68 @@ export default class MovedDeclarations extends Transform {
|
|
|
27
20
|
}
|
|
28
21
|
|
|
29
22
|
match(object, parents) {
|
|
30
|
-
return
|
|
23
|
+
return (
|
|
24
|
+
object.type === "VariableDeclaration" &&
|
|
25
|
+
object.kind === "var" &&
|
|
26
|
+
object.declarations.length === 1 &&
|
|
27
|
+
object.declarations[0].id.type === "Identifier"
|
|
28
|
+
);
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
transform(object: Node, parents: Node[]) {
|
|
34
32
|
return () => {
|
|
35
|
-
var
|
|
36
|
-
ok(Array.isArray(body));
|
|
33
|
+
var forInitializeType = isForInitialize(object, parents);
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
replace: Node;
|
|
44
|
-
};
|
|
45
|
-
} = Object.create(null);
|
|
46
|
-
|
|
47
|
-
walk(object, parents, (o, p) => {
|
|
48
|
-
if (o.type == "Identifier") {
|
|
49
|
-
if (o.hidden || getLexicalScope(o, p) !== object) {
|
|
50
|
-
illegal.add(o.name);
|
|
51
|
-
} else {
|
|
52
|
-
var info = getIdentifierInfo(o, p);
|
|
53
|
-
if (!info.spec.isReferenced) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (info.spec.isDefined) {
|
|
58
|
-
if (info.isFunctionDeclaration || info.isClassDeclaration) {
|
|
59
|
-
illegal.add(o.name);
|
|
60
|
-
} else {
|
|
61
|
-
if (defined.has(o.name)) {
|
|
62
|
-
illegal.add(o.name);
|
|
63
|
-
} else {
|
|
64
|
-
defined.add(o.name);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
35
|
+
// Get the block statement or Program node
|
|
36
|
+
var blockIndex = parents.findIndex((x) => isBlock(x));
|
|
37
|
+
var block = parents[blockIndex];
|
|
38
|
+
var body = block.body;
|
|
39
|
+
var bodyObject = parents[blockIndex - 2] || object;
|
|
70
40
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
o.declarations.length === 1 &&
|
|
75
|
-
o.declarations[0].id.type === "Identifier"
|
|
76
|
-
) {
|
|
77
|
-
var name = o.declarations[0].id.name;
|
|
41
|
+
// Make sure in the block statement, and not already at the top of it
|
|
42
|
+
var index = body.indexOf(bodyObject);
|
|
43
|
+
if (index === -1 || index === 0) return;
|
|
78
44
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
var replace: Node = AssignmentExpression(
|
|
92
|
-
"=",
|
|
93
|
-
Identifier(name),
|
|
94
|
-
o.declarations[0].init || Identifier("undefined")
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
var forType = isForInitialize(o, p);
|
|
98
|
-
if (forType === "left-hand") {
|
|
99
|
-
replace = Identifier(name);
|
|
100
|
-
} else if (!forType) {
|
|
101
|
-
replace = ExpressionStatement(replace);
|
|
102
|
-
}
|
|
103
|
-
variableDeclarations[name] = {
|
|
104
|
-
location: [o, p],
|
|
105
|
-
replace: replace,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
});
|
|
45
|
+
var topVariableDeclaration;
|
|
46
|
+
if (body[0].type === "VariableDeclaration" && body[0].kind === "var") {
|
|
47
|
+
topVariableDeclaration = body[0];
|
|
48
|
+
} else {
|
|
49
|
+
topVariableDeclaration = {
|
|
50
|
+
type: "VariableDeclaration",
|
|
51
|
+
declarations: [],
|
|
52
|
+
kind: "var",
|
|
53
|
+
};
|
|
111
54
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
});
|
|
55
|
+
prepend(block, topVariableDeclaration);
|
|
56
|
+
}
|
|
115
57
|
|
|
116
|
-
var
|
|
58
|
+
var varName = object.declarations[0].id.name;
|
|
59
|
+
ok(typeof varName === "string");
|
|
117
60
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
61
|
+
// Add `var x` at the top of the block
|
|
62
|
+
topVariableDeclaration.declarations.push(
|
|
63
|
+
VariableDeclarator(Identifier(varName))
|
|
64
|
+
);
|
|
121
65
|
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
66
|
+
var assignmentExpression = AssignmentExpression(
|
|
67
|
+
"=",
|
|
68
|
+
Identifier(varName),
|
|
69
|
+
object.declarations[0].init || Identifier(varName)
|
|
126
70
|
);
|
|
127
71
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
72
|
+
if (forInitializeType) {
|
|
73
|
+
if (forInitializeType === "initializer") {
|
|
74
|
+
// Replace `for (var i = 0...)` to `for (i = 0...)`
|
|
75
|
+
this.replace(object, assignmentExpression);
|
|
76
|
+
} else if (forInitializeType === "left-hand") {
|
|
77
|
+
// Replace `for (var k in...)` to `for (k in ...)`
|
|
78
|
+
|
|
79
|
+
this.replace(object, Identifier(varName));
|
|
80
|
+
}
|
|
130
81
|
} else {
|
|
131
|
-
|
|
82
|
+
// Replace `var x = value` to `x = value`
|
|
83
|
+
this.replace(object, ExpressionStatement(assignmentExpression));
|
|
132
84
|
}
|
|
133
|
-
|
|
134
|
-
movingNames.forEach((name) => {
|
|
135
|
-
var { location, replace } = variableDeclarations[name];
|
|
136
|
-
this.replace(location[0], replace);
|
|
137
|
-
});
|
|
138
85
|
};
|
|
139
86
|
}
|
|
140
87
|
}
|