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
package/dist/util/identifiers.js
CHANGED
|
@@ -4,8 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.validateChain = validateChain;
|
|
7
|
-
exports.isWithinClass = isWithinClass;
|
|
8
|
-
exports.isWithin = isWithin;
|
|
9
7
|
exports.getIdentifierInfo = getIdentifierInfo;
|
|
10
8
|
exports.getDefiningIdentifier = getDefiningIdentifier;
|
|
11
9
|
exports.isFunctionParameter = isFunctionParameter;
|
|
@@ -44,14 +42,6 @@ function validateChain(object, parents) {
|
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
}
|
|
47
|
-
|
|
48
|
-
function isWithinClass(object, parents) {
|
|
49
|
-
return isWithin(object, parents, "ClassDeclaration") || isWithin(object, parents, "ClassExpression");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function isWithin(object, parents, type) {
|
|
53
|
-
return [object, ...parents].some(x => x.type == type);
|
|
54
|
-
}
|
|
55
45
|
/**
|
|
56
46
|
* Returns detailed information about the given Identifier node.
|
|
57
47
|
* @param object
|
|
@@ -99,10 +89,11 @@ function getIdentifierInfo(object, parents) {
|
|
|
99
89
|
var isImportSpecifier = (parent.type == "ImportDefaultSpecifier" || parent.type == "ImportSpecifier") && parent.local == object;
|
|
100
90
|
var isFunctionCall = parent.callee == object; // NewExpression and CallExpression
|
|
101
91
|
|
|
102
|
-
var
|
|
103
|
-
var
|
|
92
|
+
var assignmentIndex = parents.findIndex(p => p.type === "AssignmentExpression");
|
|
93
|
+
var isAssignmentLeft = assignmentIndex !== -1 && parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
|
|
94
|
+
var isAssignmentValue = assignmentIndex !== -1 && parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
|
|
104
95
|
var isUpdateExpression = parent.type == "UpdateExpression";
|
|
105
|
-
var isClassDeclaration = parent.type == "ClassDeclaration" && parent.id == object;
|
|
96
|
+
var isClassDeclaration = (parent.type == "ClassDeclaration" || parent.type == "ClassExpression") && parent.id == object;
|
|
106
97
|
var isMethodDefinition = parent.type == "MethodDefinition" && parent.key == object && !parent.computed;
|
|
107
98
|
var isMetaProperty = parent.type == "MetaProperty";
|
|
108
99
|
var isLabel = parent.type == "LabeledStatement" && parent.label == object; // Fix 1: Labels are properly identified
|
|
@@ -300,7 +291,7 @@ function getDefiningIdentifier(object, parents) {
|
|
|
300
291
|
}
|
|
301
292
|
}
|
|
302
293
|
|
|
303
|
-
function isFunctionParameter(o, p) {
|
|
294
|
+
function isFunctionParameter(o, p, c) {
|
|
304
295
|
(0, _assert.ok)(o);
|
|
305
296
|
(0, _assert.ok)(p);
|
|
306
297
|
validateChain(o, p);
|
|
@@ -315,7 +306,7 @@ function isFunctionParameter(o, p) {
|
|
|
315
306
|
return false;
|
|
316
307
|
}
|
|
317
308
|
|
|
318
|
-
|
|
309
|
+
c = c || (0, _insert.getVarContext)(o, p);
|
|
319
310
|
|
|
320
311
|
if (c === object) {
|
|
321
312
|
var pIndex = p.indexOf(object.params);
|
|
@@ -327,8 +318,7 @@ function isFunctionParameter(o, p) {
|
|
|
327
318
|
var param = p[pIndex - 1] || o;
|
|
328
319
|
var paramIndex = object.params.indexOf(param);
|
|
329
320
|
(0, _assert.ok)(paramIndex !== -1);
|
|
330
|
-
var sliced = p.slice(
|
|
331
|
-
(0, _assert.ok)(!sliced.includes(o));
|
|
321
|
+
var sliced = p.slice(0, pIndex);
|
|
332
322
|
var isReferenced = true;
|
|
333
323
|
var i = 0;
|
|
334
324
|
|
|
@@ -342,7 +332,7 @@ function isFunctionParameter(o, p) {
|
|
|
342
332
|
break;
|
|
343
333
|
}
|
|
344
334
|
|
|
345
|
-
if (node.type == "
|
|
335
|
+
if (node.type == "Property" && node.key === down && sliced[i + 2] && sliced[i + 2].type == "ObjectPattern") {
|
|
346
336
|
isReferenced = false;
|
|
347
337
|
break;
|
|
348
338
|
}
|
|
@@ -365,7 +355,7 @@ function getFunctionParameters(object, parents) {
|
|
|
365
355
|
var locations = [];
|
|
366
356
|
(0, _traverse.walk)(object.params, [object, ...parents], (o, p) => {
|
|
367
357
|
if (o.type == "Identifier") {
|
|
368
|
-
if (isFunctionParameter(o, p)) {
|
|
358
|
+
if (isFunctionParameter(o, p, object)) {
|
|
369
359
|
locations.push([o, p]);
|
|
370
360
|
}
|
|
371
361
|
}
|
package/dist/util/insert.js
CHANGED
|
@@ -21,7 +21,6 @@ exports.prepend = prepend;
|
|
|
21
21
|
exports.append = append;
|
|
22
22
|
exports.clone = clone;
|
|
23
23
|
exports.isForInitialize = isForInitialize;
|
|
24
|
-
exports.isInBranch = isInBranch;
|
|
25
24
|
|
|
26
25
|
var _assert = require("assert");
|
|
27
26
|
|
|
@@ -151,27 +150,15 @@ function getDefiningContext(o, p) {
|
|
|
151
150
|
return getVarContext(o, p);
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
function getReferencingContexts(o, p) {
|
|
153
|
+
function getReferencingContexts(o, p, info) {
|
|
155
154
|
(0, _identifiers.validateChain)(o, p);
|
|
156
155
|
(0, _assert.ok)(o.type == "Identifier");
|
|
157
|
-
var info = (0, _identifiers.getIdentifierInfo)(o, p);
|
|
158
|
-
(0, _assert.ok)(info.spec.isReferenced);
|
|
159
|
-
var assignmentPatternIndex = p.findIndex(x => x.type == "AssignmentPattern");
|
|
160
|
-
|
|
161
|
-
if (assignmentPatternIndex != -1) {
|
|
162
|
-
if (p[assignmentPatternIndex].right == (p[assignmentPatternIndex - 1] || o)) {
|
|
163
|
-
var sliced = p.slice(assignmentPatternIndex);
|
|
164
|
-
var fnIndex = sliced.findIndex(x => isFunction(x));
|
|
165
|
-
var associatedFn = sliced[fnIndex];
|
|
166
156
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return isLexContext(associatedFn.body) ? [associatedFn, associatedFn.body] : [associatedFn];
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
157
|
+
if (!info) {
|
|
158
|
+
info = (0, _identifiers.getIdentifierInfo)(o, p);
|
|
173
159
|
}
|
|
174
160
|
|
|
161
|
+
(0, _assert.ok)(info.spec.isReferenced);
|
|
175
162
|
return [getVarContext(o, p), getLexContext(o, p)];
|
|
176
163
|
}
|
|
177
164
|
|
|
@@ -328,36 +315,15 @@ function isForInitialize(o, p) {
|
|
|
328
315
|
|
|
329
316
|
if (forIndex !== -1) {
|
|
330
317
|
if (p[forIndex].type == "ForStatement") {
|
|
331
|
-
if (p[forIndex].init == p[forIndex - 1] || o) {
|
|
318
|
+
if (p[forIndex].init == (p[forIndex - 1] || o)) {
|
|
332
319
|
return "initializer";
|
|
333
320
|
}
|
|
334
321
|
} else {
|
|
335
|
-
if (p[forIndex].left == p[forIndex - 1] || o) {
|
|
322
|
+
if (p[forIndex].left == (p[forIndex - 1] || o)) {
|
|
336
323
|
return "left-hand";
|
|
337
324
|
}
|
|
338
325
|
}
|
|
339
326
|
}
|
|
340
327
|
|
|
341
328
|
return false;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function isInBranch(object, parents, context) {
|
|
345
|
-
(0, _assert.ok)(object);
|
|
346
|
-
(0, _assert.ok)(parents);
|
|
347
|
-
(0, _assert.ok)(context);
|
|
348
|
-
(0, _assert.ok)(parents.includes(context));
|
|
349
|
-
var definingContext = parents[0].type == "FunctionDeclaration" && parents[0].id == object ? getVarContext(parents[0], parents.slice(1)) : getVarContext(object, parents);
|
|
350
|
-
var contextIndex = parents.findIndex(x => x === context);
|
|
351
|
-
var slicedParents = parents.slice(0, contextIndex);
|
|
352
|
-
(0, _assert.ok)(!slicedParents.includes(object), "slicedParents includes object");
|
|
353
|
-
var slicedTypes = new Set(slicedParents.map(x => x.type));
|
|
354
|
-
var isBranch = definingContext !== context;
|
|
355
|
-
|
|
356
|
-
if (!isBranch) {
|
|
357
|
-
if (["IfStatement", "ForStatement", "ForInStatement", "ForOfStatement", "WhileStatement", "DoWhileStatement", "SwitchStatement", "ConditionalExpression", "LogicalExpression", "TryStatement", "ChainExpression", "BinaryExpression", "FunctionExpression", "FunctionDeclaration", "ArrowFunctionExpression", "ClassExpression", "ClassDeclaration"].find(x => slicedTypes.has(x))) {
|
|
358
|
-
isBranch = true;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return isBranch;
|
|
363
329
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isLexicalScope = isLexicalScope;
|
|
7
|
+
exports.getLexicalScope = getLexicalScope;
|
|
8
|
+
|
|
9
|
+
var _traverse = require("../traverse");
|
|
10
|
+
|
|
11
|
+
function isLexicalScope(object) {
|
|
12
|
+
return (0, _traverse.isBlock)(object) || object.type == "SwitchCase";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getLexicalScope(object, parents) {
|
|
16
|
+
return [object, ...parents].find(node => isLexicalScope(node));
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-confuser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "JavaScript Obfuscation Tool.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "MichaelXF",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"acorn": "^8.
|
|
25
|
+
"acorn": "^8.5.0",
|
|
26
26
|
"escodegen": "^2.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
package/src/options.ts
CHANGED
|
@@ -224,7 +224,7 @@ export interface ObfuscateOptions {
|
|
|
224
224
|
/**
|
|
225
225
|
* ### `stringConcealing`
|
|
226
226
|
*
|
|
227
|
-
* [String Concealing](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-concealing) involves encoding strings to conceal plain-text values. (`true/false`)
|
|
227
|
+
* [String Concealing](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-concealing) involves encoding strings to conceal plain-text values. (`true/false/0-1`)
|
|
228
228
|
*
|
|
229
229
|
* `"console"` -> `decrypt('<~@rH7+Dert~>')`
|
|
230
230
|
*
|
|
@@ -237,7 +237,7 @@ export interface ObfuscateOptions {
|
|
|
237
237
|
/**
|
|
238
238
|
* ### `stringEncoding`
|
|
239
239
|
*
|
|
240
|
-
* [String Encoding](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-encoding) transforms a string into an encoded representation. (`true/false`)
|
|
240
|
+
* [String Encoding](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-encoding) transforms a string into an encoded representation. (`true/false/0-1`)
|
|
241
241
|
*
|
|
242
242
|
* `"console"` -> `'\x63\x6f\x6e\x73\x6f\x6c\x65'`
|
|
243
243
|
*
|
|
@@ -252,7 +252,7 @@ export interface ObfuscateOptions {
|
|
|
252
252
|
/**
|
|
253
253
|
* ### `stringSplitting`
|
|
254
254
|
*
|
|
255
|
-
* [String Splitting](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-splitting) splits your strings into multiple expressions. (`true/false`)
|
|
255
|
+
* [String Splitting](https://docs.jscrambler.com/code-integrity/documentation/transformations/string-splitting) splits your strings into multiple expressions. (`true/false/0-1`)
|
|
256
256
|
*
|
|
257
257
|
* `"console"` -> `String.fromCharCode(99) + 'ons' + 'ole'`
|
|
258
258
|
*
|
|
@@ -447,6 +447,17 @@ export interface ObfuscateOptions {
|
|
|
447
447
|
calculator?: ProbabilityMap<boolean>;
|
|
448
448
|
|
|
449
449
|
lock?: {
|
|
450
|
+
/**
|
|
451
|
+
* ### `lock.selfDefending`
|
|
452
|
+
*
|
|
453
|
+
* Prevents the use of code beautifiers or formatters against your code.
|
|
454
|
+
*
|
|
455
|
+
* [Identical to Obfuscator.io's Self Defending](https://github.com/javascript-obfuscator/javascript-obfuscator#selfdefending)
|
|
456
|
+
*
|
|
457
|
+
* [See all settings here](https://github.com/MichaelXF/js-confuser/blob/master/README.md#options)
|
|
458
|
+
*/
|
|
459
|
+
selfDefending?: boolean;
|
|
460
|
+
|
|
450
461
|
/**
|
|
451
462
|
* ### `lock.antiDebug`
|
|
452
463
|
*
|
|
@@ -692,6 +703,7 @@ const validProperties = new Set([
|
|
|
692
703
|
"shuffle",
|
|
693
704
|
"stack",
|
|
694
705
|
"verbose",
|
|
706
|
+
"globalVariables",
|
|
695
707
|
"debugComments",
|
|
696
708
|
]);
|
|
697
709
|
|
|
@@ -837,6 +849,10 @@ export async function correctOptions(
|
|
|
837
849
|
options.globalVariables = new Set(Object.keys(options.globalVariables));
|
|
838
850
|
}
|
|
839
851
|
|
|
852
|
+
if (options.lock && options.lock.selfDefending) {
|
|
853
|
+
options.compact = true; // self defending forcibly enables this
|
|
854
|
+
}
|
|
855
|
+
|
|
840
856
|
// options.globalVariables was never used.
|
|
841
857
|
// GlobalConcealing implicitly determines a global to be a variable referenced but never defined or modified.
|
|
842
858
|
if (!options.hasOwnProperty("globalVariables")) {
|
package/src/parser.ts
CHANGED
package/src/presets.ts
CHANGED
|
@@ -43,11 +43,11 @@ const highPreset: ObfuscateOptions = {
|
|
|
43
43
|
renameVariables: true,
|
|
44
44
|
renameGlobals: true,
|
|
45
45
|
shuffle: { hash: 0.5, true: 0.5 },
|
|
46
|
+
stack: true,
|
|
46
47
|
stringConcealing: true,
|
|
47
48
|
stringCompression: true,
|
|
48
49
|
stringEncoding: true,
|
|
49
50
|
stringSplitting: 0.75,
|
|
50
|
-
stack: true,
|
|
51
51
|
|
|
52
52
|
// Use at own risk
|
|
53
53
|
eval: false,
|
|
@@ -68,7 +68,6 @@ const mediumPreset: ObfuscateOptions = {
|
|
|
68
68
|
deadCode: 0.025,
|
|
69
69
|
dispatcher: 0.75,
|
|
70
70
|
duplicateLiteralsRemoval: 0.5,
|
|
71
|
-
flatten: true,
|
|
72
71
|
globalConcealing: true,
|
|
73
72
|
identifierGenerator: "randomized",
|
|
74
73
|
minify: true,
|
|
@@ -78,6 +77,7 @@ const mediumPreset: ObfuscateOptions = {
|
|
|
78
77
|
renameVariables: true,
|
|
79
78
|
renameGlobals: true,
|
|
80
79
|
shuffle: true,
|
|
80
|
+
stack: 0.5,
|
|
81
81
|
stringConcealing: true,
|
|
82
82
|
stringSplitting: 0.25,
|
|
83
83
|
};
|
|
@@ -34,104 +34,100 @@ export default class Calculator extends Transform {
|
|
|
34
34
|
this.gen = this.getGenerator();
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
apply(tree) {
|
|
38
|
+
super.apply(tree);
|
|
39
|
+
|
|
40
|
+
if (Object.keys(this.ops).length == 0) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var opArg = this.getPlaceholder();
|
|
45
|
+
var leftArg = this.getPlaceholder();
|
|
46
|
+
var rightArg = this.getPlaceholder();
|
|
47
|
+
var switchCases = [];
|
|
48
|
+
|
|
49
|
+
Object.keys(this.ops).forEach((operator) => {
|
|
50
|
+
var code = this.ops[operator];
|
|
51
|
+
|
|
52
|
+
var factory =
|
|
53
|
+
operator == "&&" || operator == "||"
|
|
54
|
+
? LogicalExpression
|
|
55
|
+
: BinaryExpression;
|
|
56
|
+
|
|
57
|
+
var body = [
|
|
58
|
+
ReturnStatement(
|
|
59
|
+
factory(operator, Identifier(leftArg), Identifier(rightArg))
|
|
60
|
+
),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
switchCases.push(SwitchCase(Literal(code), body));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
var func = FunctionDeclaration(
|
|
67
|
+
this.calculatorFn,
|
|
68
|
+
[opArg, leftArg, rightArg].map((x) => Identifier(x)),
|
|
69
|
+
[SwitchStatement(Identifier(opArg), switchCases)]
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
prepend(tree, func);
|
|
73
|
+
}
|
|
74
|
+
|
|
37
75
|
match(object: Node, parents: Node[]) {
|
|
38
|
-
return object.type == "
|
|
76
|
+
return object.type == "BinaryExpression";
|
|
39
77
|
}
|
|
40
78
|
|
|
41
79
|
transform(object: Node, parents: Node[]) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (Object.keys(this.ops).length == 0) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
var opArg = this.getPlaceholder();
|
|
51
|
-
var leftArg = this.getPlaceholder();
|
|
52
|
-
var rightArg = this.getPlaceholder();
|
|
53
|
-
var switchCases = [];
|
|
54
|
-
|
|
55
|
-
Object.keys(this.ops).forEach((operator) => {
|
|
56
|
-
var code = this.ops[operator];
|
|
57
|
-
|
|
58
|
-
var factory =
|
|
59
|
-
operator == "&&" || operator == "||"
|
|
60
|
-
? LogicalExpression
|
|
61
|
-
: BinaryExpression;
|
|
62
|
-
|
|
63
|
-
var body = [
|
|
64
|
-
ReturnStatement(
|
|
65
|
-
factory(operator, Identifier(leftArg), Identifier(rightArg))
|
|
66
|
-
),
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
switchCases.push(SwitchCase(Literal(code), body));
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
var func = FunctionDeclaration(
|
|
73
|
-
this.calculatorFn,
|
|
74
|
-
[opArg, leftArg, rightArg].map((x) => Identifier(x)),
|
|
75
|
-
[SwitchStatement(Identifier(opArg), switchCases)]
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
prepend(block, func);
|
|
79
|
-
};
|
|
80
|
+
var operator = object.operator;
|
|
81
|
+
var allowedOperators = new Set(["+", "-", "*", "/"]);
|
|
82
|
+
if (!allowedOperators.has(operator)) {
|
|
83
|
+
return;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
var myPrecedence =
|
|
87
|
+
OPERATOR_PRECEDENCE[operator] +
|
|
88
|
+
Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100;
|
|
89
|
+
var precedences = parents.map(
|
|
90
|
+
(x) =>
|
|
91
|
+
x.type == "BinaryExpression" &&
|
|
92
|
+
OPERATOR_PRECEDENCE[x.operator] +
|
|
93
|
+
Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// corrupt AST
|
|
97
|
+
if (precedences.find((x) => x >= myPrecedence)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (
|
|
101
|
+
parents.find((x) => x.$dispatcherSkip || x.type == "BinaryExpression")
|
|
102
|
+
) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return;
|
|
106
|
+
return () => {
|
|
107
|
+
if (typeof this.ops[operator] !== "number") {
|
|
108
|
+
var newState;
|
|
109
|
+
do {
|
|
110
|
+
newState = getRandomInteger(
|
|
111
|
+
-1000,
|
|
112
|
+
1000 + Object.keys(this.ops).length * 5
|
|
113
|
+
);
|
|
114
|
+
} while (this.statesUsed.has(newState));
|
|
115
|
+
|
|
116
|
+
ok(!isNaN(newState));
|
|
117
|
+
|
|
118
|
+
this.statesUsed.add(newState);
|
|
119
|
+
this.ops[operator] = newState;
|
|
120
|
+
this.log(operator, `calc(${newState}, left, right)`);
|
|
104
121
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
1000 + Object.keys(this.ops).length * 5
|
|
116
|
-
);
|
|
117
|
-
} while (this.statesUsed.has(newState));
|
|
118
|
-
|
|
119
|
-
ok(!isNaN(newState));
|
|
120
|
-
|
|
121
|
-
this.statesUsed.add(newState);
|
|
122
|
-
this.ops[operator] = newState;
|
|
123
|
-
this.log(operator, `calc(${newState}, left, right)`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
this.replace(
|
|
127
|
-
object,
|
|
128
|
-
CallExpression(Identifier(this.calculatorFn), [
|
|
129
|
-
Literal(this.ops[operator]),
|
|
130
|
-
{ ...object.left },
|
|
131
|
-
{ ...object.right },
|
|
132
|
-
])
|
|
133
|
-
);
|
|
134
|
-
};
|
|
135
|
-
}
|
|
122
|
+
|
|
123
|
+
this.replace(
|
|
124
|
+
object,
|
|
125
|
+
CallExpression(Identifier(this.calculatorFn), [
|
|
126
|
+
Literal(this.ops[operator]),
|
|
127
|
+
object.left,
|
|
128
|
+
object.right,
|
|
129
|
+
])
|
|
130
|
+
);
|
|
131
|
+
};
|
|
136
132
|
}
|
|
137
133
|
}
|