js-confuser 1.6.0 → 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/CHANGELOG.md +23 -0
- package/README.md +215 -170
- package/dist/constants.js +6 -2
- package/dist/obfuscator.js +0 -6
- package/dist/options.js +4 -4
- package/dist/presets.js +6 -7
- package/dist/templates/crash.js +2 -2
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/dispatcher.js +4 -1
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +89 -58
- package/dist/transforms/flatten.js +224 -147
- package/dist/transforms/identifier/movedDeclarations.js +38 -85
- package/dist/transforms/identifier/renameVariables.js +94 -41
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +2 -2
- package/dist/transforms/rgf.js +139 -246
- package/dist/transforms/stack.js +42 -1
- package/dist/transforms/transform.js +1 -1
- package/dist/util/gen.js +2 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +24 -3
- 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 +1 -1
- package/src/constants.ts +3 -0
- package/src/obfuscator.ts +0 -4
- package/src/options.ts +9 -86
- package/src/presets.ts +6 -7
- package/src/templates/crash.ts +10 -10
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/dispatcher.ts +5 -1
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +130 -129
- package/src/transforms/flatten.ts +357 -290
- package/src/transforms/identifier/movedDeclarations.ts +50 -96
- package/src/transforms/identifier/renameVariables.ts +120 -56
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +11 -2
- package/src/transforms/rgf.ts +214 -404
- package/src/transforms/stack.ts +62 -0
- package/src/transforms/transform.ts +6 -2
- package/src/util/gen.ts +7 -2
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +26 -2
- package/test/code/ES6.src.js +24 -0
- package/test/transforms/flatten.test.ts +352 -88
- package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
- package/test/transforms/identifier/renameVariables.test.ts +37 -0
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +19 -0
- package/test/transforms/rgf.test.ts +262 -353
- package/test/transforms/stack.test.ts +52 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
|
@@ -519,3 +519,55 @@ test("Variant #16: Function with 'this'", async () => {
|
|
|
519
519
|
|
|
520
520
|
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
521
521
|
});
|
|
522
|
+
|
|
523
|
+
// https://github.com/MichaelXF/js-confuser/issues/88
|
|
524
|
+
test("Variant #17: Syncing arguments parameter", async () => {
|
|
525
|
+
var output = await JsConfuser(
|
|
526
|
+
`
|
|
527
|
+
var TEST_OUTPUT;
|
|
528
|
+
|
|
529
|
+
function syncingArguments(parameter) {
|
|
530
|
+
arguments[0] = "Correct Value";
|
|
531
|
+
TEST_OUTPUT = parameter;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
syncingArguments("Incorrect Value");
|
|
535
|
+
`,
|
|
536
|
+
{ target: "node", stack: true }
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
function evalNoStrictMode(evalCode) {
|
|
540
|
+
var fn = new Function(evalCode + ";return TEST_OUTPUT");
|
|
541
|
+
return fn();
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
var TEST_OUTPUT = evalNoStrictMode(output);
|
|
545
|
+
|
|
546
|
+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test("Variant #18: Preserve function.length property", async () => {
|
|
550
|
+
var output = await JsConfuser(
|
|
551
|
+
`
|
|
552
|
+
function oneParameter(a){
|
|
553
|
+
var _ = 1;
|
|
554
|
+
};
|
|
555
|
+
var twoParameters = function(a,b){
|
|
556
|
+
var _ = 1;
|
|
557
|
+
};
|
|
558
|
+
var myObject = {
|
|
559
|
+
threeParameters(a,b,c){
|
|
560
|
+
var _ = 1;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
TEST_OUTPUT = oneParameter.length + twoParameters.length + myObject.threeParameters.length;
|
|
565
|
+
`,
|
|
566
|
+
{ target: "node", stack: true }
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
var TEST_OUTPUT;
|
|
570
|
+
eval(output);
|
|
571
|
+
|
|
572
|
+
expect(TEST_OUTPUT).toStrictEqual(6);
|
|
573
|
+
});
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ok } from "assert";
|
|
2
|
+
import parseJS, { parseSync } from "../../src/parser";
|
|
3
|
+
import traverse from "../../src/traverse";
|
|
4
|
+
import { Location, Node } from "../../src/util/gen";
|
|
2
5
|
import {
|
|
3
6
|
getFunctionParameters,
|
|
4
7
|
getIdentifierInfo,
|
|
@@ -41,6 +44,115 @@ describe("getIdentifierInfo", () => {
|
|
|
41
44
|
getIdentifierInfo({ type: "Literal", value: true }, []);
|
|
42
45
|
}).toThrow();
|
|
43
46
|
});
|
|
47
|
+
|
|
48
|
+
function findIdentifier(tree: Node, identifierName: string) {
|
|
49
|
+
var searchLocation: Location;
|
|
50
|
+
|
|
51
|
+
traverse(tree, (o, p) => {
|
|
52
|
+
if (o.type === "Identifier" && o.name === identifierName) {
|
|
53
|
+
ok(!searchLocation);
|
|
54
|
+
searchLocation = [o, p];
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
ok(searchLocation);
|
|
59
|
+
return searchLocation;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
test("Variant #4: Variable declaration assignment pattern", async () => {
|
|
63
|
+
var tree = parseSync(`
|
|
64
|
+
var [ definedIdentifier = nonDefinedIdentifier ] = [];
|
|
65
|
+
`);
|
|
66
|
+
|
|
67
|
+
var definedIdentifier = findIdentifier(tree, "definedIdentifier");
|
|
68
|
+
var definedInfo = getIdentifierInfo(
|
|
69
|
+
definedIdentifier[0],
|
|
70
|
+
definedIdentifier[1]
|
|
71
|
+
);
|
|
72
|
+
expect(definedInfo.spec.isDefined).toStrictEqual(true);
|
|
73
|
+
expect(definedInfo.spec.isReferenced).toStrictEqual(true);
|
|
74
|
+
|
|
75
|
+
var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
|
|
76
|
+
var nonDefinedInfo = getIdentifierInfo(
|
|
77
|
+
nonDefinedIdentifier[0],
|
|
78
|
+
nonDefinedIdentifier[1]
|
|
79
|
+
);
|
|
80
|
+
expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
|
|
81
|
+
expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("Variant #5: Function parameter assignment pattern", async () => {
|
|
85
|
+
var tree = parseSync(`
|
|
86
|
+
function myFunction(definedIdentifier = nonDefinedIdentifier) {
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
`);
|
|
90
|
+
|
|
91
|
+
var myFunction = findIdentifier(tree, "myFunction");
|
|
92
|
+
var myFunctionInfo = getIdentifierInfo(myFunction[0], myFunction[1]);
|
|
93
|
+
|
|
94
|
+
expect(myFunctionInfo.isFunctionDeclaration).toStrictEqual(true);
|
|
95
|
+
expect(myFunctionInfo.spec.isDefined).toStrictEqual(true);
|
|
96
|
+
|
|
97
|
+
var definedIdentifier = findIdentifier(tree, "definedIdentifier");
|
|
98
|
+
var definedInfo = getIdentifierInfo(
|
|
99
|
+
definedIdentifier[0],
|
|
100
|
+
definedIdentifier[1]
|
|
101
|
+
);
|
|
102
|
+
expect(definedInfo.spec.isDefined).toStrictEqual(true);
|
|
103
|
+
expect(definedInfo.spec.isReferenced).toStrictEqual(true);
|
|
104
|
+
|
|
105
|
+
var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
|
|
106
|
+
var nonDefinedInfo = getIdentifierInfo(
|
|
107
|
+
nonDefinedIdentifier[0],
|
|
108
|
+
nonDefinedIdentifier[1]
|
|
109
|
+
);
|
|
110
|
+
expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
|
|
111
|
+
expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(true);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("Variant #6: Object pattern", async () => {
|
|
115
|
+
var tree = parseSync(`
|
|
116
|
+
var { nonDefinedIdentifier: definedIdentifier } = {};
|
|
117
|
+
|
|
118
|
+
( { nonModifiedIdentifier: modifiedIdentifier } = {} );
|
|
119
|
+
`);
|
|
120
|
+
|
|
121
|
+
var definedIdentifier = findIdentifier(tree, "definedIdentifier");
|
|
122
|
+
var definedInfo = getIdentifierInfo(
|
|
123
|
+
definedIdentifier[0],
|
|
124
|
+
definedIdentifier[1]
|
|
125
|
+
);
|
|
126
|
+
expect(definedInfo.spec.isDefined).toStrictEqual(true);
|
|
127
|
+
expect(definedInfo.spec.isReferenced).toStrictEqual(true);
|
|
128
|
+
|
|
129
|
+
var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
|
|
130
|
+
var nonDefinedInfo = getIdentifierInfo(
|
|
131
|
+
nonDefinedIdentifier[0],
|
|
132
|
+
nonDefinedIdentifier[1]
|
|
133
|
+
);
|
|
134
|
+
expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
|
|
135
|
+
expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(false);
|
|
136
|
+
|
|
137
|
+
var modifiedIdentifier = findIdentifier(tree, "modifiedIdentifier");
|
|
138
|
+
var modifiedInfo = getIdentifierInfo(
|
|
139
|
+
modifiedIdentifier[0],
|
|
140
|
+
modifiedIdentifier[1]
|
|
141
|
+
);
|
|
142
|
+
expect(modifiedInfo.spec.isDefined).toStrictEqual(false);
|
|
143
|
+
expect(modifiedInfo.spec.isModified).toStrictEqual(true);
|
|
144
|
+
expect(modifiedInfo.spec.isReferenced).toStrictEqual(true);
|
|
145
|
+
|
|
146
|
+
var nonModifiedIdentifier = findIdentifier(tree, "nonModifiedIdentifier");
|
|
147
|
+
var nonModifiedInfo = getIdentifierInfo(
|
|
148
|
+
nonModifiedIdentifier[0],
|
|
149
|
+
nonModifiedIdentifier[1]
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(nonModifiedInfo.spec.isDefined).toStrictEqual(false);
|
|
153
|
+
expect(nonModifiedInfo.spec.isModified).toStrictEqual(false);
|
|
154
|
+
expect(nonModifiedInfo.spec.isReferenced).toStrictEqual(false);
|
|
155
|
+
});
|
|
44
156
|
});
|
|
45
157
|
|
|
46
158
|
describe("validateChain", () => {
|
package/test/util/insert.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { ok } from "assert";
|
|
1
2
|
import { compileJsSync } from "../../src/compiler";
|
|
2
|
-
import parseJS from "../../src/parser";
|
|
3
|
-
import { isBlock } from "../../src/traverse";
|
|
4
|
-
import { Identifier } from "../../src/util/gen";
|
|
3
|
+
import parseJS, { parseSync } from "../../src/parser";
|
|
4
|
+
import traverse, { isBlock } from "../../src/traverse";
|
|
5
|
+
import { Identifier, Location } from "../../src/util/gen";
|
|
5
6
|
import {
|
|
6
7
|
deleteDeclaration,
|
|
7
8
|
isVarContext,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
getContexts,
|
|
11
12
|
getLexContext,
|
|
12
13
|
getVarContext,
|
|
14
|
+
computeFunctionLength,
|
|
13
15
|
} from "../../src/util/insert";
|
|
14
16
|
|
|
15
17
|
it("isBlock() should be true for block statements and program", async () => {
|
|
@@ -86,3 +88,55 @@ it("should throw when missing parameters", () => {
|
|
|
86
88
|
expect(() => getLexContext(Identifier("test"), [])).toThrow();
|
|
87
89
|
expect(() => getVarContext(Identifier("test"), [])).toThrow();
|
|
88
90
|
});
|
|
91
|
+
|
|
92
|
+
test("computeFunctionLength", () => {
|
|
93
|
+
var tree = parseSync(`
|
|
94
|
+
function zeroParameters(){}; // 0
|
|
95
|
+
function oneParameter(a){}; // 1
|
|
96
|
+
function twoParameter(a,b){}; // 2
|
|
97
|
+
function restParameter1(...a){}; // 0
|
|
98
|
+
function restParameter2(a,b,...c){}; // 2
|
|
99
|
+
function defaultValue(a,b,c=1,d){}; // 2
|
|
100
|
+
function arrayPattern([a],[b = 2],[[c]]){}; // 3
|
|
101
|
+
function objectPattern({a},{b = 2},{c, d}){}; // 3
|
|
102
|
+
function mixed(a,{b},[c = 3],d,e=5,f,...g){}; // 4
|
|
103
|
+
`);
|
|
104
|
+
|
|
105
|
+
function getFunction(searchName: string): Location {
|
|
106
|
+
var searchLocation: Location;
|
|
107
|
+
traverse(tree, (o, p) => {
|
|
108
|
+
if (o.type === "FunctionDeclaration" && o.id.name === searchName) {
|
|
109
|
+
ok(!searchLocation);
|
|
110
|
+
searchLocation = [o, p];
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
ok(searchLocation);
|
|
115
|
+
return searchLocation;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
expect(
|
|
119
|
+
computeFunctionLength(getFunction("zeroParameters")[0].params)
|
|
120
|
+
).toStrictEqual(0);
|
|
121
|
+
expect(
|
|
122
|
+
computeFunctionLength(getFunction("oneParameter")[0].params)
|
|
123
|
+
).toStrictEqual(1);
|
|
124
|
+
expect(
|
|
125
|
+
computeFunctionLength(getFunction("twoParameter")[0].params)
|
|
126
|
+
).toStrictEqual(2);
|
|
127
|
+
expect(
|
|
128
|
+
computeFunctionLength(getFunction("restParameter1")[0].params)
|
|
129
|
+
).toStrictEqual(0);
|
|
130
|
+
expect(
|
|
131
|
+
computeFunctionLength(getFunction("restParameter2")[0].params)
|
|
132
|
+
).toStrictEqual(2);
|
|
133
|
+
expect(
|
|
134
|
+
computeFunctionLength(getFunction("arrayPattern")[0].params)
|
|
135
|
+
).toStrictEqual(3);
|
|
136
|
+
expect(
|
|
137
|
+
computeFunctionLength(getFunction("objectPattern")[0].params)
|
|
138
|
+
).toStrictEqual(3);
|
|
139
|
+
expect(computeFunctionLength(getFunction("mixed")[0].params)).toStrictEqual(
|
|
140
|
+
4
|
|
141
|
+
);
|
|
142
|
+
});
|
package/src/transforms/eval.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { compileJsSync } from "../compiler";
|
|
2
|
-
import { ObfuscateOrder } from "../order";
|
|
3
|
-
import { ComputeProbabilityMap } from "../probability";
|
|
4
|
-
import { isBlock } from "../traverse";
|
|
5
|
-
import {
|
|
6
|
-
CallExpression,
|
|
7
|
-
Identifier,
|
|
8
|
-
Literal,
|
|
9
|
-
Node,
|
|
10
|
-
VariableDeclaration,
|
|
11
|
-
VariableDeclarator,
|
|
12
|
-
} from "../util/gen";
|
|
13
|
-
import { isFunction, prepend } from "../util/insert";
|
|
14
|
-
import Transform from "./transform";
|
|
15
|
-
|
|
16
|
-
export default class Eval extends Transform {
|
|
17
|
-
constructor(o) {
|
|
18
|
-
super(o, ObfuscateOrder.Eval);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
match(object, parents) {
|
|
22
|
-
return (
|
|
23
|
-
isFunction(object) &&
|
|
24
|
-
object.type != "ArrowFunctionExpression" &&
|
|
25
|
-
!object.$eval &&
|
|
26
|
-
!object.$dispatcherSkip
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
transform(object, parents) {
|
|
31
|
-
// Don't apply to getter/setters or class methods
|
|
32
|
-
if (parents[0]) {
|
|
33
|
-
if (
|
|
34
|
-
parents[0].type === "MethodDefinition" &&
|
|
35
|
-
parents[0].value === object
|
|
36
|
-
) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
parents[0].type === "Property" &&
|
|
42
|
-
parents[0].value === object &&
|
|
43
|
-
(parents[0].kind !== "init" || parents[0].method)
|
|
44
|
-
) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
!ComputeProbabilityMap(
|
|
51
|
-
this.options.eval,
|
|
52
|
-
(x) => x,
|
|
53
|
-
object.id && object.id.name
|
|
54
|
-
)
|
|
55
|
-
) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
object.$eval = (o, p) => {
|
|
60
|
-
var name;
|
|
61
|
-
var requiresMove = false;
|
|
62
|
-
if (object.type == "FunctionDeclaration") {
|
|
63
|
-
name = object.id.name;
|
|
64
|
-
object.type = "FunctionExpression";
|
|
65
|
-
object.id = null;
|
|
66
|
-
requiresMove = Array.isArray(p[0]) && isBlock(p[1]);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
var code = compileJsSync(object, this.options);
|
|
70
|
-
if (object.type == "FunctionExpression") {
|
|
71
|
-
code = "(" + code + ")";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
var literal = Literal(code);
|
|
75
|
-
|
|
76
|
-
var expr: Node = CallExpression(Identifier("eval"), [literal]);
|
|
77
|
-
if (name) {
|
|
78
|
-
expr = VariableDeclaration(VariableDeclarator(name, expr));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (requiresMove) {
|
|
82
|
-
prepend(p[1], expr);
|
|
83
|
-
p[0].splice(p[0].indexOf(object), 1);
|
|
84
|
-
} else {
|
|
85
|
-
this.replace(object, expr);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
import { ok } from "assert";
|
|
2
|
-
import { ObfuscateOrder } from "../../order";
|
|
3
|
-
import { ComputeProbabilityMap } from "../../probability";
|
|
4
|
-
import { getBlock, isBlock, walk } from "../../traverse";
|
|
5
|
-
import {
|
|
6
|
-
AssignmentExpression,
|
|
7
|
-
ExpressionStatement,
|
|
8
|
-
Identifier,
|
|
9
|
-
Location,
|
|
10
|
-
VariableDeclarator,
|
|
11
|
-
} from "../../util/gen";
|
|
12
|
-
import {
|
|
13
|
-
containsLexicallyBoundVariables,
|
|
14
|
-
getFunctionParameters,
|
|
15
|
-
getIdentifierInfo,
|
|
16
|
-
} from "../../util/identifiers";
|
|
17
|
-
import {
|
|
18
|
-
getDefiningContext,
|
|
19
|
-
getReferencingContexts,
|
|
20
|
-
getVarContext,
|
|
21
|
-
isForInitialize,
|
|
22
|
-
isFunction,
|
|
23
|
-
isVarContext,
|
|
24
|
-
} from "../../util/insert";
|
|
25
|
-
import Transform from "../transform";
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Statement-based variable recycling.
|
|
29
|
-
*
|
|
30
|
-
* ```js
|
|
31
|
-
* // Input
|
|
32
|
-
* function percentage(decimal) {
|
|
33
|
-
* var multiplied = x * 100;
|
|
34
|
-
* var floored = Math.floor(multiplied);
|
|
35
|
-
* var output = floored + "%"
|
|
36
|
-
* return output;
|
|
37
|
-
* }
|
|
38
|
-
*
|
|
39
|
-
* // Output
|
|
40
|
-
* function percentage(decimal) {
|
|
41
|
-
* var multiplied = x * 100;
|
|
42
|
-
* var floored = Math.floor(multiplied);
|
|
43
|
-
* multiplied = floored + "%";
|
|
44
|
-
* return multiplied;
|
|
45
|
-
* }
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export default class NameRecycling extends Transform {
|
|
49
|
-
constructor(o) {
|
|
50
|
-
super(o, ObfuscateOrder.NameRecycling);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
match(object, parents) {
|
|
54
|
-
return isBlock(object);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
transform(object, parents) {
|
|
58
|
-
return () => {
|
|
59
|
-
if (containsLexicallyBoundVariables(object, parents)) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
var context = getVarContext(object, parents);
|
|
64
|
-
|
|
65
|
-
var stmts = [...object.body];
|
|
66
|
-
ok(Array.isArray(stmts));
|
|
67
|
-
|
|
68
|
-
var definedMap = new Map<number, Set<string>>();
|
|
69
|
-
var referencedMap = new Map<number, Set<string>>();
|
|
70
|
-
var nodeMap = new Map<number, Map<string, Location[]>>();
|
|
71
|
-
|
|
72
|
-
var lastReferenceMap = new Map<string, number>();
|
|
73
|
-
|
|
74
|
-
var defined = new Set<string>();
|
|
75
|
-
var illegal = new Set<string>();
|
|
76
|
-
|
|
77
|
-
var fn = isFunction(parents[0]) ? parents[0] : null;
|
|
78
|
-
if (fn) {
|
|
79
|
-
definedMap.set(
|
|
80
|
-
-1,
|
|
81
|
-
new Set(
|
|
82
|
-
getFunctionParameters(fn, parents.slice(1)).map((x) => x[0].name)
|
|
83
|
-
)
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
stmts.forEach((stmt, i) => {
|
|
88
|
-
var definedHere = new Set<string>();
|
|
89
|
-
var referencedHere = new Set<string>();
|
|
90
|
-
var nodesHere = new Map<string, Location[]>();
|
|
91
|
-
|
|
92
|
-
walk(stmt, [object.body, object, ...parents], (o, p) => {
|
|
93
|
-
if (o.type == "Identifier") {
|
|
94
|
-
return () => {
|
|
95
|
-
var info = getIdentifierInfo(o, p);
|
|
96
|
-
if (!info.spec.isReferenced) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
var comparingContext = info.spec.isDefined
|
|
101
|
-
? getDefiningContext(o, p)
|
|
102
|
-
: getReferencingContexts(o, p).find((x) => isVarContext(x));
|
|
103
|
-
|
|
104
|
-
if (comparingContext !== context) {
|
|
105
|
-
illegal.add(o.name);
|
|
106
|
-
this.log(o.name, "is different context");
|
|
107
|
-
} else {
|
|
108
|
-
if (!nodesHere.has(o.name)) {
|
|
109
|
-
nodesHere.set(o.name, [[o, p]]);
|
|
110
|
-
} else {
|
|
111
|
-
nodesHere.get(o.name).push([o, p]);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (info.spec.isDefined) {
|
|
115
|
-
// Function Declarations can be used before they're defined, if so, don't change this
|
|
116
|
-
if (
|
|
117
|
-
info.isFunctionDeclaration &&
|
|
118
|
-
lastReferenceMap.has(o.name)
|
|
119
|
-
) {
|
|
120
|
-
illegal.add(o.name);
|
|
121
|
-
}
|
|
122
|
-
if (
|
|
123
|
-
defined.has(o.name) ||
|
|
124
|
-
getBlock(o, p) !== object ||
|
|
125
|
-
info.isImportSpecifier
|
|
126
|
-
) {
|
|
127
|
-
illegal.add(o.name);
|
|
128
|
-
}
|
|
129
|
-
defined.add(o.name);
|
|
130
|
-
definedHere.add(o.name);
|
|
131
|
-
} else {
|
|
132
|
-
referencedHere.add(o.name);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
lastReferenceMap.set(o.name, i);
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// console.log(i, definedHere);
|
|
142
|
-
|
|
143
|
-
definedMap.set(i, definedHere);
|
|
144
|
-
referencedMap.set(i, referencedHere);
|
|
145
|
-
nodeMap.set(i, nodesHere);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
this.log(illegal);
|
|
149
|
-
|
|
150
|
-
illegal.forEach((name) => {
|
|
151
|
-
nodeMap.forEach((value) => {
|
|
152
|
-
value.delete(name);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
var available = new Set<string>();
|
|
157
|
-
var newNames = Object.create(null);
|
|
158
|
-
|
|
159
|
-
stmts.forEach((stmt, i) => {
|
|
160
|
-
var nodes = nodeMap.get(i);
|
|
161
|
-
|
|
162
|
-
nodes.forEach((locations, name) => {
|
|
163
|
-
var newName = newNames[name];
|
|
164
|
-
|
|
165
|
-
if (!newName) {
|
|
166
|
-
var canChange = false;
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
object.type == "Program" &&
|
|
170
|
-
!ComputeProbabilityMap(this.options.renameGlobals, (x) => x, name)
|
|
171
|
-
) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (defined.has(name) && definedMap.get(i).has(name)) {
|
|
176
|
-
canChange = true;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (!canChange) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (available.size) {
|
|
184
|
-
newName = available.keys().next().value;
|
|
185
|
-
available.delete(newName);
|
|
186
|
-
|
|
187
|
-
ok(name !== newName);
|
|
188
|
-
newNames[name] = newName;
|
|
189
|
-
|
|
190
|
-
defined.delete(name);
|
|
191
|
-
|
|
192
|
-
this.log(name, "->", newName);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
nodes.forEach((locations, name) => {
|
|
198
|
-
var newName = newNames[name];
|
|
199
|
-
|
|
200
|
-
if (newName) {
|
|
201
|
-
locations.forEach(([object, parents]) => {
|
|
202
|
-
object.name = newName;
|
|
203
|
-
|
|
204
|
-
var declaratorIndex = parents.findIndex(
|
|
205
|
-
(p) => p.type == "VariableDeclarator"
|
|
206
|
-
);
|
|
207
|
-
if (
|
|
208
|
-
declaratorIndex !== -1 &&
|
|
209
|
-
parents[declaratorIndex].id ===
|
|
210
|
-
(parents[declaratorIndex - 1] || object)
|
|
211
|
-
) {
|
|
212
|
-
var value =
|
|
213
|
-
parents[declaratorIndex].init || Identifier("undefined");
|
|
214
|
-
|
|
215
|
-
var expr = AssignmentExpression(
|
|
216
|
-
"=",
|
|
217
|
-
parents[declaratorIndex].id,
|
|
218
|
-
value
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
if (parents[declaratorIndex + 1].length === 1) {
|
|
222
|
-
if (
|
|
223
|
-
isForInitialize(
|
|
224
|
-
parents[declaratorIndex + 2],
|
|
225
|
-
parents.slice(3)
|
|
226
|
-
)
|
|
227
|
-
) {
|
|
228
|
-
this.replace(parents[declaratorIndex + 2], expr);
|
|
229
|
-
} else {
|
|
230
|
-
this.replace(
|
|
231
|
-
parents[declaratorIndex + 2],
|
|
232
|
-
ExpressionStatement(expr)
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
this.replace(
|
|
237
|
-
parents[declaratorIndex],
|
|
238
|
-
VariableDeclarator(this.getPlaceholder(), expr)
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
if (parents[0].type == "FunctionDeclaration") {
|
|
243
|
-
this.replace(
|
|
244
|
-
parents[0],
|
|
245
|
-
ExpressionStatement(
|
|
246
|
-
AssignmentExpression("=", Identifier(newName), {
|
|
247
|
-
...parents[0],
|
|
248
|
-
type: "FunctionExpression",
|
|
249
|
-
id: null,
|
|
250
|
-
})
|
|
251
|
-
)
|
|
252
|
-
);
|
|
253
|
-
} else if (parents[0].type == "ClassDeclaration") {
|
|
254
|
-
this.replace(
|
|
255
|
-
parents[0],
|
|
256
|
-
ExpressionStatement(
|
|
257
|
-
AssignmentExpression("=", Identifier(newName), {
|
|
258
|
-
...parents[0],
|
|
259
|
-
type: "ClassExpression",
|
|
260
|
-
})
|
|
261
|
-
)
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (defined.has(name)) {
|
|
269
|
-
var lastRef = lastReferenceMap.get(name);
|
|
270
|
-
var isDecommissioned = lastRef === i;
|
|
271
|
-
|
|
272
|
-
if (isDecommissioned) {
|
|
273
|
-
available.add(name);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|