js-confuser 1.2.1 → 1.4.1
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 +171 -0
- package/README.md +7 -6
- package/dist/options.js +5 -1
- package/dist/parser.js +1 -2
- package/dist/presets.js +2 -2
- package/dist/transforms/calculator.js +48 -60
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -95
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
- package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
- package/dist/transforms/deadCode.js +1 -1
- package/dist/transforms/dispatcher.js +14 -13
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -10
- package/dist/transforms/flatten.js +5 -1
- package/dist/transforms/hideInitializingCode.js +17 -2
- package/dist/transforms/identifier/globalConcealing.js +46 -25
- package/dist/transforms/identifier/movedDeclarations.js +69 -68
- package/dist/transforms/identifier/renameVariables.js +22 -98
- package/dist/transforms/identifier/variableAnalysis.js +133 -0
- package/dist/transforms/label.js +11 -2
- package/dist/transforms/lock/antiDebug.js +32 -13
- package/dist/transforms/lock/lock.js +13 -2
- package/dist/transforms/minify.js +117 -120
- package/dist/transforms/opaquePredicates.js +4 -2
- package/dist/transforms/preparation/preparation.js +8 -0
- package/dist/transforms/renameLabels.js +17 -3
- package/dist/transforms/rgf.js +8 -3
- package/dist/transforms/shuffle.js +25 -9
- package/dist/transforms/stack.js +5 -9
- package/dist/transforms/string/encoding.js +209 -0
- package/dist/transforms/string/stringCompression.js +10 -10
- package/dist/transforms/string/stringConcealing.js +94 -65
- package/dist/transforms/string/stringSplitting.js +7 -7
- package/dist/transforms/transform.js +10 -0
- package/dist/traverse.js +1 -35
- package/dist/util/gen.js +3 -1
- package/dist/util/identifiers.js +9 -19
- package/dist/util/insert.js +6 -40
- package/dist/util/scope.js +17 -0
- package/package.json +2 -2
- package/src/options.ts +19 -3
- package/src/parser.ts +1 -2
- package/src/presets.ts +2 -2
- package/src/transforms/calculator.ts +87 -91
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +742 -142
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
- package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
- package/src/transforms/deadCode.ts +8 -0
- package/src/transforms/dispatcher.ts +29 -14
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +43 -19
- package/src/transforms/flatten.ts +15 -2
- package/src/transforms/hideInitializingCode.ts +432 -406
- package/src/transforms/identifier/globalConcealing.ts +148 -46
- package/src/transforms/identifier/movedDeclarations.ts +78 -101
- package/src/transforms/identifier/renameVariables.ts +21 -96
- package/src/transforms/identifier/variableAnalysis.ts +124 -0
- package/src/transforms/label.ts +20 -2
- package/src/transforms/lock/antiDebug.ts +69 -26
- package/src/transforms/lock/lock.ts +37 -3
- package/src/transforms/minify.ts +154 -130
- package/src/transforms/opaquePredicates.ts +25 -3
- package/src/transforms/preparation/preparation.ts +8 -1
- package/src/transforms/renameLabels.ts +26 -3
- package/src/transforms/rgf.ts +6 -1
- package/src/transforms/shuffle.ts +87 -29
- package/src/transforms/stack.ts +6 -8
- package/src/transforms/string/encoding.ts +310 -0
- package/src/transforms/string/stringCompression.ts +37 -24
- package/src/transforms/string/stringConcealing.ts +157 -160
- package/src/transforms/string/stringSplitting.ts +12 -8
- package/src/transforms/transform.ts +15 -2
- package/src/traverse.ts +1 -31
- package/src/util/gen.ts +5 -3
- package/src/util/identifiers.ts +20 -20
- package/src/util/insert.ts +12 -78
- package/src/util/scope.ts +9 -0
- package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
- package/test/index.test.ts +109 -1
- package/test/templates/template.test.ts +14 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
- package/test/transforms/dispatcher.test.ts +30 -0
- package/test/transforms/flatten.test.ts +28 -0
- package/test/transforms/hideInitializingCode.test.ts +336 -336
- package/test/transforms/identifier/globalConcealing.test.ts +1 -2
- package/test/transforms/identifier/movedDeclarations.test.ts +137 -112
- package/test/transforms/identifier/renameVariables.test.ts +124 -13
- package/test/transforms/lock/antiDebug.test.ts +43 -0
- package/test/transforms/lock/selfDefending.test.ts +68 -0
- package/test/transforms/minify.test.ts +137 -0
- package/test/transforms/renameLabels.test.ts +33 -0
- package/test/transforms/rgf.test.ts +29 -0
- package/test/transforms/string/stringSplitting.test.ts +33 -0
- package/test/util/identifiers.test.ts +105 -17
- package/dist/util/expr.js +0 -60
- package/src/util/expr.ts +0 -56
|
@@ -124,3 +124,140 @@ it("should work when shortening nested if-statements", async () => {
|
|
|
124
124
|
|
|
125
125
|
expect(value).toStrictEqual(10);
|
|
126
126
|
});
|
|
127
|
+
|
|
128
|
+
test("Variant #8: Shorten simple array destructuring", async () => {
|
|
129
|
+
// Valid
|
|
130
|
+
var output = await JsConfuser(`var [x] = [1]`, {
|
|
131
|
+
target: "node",
|
|
132
|
+
minify: true,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(output).toContain("var x=1");
|
|
136
|
+
|
|
137
|
+
// Invalid
|
|
138
|
+
var output2 = await JsConfuser(`var [x, y] = [1]`, {
|
|
139
|
+
target: "node",
|
|
140
|
+
minify: true,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(output2).toContain("var [x,y]");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("Variant #9: Shorten simple object destructuring", async () => {
|
|
147
|
+
// Valid
|
|
148
|
+
var output = await JsConfuser(`var {x} = {x: 1}`, {
|
|
149
|
+
target: "node",
|
|
150
|
+
minify: true,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(output).toContain("var x=1");
|
|
154
|
+
|
|
155
|
+
// Valid
|
|
156
|
+
var output2 = await JsConfuser(`var {['x']: y} = {x: 1}`, {
|
|
157
|
+
target: "node",
|
|
158
|
+
minify: true,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(output2).toContain("var y=1");
|
|
162
|
+
|
|
163
|
+
// Invalid
|
|
164
|
+
var output3 = await JsConfuser(`var {x,y} = {x:1}`, {
|
|
165
|
+
target: "node",
|
|
166
|
+
minify: true,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(output3).toContain("var {x:x,y:y}");
|
|
170
|
+
|
|
171
|
+
// Invalid
|
|
172
|
+
var output4 = await JsConfuser(`var {y} = {x:1}`, {
|
|
173
|
+
target: "node",
|
|
174
|
+
minify: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(output4).toContain("var {y:y}");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("Variant #10: Shorten booleans", async () => {
|
|
181
|
+
// Valid
|
|
182
|
+
var output = await JsConfuser(`var x = true;`, {
|
|
183
|
+
target: "node",
|
|
184
|
+
minify: true,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(output).toContain("var x=!0");
|
|
188
|
+
|
|
189
|
+
// Valid
|
|
190
|
+
var output2 = await JsConfuser(`var x = false`, {
|
|
191
|
+
target: "node",
|
|
192
|
+
minify: true,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(output2).toContain("var x=!1");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("Variant #11: Shorten 'undefined' to 'void 0'", async () => {
|
|
199
|
+
// Valid
|
|
200
|
+
var output = await JsConfuser(`x = undefined;`, {
|
|
201
|
+
target: "node",
|
|
202
|
+
minify: true,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(output).toContain("x=void 0");
|
|
206
|
+
|
|
207
|
+
// Valid
|
|
208
|
+
var output2 = await JsConfuser(`var x = {undefined: 1}`, {
|
|
209
|
+
target: "node",
|
|
210
|
+
minify: true,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(output2).toContain("var x={[void 0]:1}");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("Variant #11: Shorten 'Infinity' to 1/0", async () => {
|
|
217
|
+
// Valid
|
|
218
|
+
var output = await JsConfuser(`var x = Infinity;`, {
|
|
219
|
+
target: "node",
|
|
220
|
+
minify: true,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(output).toContain("var x=1/0");
|
|
224
|
+
|
|
225
|
+
// Valid
|
|
226
|
+
var output2 = await JsConfuser(`var x = {Infinity: 1}`, {
|
|
227
|
+
target: "node",
|
|
228
|
+
minify: true,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(output2).toContain("var x={[1/0]:1}");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("Variant #12: Shorten '!false' to 'true'", async () => {
|
|
235
|
+
// Valid
|
|
236
|
+
var output = await JsConfuser(`var x = !false;`, {
|
|
237
|
+
target: "node",
|
|
238
|
+
minify: true,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(output).toContain("var x=true");
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("Variant #13: Shorten 'false ? a : b' to 'b'", async () => {
|
|
245
|
+
// Valid
|
|
246
|
+
var output = await JsConfuser(`var x = false ? 10 : 15;`, {
|
|
247
|
+
target: "node",
|
|
248
|
+
minify: true,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(output).toContain("var x=15");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("Variant #14: Shorten 'var x = undefined' to 'var x'", async () => {
|
|
255
|
+
// Valid
|
|
256
|
+
var output = await JsConfuser(`var x = undefined`, {
|
|
257
|
+
target: "node",
|
|
258
|
+
minify: true,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
expect(output).toContain("var x");
|
|
262
|
+
expect(output).not.toContain("var x=");
|
|
263
|
+
});
|
|
@@ -60,3 +60,36 @@ it("should not rename nested labels", async () => {
|
|
|
60
60
|
expect(output).not.toContain("TEST_LABEL");
|
|
61
61
|
expect(output).toContain(":for");
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
it("should not remove labels on block statements", async () => {
|
|
65
|
+
var code = `
|
|
66
|
+
TEST_LABEL: {
|
|
67
|
+
break TEST_LABEL;
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
var output = await JsConfuser(code, {
|
|
72
|
+
target: "browser",
|
|
73
|
+
objectExtraction: true,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(output).not.toContain("TEST_LABEL");
|
|
77
|
+
expect(output).toContain(":{");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should remove labels on block statements when the label was never used", async () => {
|
|
81
|
+
var code = `
|
|
82
|
+
TEST_LABEL: {
|
|
83
|
+
"";
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
var output = await JsConfuser(code, {
|
|
88
|
+
target: "browser",
|
|
89
|
+
objectExtraction: true,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(output).not.toContain("TEST_LABEL");
|
|
93
|
+
expect(output).not.toContain(":{");
|
|
94
|
+
expect(output).toContain("{");
|
|
95
|
+
});
|
|
@@ -125,6 +125,35 @@ describe("RGF", () => {
|
|
|
125
125
|
|
|
126
126
|
expect(value).toStrictEqual("Hello World");
|
|
127
127
|
});
|
|
128
|
+
|
|
129
|
+
it("should work with hideInitializingCode enabled", async () => {
|
|
130
|
+
var output = await JsConfuser.obfuscate(
|
|
131
|
+
`
|
|
132
|
+
function abc(x, y){
|
|
133
|
+
return x + y;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var result = abc(10, 50);
|
|
137
|
+
input(console.log, result)
|
|
138
|
+
`,
|
|
139
|
+
{
|
|
140
|
+
target: "node",
|
|
141
|
+
identifierGenerator: "randomized",
|
|
142
|
+
hideInitializingCode: true,
|
|
143
|
+
rgf: true,
|
|
144
|
+
compact: false,
|
|
145
|
+
renameVariables: true,
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
var value = "never_called";
|
|
150
|
+
function input(_, valueIn) {
|
|
151
|
+
value = valueIn;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
eval(output);
|
|
155
|
+
expect(value).toStrictEqual(60);
|
|
156
|
+
});
|
|
128
157
|
});
|
|
129
158
|
|
|
130
159
|
describe("RGF with the 'all' mode", () => {
|
|
@@ -100,3 +100,36 @@ it("should not encode constructor key", async () => {
|
|
|
100
100
|
|
|
101
101
|
expect(TEST_VAR).toStrictEqual(100);
|
|
102
102
|
});
|
|
103
|
+
|
|
104
|
+
it("should allow custom callback to exclude strings", async () => {
|
|
105
|
+
var code = `
|
|
106
|
+
var str1 = "-- Hello World --";
|
|
107
|
+
var str2 = "-- This String Will Not Be Split --";
|
|
108
|
+
var str3 = "-- This string Will Be Split --";
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
var strings = [];
|
|
112
|
+
var output = await JsConfuser(code, {
|
|
113
|
+
target: "node",
|
|
114
|
+
stringSplitting: (str) => {
|
|
115
|
+
strings.push(str);
|
|
116
|
+
|
|
117
|
+
if (str == "-- This String Will Not Be Split --") {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(strings).toEqual([
|
|
126
|
+
"-- Hello World --",
|
|
127
|
+
"-- This String Will Not Be Split --",
|
|
128
|
+
"-- This string Will Be Split --",
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
expect(output).toContain("-- This String Will Not Be Split --");
|
|
132
|
+
|
|
133
|
+
expect(output).not.toContain("-- Hello World --");
|
|
134
|
+
expect(output).not.toContain("-- This string Will Be Split --");
|
|
135
|
+
});
|
|
@@ -1,32 +1,120 @@
|
|
|
1
1
|
import parseJS from "../../src/parser";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getFunctionParameters,
|
|
4
|
+
getIdentifierInfo,
|
|
5
|
+
validateChain,
|
|
6
|
+
} from "../../src/util/identifiers";
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
describe("getIdentifierInfo", () => {
|
|
9
|
+
test("Variant #1: Determine function declarations", async () => {
|
|
10
|
+
var tree = await parseJS(`function abc(){}`);
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
var object = tree.body[0].id;
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
expect(object.type).toStrictEqual("Identifier");
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
var parents = [tree.body[0], tree.body, tree];
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
var info = getIdentifierInfo(object, parents as any);
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
expect(info.isFunctionDeclaration).toStrictEqual(true);
|
|
21
|
+
expect(info.spec.isDefined).toStrictEqual(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("Variant #2: Determine labels", async () => {
|
|
25
|
+
var tree = await parseJS(`label: for (var i = 0; i < 0; i++ ) {}`);
|
|
26
|
+
|
|
27
|
+
var object = tree.body[0].label;
|
|
28
|
+
|
|
29
|
+
expect(object.type).toStrictEqual("Identifier");
|
|
30
|
+
|
|
31
|
+
var parents = [tree.body[0], tree.body, tree];
|
|
32
|
+
|
|
33
|
+
var info = getIdentifierInfo(object, parents as any);
|
|
34
|
+
|
|
35
|
+
expect(info.isLabel).toStrictEqual(true);
|
|
36
|
+
expect(info.spec.isReferenced).toStrictEqual(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("Variant #3: Error when a non-identifier node is given", async () => {
|
|
40
|
+
expect(() => {
|
|
41
|
+
getIdentifierInfo({ type: "Literal", value: true }, []);
|
|
42
|
+
}).toThrow();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("validateChain", () => {
|
|
47
|
+
test("Variant #1: Error when parents is not an array", () => {
|
|
48
|
+
expect(() => {
|
|
49
|
+
validateChain({ type: "Identifier", name: "name" }, {} as any);
|
|
50
|
+
}).toThrow();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("Variant #2: Error when object is undefined", () => {
|
|
54
|
+
expect(() => {
|
|
55
|
+
validateChain(undefined, []);
|
|
56
|
+
}).toThrow();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("Variant #3: Error when object is not connected to direct parent", () => {
|
|
60
|
+
expect(() => {
|
|
61
|
+
validateChain({ type: "Identifier", name: "name" }, [
|
|
62
|
+
{ type: "Program", body: [] },
|
|
63
|
+
]);
|
|
64
|
+
}).toThrow();
|
|
65
|
+
});
|
|
17
66
|
});
|
|
18
67
|
|
|
19
|
-
|
|
20
|
-
|
|
68
|
+
describe("getFunctionParameters", () => {
|
|
69
|
+
test("Variant #1: Work with default values and destructuring", async () => {
|
|
70
|
+
var code = `function a(A=_b,{B,[_c]:C},[D]){}`;
|
|
71
|
+
var tree = await parseJS(code);
|
|
72
|
+
|
|
73
|
+
var object = tree.body[0];
|
|
74
|
+
var parents: any = [tree.body, tree];
|
|
75
|
+
|
|
76
|
+
var locations = getFunctionParameters(object, parents);
|
|
77
|
+
var names = locations.map((x) => x[0].name);
|
|
78
|
+
|
|
79
|
+
expect(names).toStrictEqual(["A", "B", "C", "D"]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("Variant #2: Work with spread element", async () => {
|
|
83
|
+
var code = `function a(...A){}`;
|
|
84
|
+
var tree = await parseJS(code);
|
|
85
|
+
|
|
86
|
+
var object = tree.body[0];
|
|
87
|
+
var parents: any = [tree.body, tree];
|
|
88
|
+
|
|
89
|
+
var locations = getFunctionParameters(object, parents);
|
|
90
|
+
var names = locations.map((x) => x[0].name);
|
|
91
|
+
|
|
92
|
+
expect(names).toStrictEqual(["A"]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("Variant #3: Normal parameters", async () => {
|
|
96
|
+
var code = `function a(A,B,C,D){}`;
|
|
97
|
+
var tree = await parseJS(code);
|
|
98
|
+
|
|
99
|
+
var object = tree.body[0];
|
|
100
|
+
var parents: any = [tree.body, tree];
|
|
101
|
+
|
|
102
|
+
var locations = getFunctionParameters(object, parents);
|
|
103
|
+
var names = locations.map((x) => x[0].name);
|
|
21
104
|
|
|
22
|
-
|
|
105
|
+
expect(names).toStrictEqual(["A", "B", "C", "D"]);
|
|
106
|
+
});
|
|
23
107
|
|
|
24
|
-
|
|
108
|
+
test("Variant #4: Default values as functions", async () => {
|
|
109
|
+
var code = `function a(A = function(_a){ return _a; },B = function(_a, _b = function(){return this;}){return _a + _b();},C,D){}`;
|
|
110
|
+
var tree = await parseJS(code);
|
|
25
111
|
|
|
26
|
-
|
|
112
|
+
var object = tree.body[0];
|
|
113
|
+
var parents: any = [tree.body, tree];
|
|
27
114
|
|
|
28
|
-
|
|
115
|
+
var locations = getFunctionParameters(object, parents);
|
|
116
|
+
var names = locations.map((x) => x[0].name);
|
|
29
117
|
|
|
30
|
-
|
|
31
|
-
|
|
118
|
+
expect(names).toStrictEqual(["A", "B", "C", "D"]);
|
|
119
|
+
});
|
|
32
120
|
});
|
package/dist/util/expr.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.inverseExpression = inverseExpression;
|
|
7
|
-
|
|
8
|
-
var _gen = require("./gen");
|
|
9
|
-
|
|
10
|
-
var _traverse = require("../traverse");
|
|
11
|
-
|
|
12
|
-
function inverseExpression(expr) {
|
|
13
|
-
/**
|
|
14
|
-
* !x -> x
|
|
15
|
-
*/
|
|
16
|
-
if (expr.type == "UnaryExpression" && expr.operator == "!" && expr.prefix) {
|
|
17
|
-
return expr.argument;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
var inverseMapping = {
|
|
21
|
-
BinaryExpression: {
|
|
22
|
-
"<": ">=",
|
|
23
|
-
">": "<=",
|
|
24
|
-
"<=": ">",
|
|
25
|
-
">=": "<",
|
|
26
|
-
"==": "!=",
|
|
27
|
-
"===": "!=",
|
|
28
|
-
"!=": "==",
|
|
29
|
-
"!==": "==="
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
if (!inverseMapping[expr.type]) {
|
|
34
|
-
return (0, _gen.UnaryExpression)("!", expr);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
var safe = new Set(["Literal", "Identifier", "MemberExpression"]);
|
|
38
|
-
var canInvert = true;
|
|
39
|
-
(0, _traverse.walk)(expr, [], (object, parents) => {
|
|
40
|
-
if (object.type) {
|
|
41
|
-
var hasInverse = inverseMapping[object.type] && inverseMapping[object.type][object.operator];
|
|
42
|
-
|
|
43
|
-
if (!safe.has(object.type) && !hasInverse) {
|
|
44
|
-
// console.log(object.type);
|
|
45
|
-
canInvert = false;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
if (canInvert) {
|
|
51
|
-
(0, _traverse.walk)(expr, [], (object, parents) => {
|
|
52
|
-
if (object.operator) {
|
|
53
|
-
object.operator = inverseMapping[object.type][object.operator];
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return expr;
|
|
57
|
-
} else {
|
|
58
|
-
return (0, _gen.UnaryExpression)("!", expr);
|
|
59
|
-
}
|
|
60
|
-
}
|
package/src/util/expr.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Node, UnaryExpression } from "./gen";
|
|
2
|
-
import { walk } from "../traverse";
|
|
3
|
-
|
|
4
|
-
export function inverseExpression(expr: Node) {
|
|
5
|
-
/**
|
|
6
|
-
* !x -> x
|
|
7
|
-
*/
|
|
8
|
-
if (expr.type == "UnaryExpression" && expr.operator == "!" && expr.prefix) {
|
|
9
|
-
return expr.argument;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
var inverseMapping = {
|
|
13
|
-
BinaryExpression: {
|
|
14
|
-
"<": ">=",
|
|
15
|
-
">": "<=",
|
|
16
|
-
"<=": ">",
|
|
17
|
-
">=": "<",
|
|
18
|
-
"==": "!=",
|
|
19
|
-
"===": "!=",
|
|
20
|
-
"!=": "==",
|
|
21
|
-
"!==": "===",
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
if (!inverseMapping[expr.type]) {
|
|
26
|
-
return UnaryExpression("!", expr);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
var safe = new Set(["Literal", "Identifier", "MemberExpression"]);
|
|
30
|
-
|
|
31
|
-
var canInvert = true;
|
|
32
|
-
walk(expr, [], (object: Node, parents: Node[]) => {
|
|
33
|
-
if (object.type) {
|
|
34
|
-
var hasInverse =
|
|
35
|
-
inverseMapping[object.type] &&
|
|
36
|
-
inverseMapping[object.type][object.operator];
|
|
37
|
-
|
|
38
|
-
if (!safe.has(object.type) && !hasInverse) {
|
|
39
|
-
// console.log(object.type);
|
|
40
|
-
canInvert = false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
if (canInvert) {
|
|
46
|
-
walk(expr, [], (object: Node, parents: Node[]) => {
|
|
47
|
-
if (object.operator) {
|
|
48
|
-
object.operator = inverseMapping[object.type][object.operator];
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return expr;
|
|
53
|
-
} else {
|
|
54
|
-
return UnaryExpression("!", expr);
|
|
55
|
-
}
|
|
56
|
-
}
|