node-automator 1.1.0 → 1.2.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/commands/deobfuscate.js +15 -0
- package/commands/mgr.js +2 -0
- package/package.json +7 -2
- package/utils/deobfuscator/deobfuscator.js +97 -0
- package/utils/deobfuscator/helpers/declaration.js +57 -0
- package/utils/deobfuscator/helpers/expression.js +36 -0
- package/utils/deobfuscator/helpers/misc.js +38 -0
- package/utils/deobfuscator/helpers/strings/decoders/base64StringDecoder.js +50 -0
- package/utils/deobfuscator/helpers/strings/decoders/basicStringDecoder.js +28 -0
- package/utils/deobfuscator/helpers/strings/decoders/rc4StringDecoder.js +77 -0
- package/utils/deobfuscator/helpers/strings/decoders/stringDecoder.js +22 -0
- package/utils/deobfuscator/helpers/strings/rotation/rotation.js +216 -0
- package/utils/deobfuscator/helpers/strings/util/util.js +30 -0
- package/utils/deobfuscator/helpers/variable.js +140 -0
- package/utils/deobfuscator/index.js +25 -0
- package/utils/deobfuscator/transformations/config.js +43 -0
- package/utils/deobfuscator/transformations/controlFlow/controlFlowRecoverer.js +160 -0
- package/utils/deobfuscator/transformations/controlFlow/deadBranchRemover.js +120 -0
- package/utils/deobfuscator/transformations/controlFlow/sequenceSplitter.js +168 -0
- package/utils/deobfuscator/transformations/expressions/expressionSimplifier.js +288 -0
- package/utils/deobfuscator/transformations/objects/objectPacker.js +125 -0
- package/utils/deobfuscator/transformations/objects/objectSimplifier.js +71 -0
- package/utils/deobfuscator/transformations/objects/proxyObject.js +144 -0
- package/utils/deobfuscator/transformations/properties/propertySimplifier.js +70 -0
- package/utils/deobfuscator/transformations/proxyFunctions/proxyFunction.js +151 -0
- package/utils/deobfuscator/transformations/proxyFunctions/proxyFunctionInliner.js +46 -0
- package/utils/deobfuscator/transformations/strings/stringRevealer.js +381 -0
- package/utils/deobfuscator/transformations/transformation.js +28 -0
- package/utils/deobfuscator/transformations/variables/constantPropagator.js +73 -0
- package/utils/deobfuscator/transformations/variables/reassignmentRemover.js +78 -0
- package/utils/deobfuscator/transformations/variables/unusedVariableRemover.js +93 -0
- package/utils/request_tool.js +2 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.SequenceSplitter = void 0;
|
|
30
|
+
const t = __importStar(require("@babel/types"));
|
|
31
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
32
|
+
const transformation_1 = require("../transformation");
|
|
33
|
+
class SequenceSplitter extends transformation_1.Transformation {
|
|
34
|
+
/**
|
|
35
|
+
* Executes the transformation.
|
|
36
|
+
* @param log The log function.
|
|
37
|
+
*/
|
|
38
|
+
execute(log) {
|
|
39
|
+
const self = this;
|
|
40
|
+
(0, traverse_1.default)(this.ast, {
|
|
41
|
+
ConditionalExpression(path) {
|
|
42
|
+
if (path.parentPath && path.parentPath.isExpressionStatement()) {
|
|
43
|
+
const replacement = t.ifStatement(path.node.test, t.expressionStatement(path.node.consequent), t.expressionStatement(path.node.alternate));
|
|
44
|
+
if (path.parentPath.parentPath &&
|
|
45
|
+
path.parentPath.parentPath.key == 'alternate' &&
|
|
46
|
+
path.parentPath.parentPath.isBlockStatement() &&
|
|
47
|
+
path.parentPath.parentPath.node.body.length == 1) {
|
|
48
|
+
path.parentPath.parentPath.replaceWith(replacement);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
path.parentPath.replaceWith(replacement);
|
|
52
|
+
}
|
|
53
|
+
path.skip();
|
|
54
|
+
self.setChanged();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
LogicalExpression(path) {
|
|
58
|
+
if ((path.node.operator == '&&' || path.node.operator == '||') &&
|
|
59
|
+
path.parentPath &&
|
|
60
|
+
path.parentPath.isExpressionStatement()) {
|
|
61
|
+
const test = path.node.operator == '&&'
|
|
62
|
+
? path.node.left
|
|
63
|
+
: t.unaryExpression('!', path.node.left);
|
|
64
|
+
const replacement = t.ifStatement(test, t.expressionStatement(path.node.right));
|
|
65
|
+
if (path.parentPath.parentPath &&
|
|
66
|
+
path.parentPath.parentPath.key == 'alternate' &&
|
|
67
|
+
path.parentPath.parentPath.isBlockStatement() &&
|
|
68
|
+
path.parentPath.parentPath.node.body.length == 1) {
|
|
69
|
+
path.parentPath.parentPath.replaceWith(replacement);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
path.parentPath.replaceWith(replacement);
|
|
73
|
+
}
|
|
74
|
+
path.skip();
|
|
75
|
+
self.setChanged();
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
['ForStatement|WhileStatement|DoWhileStatement'](path) {
|
|
79
|
+
if (!t.isBlockStatement(path.node.body)) {
|
|
80
|
+
path.node.body = t.blockStatement([path.node.body]);
|
|
81
|
+
self.setChanged();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
IfStatement(path) {
|
|
85
|
+
if (!t.isBlockStatement(path.node.consequent)) {
|
|
86
|
+
path.node.consequent = t.blockStatement([path.node.consequent]);
|
|
87
|
+
self.setChanged();
|
|
88
|
+
}
|
|
89
|
+
if (path.node.alternate &&
|
|
90
|
+
!t.isBlockStatement(path.node.alternate) &&
|
|
91
|
+
!t.isIfStatement(path.node.alternate)) {
|
|
92
|
+
path.node.alternate = t.blockStatement([path.node.alternate]);
|
|
93
|
+
self.setChanged();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
VariableDeclaration(path) {
|
|
97
|
+
if (path.node.declarations.length > 1) {
|
|
98
|
+
const replacements = path.node.declarations.map(d => t.variableDeclaration(path.node.kind, [d]));
|
|
99
|
+
if (path.parentPath &&
|
|
100
|
+
path.parentPath.isForStatement() &&
|
|
101
|
+
path.parentKey == 'init') {
|
|
102
|
+
const lastDeclaration = replacements.pop();
|
|
103
|
+
path.parentPath.insertBefore(replacements);
|
|
104
|
+
path.parentPath.node.init = lastDeclaration;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
path.replaceWithMultiple(replacements);
|
|
108
|
+
}
|
|
109
|
+
self.setChanged();
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
SequenceExpression(path) {
|
|
113
|
+
const expressions = path.node.expressions;
|
|
114
|
+
if (expressions.length == 1) {
|
|
115
|
+
path.replaceWith(expressions[0]);
|
|
116
|
+
self.setChanged();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
let outerPath = path;
|
|
120
|
+
while (!t.isStatement(outerPath.node)) {
|
|
121
|
+
const parent = outerPath.parentPath;
|
|
122
|
+
if (!parent) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if ((parent.isConditionalExpression() &&
|
|
126
|
+
(outerPath.key == 'consequent' || outerPath.key == 'alternate')) ||
|
|
127
|
+
(parent.isLogicalExpression() && outerPath.key == 'right') ||
|
|
128
|
+
(parent.isForStatement() &&
|
|
129
|
+
(outerPath.key == 'test' || outerPath.key == 'update')) ||
|
|
130
|
+
(parent.isDoWhileStatement() && outerPath.key == 'test')) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
outerPath = parent;
|
|
134
|
+
}
|
|
135
|
+
const lastExpression = expressions[expressions.length - 1];
|
|
136
|
+
if (self.isExcluded(lastExpression)) {
|
|
137
|
+
const firstExpressions = expressions.splice(0, expressions.length - 2);
|
|
138
|
+
if (firstExpressions.length > 0) {
|
|
139
|
+
const expressionStatements = firstExpressions.map(e => t.expressionStatement(e));
|
|
140
|
+
outerPath.insertBefore(expressionStatements);
|
|
141
|
+
self.setChanged();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const lastExpression = expressions.splice(expressions.length - 1, 1)[0];
|
|
146
|
+
const expressionStatements = expressions.map(e => t.expressionStatement(e));
|
|
147
|
+
outerPath.insertBefore(expressionStatements);
|
|
148
|
+
path.replaceWith(lastExpression);
|
|
149
|
+
self.setChanged();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return this.hasChanged();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns whether a node that is the last in a sequence expression
|
|
157
|
+
* is excluded from being placed on its own.
|
|
158
|
+
* @param node The AST node.
|
|
159
|
+
* @returns Whether.
|
|
160
|
+
*/
|
|
161
|
+
isExcluded(node) {
|
|
162
|
+
return t.isIdentifier(node) && node.name == 'eval';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.SequenceSplitter = SequenceSplitter;
|
|
166
|
+
SequenceSplitter.properties = {
|
|
167
|
+
key: 'sequenceSplitting'
|
|
168
|
+
};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.ExpressionSimplifier = void 0;
|
|
30
|
+
const t = __importStar(require("@babel/types"));
|
|
31
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
32
|
+
const transformation_1 = require("../transformation");
|
|
33
|
+
const expression_1 = require("../../helpers/expression");
|
|
34
|
+
class ExpressionSimplifier extends transformation_1.Transformation {
|
|
35
|
+
/**
|
|
36
|
+
* Executes the transformation.
|
|
37
|
+
* @param log The log function.
|
|
38
|
+
*/
|
|
39
|
+
execute(log) {
|
|
40
|
+
const self = this;
|
|
41
|
+
(0, traverse_1.default)(this.ast, {
|
|
42
|
+
['UnaryExpression|BinaryExpression'](path) {
|
|
43
|
+
const replacement = path.isUnaryExpression()
|
|
44
|
+
? self.simplifyUnaryExpression(path.node)
|
|
45
|
+
: self.simplifyBinaryExpression(path.node);
|
|
46
|
+
if (replacement) {
|
|
47
|
+
path.replaceWith(replacement);
|
|
48
|
+
self.setChanged();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return this.hasChanged();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Attempts to simplify an expression.
|
|
56
|
+
* @param expression The expression.
|
|
57
|
+
* @returns The expression in the simplest form possible.
|
|
58
|
+
*/
|
|
59
|
+
simplifyExpression(expression) {
|
|
60
|
+
if (t.isUnaryExpression(expression) || t.isBinaryExpression(expression)) {
|
|
61
|
+
const replacement = t.isUnaryExpression(expression)
|
|
62
|
+
? this.simplifyUnaryExpression(expression)
|
|
63
|
+
: this.simplifyBinaryExpression(expression);
|
|
64
|
+
return replacement || expression;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
return expression;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Attempts to simplify a unary expression.
|
|
72
|
+
* @param expression The unary expression.
|
|
73
|
+
* @returns The simplified expression or undefined.
|
|
74
|
+
*/
|
|
75
|
+
simplifyUnaryExpression(expression) {
|
|
76
|
+
if (!ExpressionSimplifier.RESOLVABLE_UNARY_OPERATORS.has(expression.operator)) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
else if ((0, expression_1.isNegativeNumericLiteral)(expression)) {
|
|
80
|
+
return undefined; // avoid trying to simplify negative numbers
|
|
81
|
+
}
|
|
82
|
+
const argument = this.simplifyExpression(expression.argument);
|
|
83
|
+
if (this.isResolvableExpression(argument)) {
|
|
84
|
+
const argumentValue = this.getResolvableExpressionValue(argument);
|
|
85
|
+
const value = this.applyUnaryOperation(expression.operator, argumentValue);
|
|
86
|
+
return this.convertValueToExpression(value);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Attempts to simplify a binary expression.
|
|
94
|
+
* @param expression The binary expression.
|
|
95
|
+
* @returns The simplified expression or undefined.
|
|
96
|
+
*/
|
|
97
|
+
simplifyBinaryExpression(expression) {
|
|
98
|
+
if (!t.isExpression(expression.left) ||
|
|
99
|
+
!ExpressionSimplifier.RESOLVABLE_BINARY_OPERATORS.has(expression.operator)) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
const left = this.simplifyExpression(expression.left);
|
|
103
|
+
const right = this.simplifyExpression(expression.right);
|
|
104
|
+
if (this.isResolvableExpression(left) && this.isResolvableExpression(right)) {
|
|
105
|
+
const leftValue = this.getResolvableExpressionValue(left);
|
|
106
|
+
const rightValue = this.getResolvableExpressionValue(right);
|
|
107
|
+
const value = this.applyBinaryOperation(expression.operator, leftValue, rightValue);
|
|
108
|
+
return this.convertValueToExpression(value);
|
|
109
|
+
}
|
|
110
|
+
else if (expression.operator == '-' && (0, expression_1.isNegativeNumericLiteral)(right)) {
|
|
111
|
+
// convert (- -a) to +a (as long as a is a number)
|
|
112
|
+
expression.right = right.argument;
|
|
113
|
+
expression.operator = '+';
|
|
114
|
+
return expression;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Applies a unary operation.
|
|
122
|
+
* @param operator The operator.
|
|
123
|
+
* @param argument The argument value.
|
|
124
|
+
* @returns The resultant value.
|
|
125
|
+
*/
|
|
126
|
+
applyUnaryOperation(operator, argument) {
|
|
127
|
+
switch (operator) {
|
|
128
|
+
case '-':
|
|
129
|
+
return -argument;
|
|
130
|
+
case '+':
|
|
131
|
+
return +argument;
|
|
132
|
+
case '!':
|
|
133
|
+
return !argument;
|
|
134
|
+
case '~':
|
|
135
|
+
return ~argument;
|
|
136
|
+
case 'typeof':
|
|
137
|
+
return typeof argument;
|
|
138
|
+
case 'void':
|
|
139
|
+
return void argument;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Applies a binary operation.
|
|
144
|
+
* @param operator The resolvable binary operator.
|
|
145
|
+
* @param left The value of the left expression.
|
|
146
|
+
* @param right The value of the right expression.
|
|
147
|
+
* @returns The resultant value.
|
|
148
|
+
*/
|
|
149
|
+
applyBinaryOperation(operator, left, right) {
|
|
150
|
+
switch (operator) {
|
|
151
|
+
case '==':
|
|
152
|
+
return left == right;
|
|
153
|
+
case '!=':
|
|
154
|
+
return left != right;
|
|
155
|
+
case '===':
|
|
156
|
+
return left === right;
|
|
157
|
+
case '!==':
|
|
158
|
+
return left !== right;
|
|
159
|
+
case '<':
|
|
160
|
+
return left < right;
|
|
161
|
+
case '<=':
|
|
162
|
+
return left <= right;
|
|
163
|
+
case '>':
|
|
164
|
+
return left > right;
|
|
165
|
+
case '>=':
|
|
166
|
+
return left >= right;
|
|
167
|
+
case '<<':
|
|
168
|
+
return left << right;
|
|
169
|
+
case '>>':
|
|
170
|
+
return left >> right;
|
|
171
|
+
case '>>>':
|
|
172
|
+
return left >>> right;
|
|
173
|
+
case '+':
|
|
174
|
+
return left + right;
|
|
175
|
+
case '-':
|
|
176
|
+
return left - right;
|
|
177
|
+
case '*':
|
|
178
|
+
return left * right;
|
|
179
|
+
case '/':
|
|
180
|
+
return left / right;
|
|
181
|
+
case '%':
|
|
182
|
+
return left % right;
|
|
183
|
+
case '**':
|
|
184
|
+
return left ** right;
|
|
185
|
+
case '|':
|
|
186
|
+
return left | right;
|
|
187
|
+
case '^':
|
|
188
|
+
return left ^ right;
|
|
189
|
+
case '&':
|
|
190
|
+
return left & right;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Gets the real value from a resolvable expression.
|
|
195
|
+
* @param expression The resolvable expression.
|
|
196
|
+
* @returns The value.
|
|
197
|
+
*/
|
|
198
|
+
getResolvableExpressionValue(expression) {
|
|
199
|
+
switch (expression.type) {
|
|
200
|
+
case 'NumericLiteral':
|
|
201
|
+
case 'StringLiteral':
|
|
202
|
+
case 'BooleanLiteral':
|
|
203
|
+
case 'DecimalLiteral':
|
|
204
|
+
case 'BigIntLiteral':
|
|
205
|
+
return expression.value;
|
|
206
|
+
case 'UnaryExpression':
|
|
207
|
+
return -this.getResolvableExpressionValue(expression.argument);
|
|
208
|
+
case 'NullLiteral':
|
|
209
|
+
return null;
|
|
210
|
+
case 'Identifier':
|
|
211
|
+
return undefined;
|
|
212
|
+
case 'ArrayExpression':
|
|
213
|
+
return [];
|
|
214
|
+
case 'ObjectExpression':
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Attempts to convert a value of unknown type to an expression node.
|
|
220
|
+
* @param value The value.
|
|
221
|
+
* @returns The expression or undefined.
|
|
222
|
+
*/
|
|
223
|
+
convertValueToExpression(value) {
|
|
224
|
+
switch (typeof value) {
|
|
225
|
+
case 'string':
|
|
226
|
+
return t.stringLiteral(value);
|
|
227
|
+
case 'number':
|
|
228
|
+
return value >= 0
|
|
229
|
+
? t.numericLiteral(value)
|
|
230
|
+
: t.unaryExpression('-', t.numericLiteral(Math.abs(value)));
|
|
231
|
+
case 'boolean':
|
|
232
|
+
return t.booleanLiteral(value);
|
|
233
|
+
case 'bigint':
|
|
234
|
+
return t.bigIntLiteral(value.toString());
|
|
235
|
+
case 'undefined':
|
|
236
|
+
return t.identifier('undefined');
|
|
237
|
+
default:
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Returns whether a node is a resolvable expression that can be
|
|
243
|
+
* evaluated safely.
|
|
244
|
+
* @param node The AST node.
|
|
245
|
+
* @returns Whether.
|
|
246
|
+
*/
|
|
247
|
+
isResolvableExpression(node) {
|
|
248
|
+
return ((t.isLiteral(node) && !t.isRegExpLiteral(node) && !t.isTemplateLiteral(node)) ||
|
|
249
|
+
(t.isUnaryExpression(node) && node.operator == '-' && t.isLiteral(node.argument)) ||
|
|
250
|
+
(t.isIdentifier(node) && node.name == 'undefined') ||
|
|
251
|
+
(t.isArrayExpression(node) && node.elements.length == 0) ||
|
|
252
|
+
(t.isObjectExpression(node) && node.properties.length == 0));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.ExpressionSimplifier = ExpressionSimplifier;
|
|
256
|
+
ExpressionSimplifier.properties = {
|
|
257
|
+
key: 'expressionSimplification'
|
|
258
|
+
};
|
|
259
|
+
ExpressionSimplifier.RESOLVABLE_UNARY_OPERATORS = new Set([
|
|
260
|
+
'-',
|
|
261
|
+
'+',
|
|
262
|
+
'!',
|
|
263
|
+
'~',
|
|
264
|
+
'typeof',
|
|
265
|
+
'void'
|
|
266
|
+
]);
|
|
267
|
+
ExpressionSimplifier.RESOLVABLE_BINARY_OPERATORS = new Set([
|
|
268
|
+
'==',
|
|
269
|
+
'!=',
|
|
270
|
+
'===',
|
|
271
|
+
'!==',
|
|
272
|
+
'<',
|
|
273
|
+
'<=',
|
|
274
|
+
'>',
|
|
275
|
+
'>=',
|
|
276
|
+
'<<',
|
|
277
|
+
'>>',
|
|
278
|
+
'>>>',
|
|
279
|
+
'+',
|
|
280
|
+
'-',
|
|
281
|
+
'*',
|
|
282
|
+
'/',
|
|
283
|
+
'%',
|
|
284
|
+
'**',
|
|
285
|
+
'|',
|
|
286
|
+
'^',
|
|
287
|
+
'&'
|
|
288
|
+
]);
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.ObjectPacker = void 0;
|
|
30
|
+
const t = __importStar(require("@babel/types"));
|
|
31
|
+
const variable_1 = require("../../helpers/variable");
|
|
32
|
+
const transformation_1 = require("../transformation");
|
|
33
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
34
|
+
class ObjectPacker extends transformation_1.Transformation {
|
|
35
|
+
/**
|
|
36
|
+
* Executes the transformation.
|
|
37
|
+
* @param log The log function.
|
|
38
|
+
*/
|
|
39
|
+
execute(log) {
|
|
40
|
+
const self = this;
|
|
41
|
+
(0, traverse_1.default)(this.ast, {
|
|
42
|
+
enter(path) {
|
|
43
|
+
const variable = (0, variable_1.findConstantVariable)(path, isEmptyObjectExpression);
|
|
44
|
+
if (!variable) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const parentPath = path.getStatementParent();
|
|
48
|
+
if (!parentPath ||
|
|
49
|
+
parentPath.parentPath == undefined ||
|
|
50
|
+
typeof parentPath.key != 'number') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const statements = parentPath.parentPath.node[parentPath.parentKey];
|
|
54
|
+
let numRemoved = 0;
|
|
55
|
+
for (let i = parentPath.key + 1; i < statements.length; i++) {
|
|
56
|
+
const node = statements[i];
|
|
57
|
+
if (t.isExpressionStatement(node) &&
|
|
58
|
+
self.isPropertyAssignment(node.expression, variable.name)) {
|
|
59
|
+
// replace multiple properties assigned in same statement
|
|
60
|
+
if (self.isPropertyAssignment(node.expression.right, variable.name)) {
|
|
61
|
+
const properties = [node.expression.left];
|
|
62
|
+
let right = node.expression.right;
|
|
63
|
+
while (self.isPropertyAssignment(right, variable.name)) {
|
|
64
|
+
properties.push(right.left);
|
|
65
|
+
right = right.right;
|
|
66
|
+
}
|
|
67
|
+
// don't duplicate expressions with side effects
|
|
68
|
+
if (!t.isLiteral(right)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
for (const { property } of properties) {
|
|
72
|
+
const isComputed = !t.isStringLiteral(property) &&
|
|
73
|
+
!t.isNumericLiteral(property) &&
|
|
74
|
+
!t.isIdentifier(property);
|
|
75
|
+
const objectProperty = t.objectProperty(property, right, isComputed);
|
|
76
|
+
variable.expression.properties.push(objectProperty);
|
|
77
|
+
self.setChanged();
|
|
78
|
+
numRemoved++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const key = node.expression.left.property;
|
|
83
|
+
const isComputed = !t.isStringLiteral(key) &&
|
|
84
|
+
!t.isNumericLiteral(key) &&
|
|
85
|
+
!t.isIdentifier(key);
|
|
86
|
+
const property = t.objectProperty(key, node.expression.right, isComputed);
|
|
87
|
+
variable.expression.properties.push(property);
|
|
88
|
+
self.setChanged();
|
|
89
|
+
numRemoved++;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
statements.splice(parentPath.key + 1, numRemoved);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return this.hasChanged();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Returns whether a node is setting a property on a given object.
|
|
103
|
+
* @param node The AST node.
|
|
104
|
+
* @param objectName The name of the object.
|
|
105
|
+
* @returns Whether.
|
|
106
|
+
*/
|
|
107
|
+
isPropertyAssignment(node, objectName) {
|
|
108
|
+
return (t.isAssignmentExpression(node) &&
|
|
109
|
+
t.isMemberExpression(node.left) &&
|
|
110
|
+
t.isIdentifier(node.left.object) &&
|
|
111
|
+
node.left.object.name == objectName);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.ObjectPacker = ObjectPacker;
|
|
115
|
+
ObjectPacker.properties = {
|
|
116
|
+
key: 'objectPacking'
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Returns whether a node is an empty object expression.
|
|
120
|
+
* @param node The node.
|
|
121
|
+
* @returns Whether.
|
|
122
|
+
*/
|
|
123
|
+
const isEmptyObjectExpression = (node) => {
|
|
124
|
+
return t.isObjectExpression(node) && node.properties.length == 0;
|
|
125
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ObjectSimplifier = void 0;
|
|
7
|
+
const transformation_1 = require("../transformation");
|
|
8
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
9
|
+
const variable_1 = require("../../helpers/variable");
|
|
10
|
+
const proxyObject_1 = require("./proxyObject");
|
|
11
|
+
const misc_1 = require("../../helpers/misc");
|
|
12
|
+
class ObjectSimplifier extends transformation_1.Transformation {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new transformation.
|
|
15
|
+
* @param ast The AST.
|
|
16
|
+
* @param config The config.
|
|
17
|
+
*/
|
|
18
|
+
constructor(ast, config) {
|
|
19
|
+
super(ast, config);
|
|
20
|
+
this.config = config;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Executes the transformation.
|
|
24
|
+
* @param log The log function.
|
|
25
|
+
* @returns Whether any changes were made.
|
|
26
|
+
*/
|
|
27
|
+
execute(log) {
|
|
28
|
+
const self = this;
|
|
29
|
+
const usages = [];
|
|
30
|
+
let depth = 0;
|
|
31
|
+
(0, traverse_1.default)(this.ast, {
|
|
32
|
+
enter(path) {
|
|
33
|
+
(0, misc_1.setProperty)(path, 'depth', depth++);
|
|
34
|
+
const variable = (0, variable_1.findConstantVariable)(path, proxyObject_1.isProxyObjectExpression);
|
|
35
|
+
if (!variable) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// check if object values are modified
|
|
39
|
+
for (const referencePath of variable.binding.referencePaths) {
|
|
40
|
+
if (referencePath.parentPath &&
|
|
41
|
+
referencePath.parentPath.isMemberExpression() &&
|
|
42
|
+
referencePath.parentPath.parentPath &&
|
|
43
|
+
referencePath.parentPath.parentPath.isAssignmentExpression() &&
|
|
44
|
+
referencePath.parentPath.key == 'left') {
|
|
45
|
+
if (!self.config.unsafeReplace) {
|
|
46
|
+
log(`Not replacing object ${variable.name} as it is modified`);
|
|
47
|
+
path.skip();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const proxyObject = new proxyObject_1.ProxyObject(variable);
|
|
53
|
+
proxyObject.process();
|
|
54
|
+
usages.push(...proxyObject.getUsages().map(p => [p, proxyObject]));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// replace innermost usages first
|
|
58
|
+
usages.sort((a, b) => (0, misc_1.getProperty)(b[0], 'depth') - (0, misc_1.getProperty)(a[0], 'depth'));
|
|
59
|
+
for (const [path, proxyObject] of usages) {
|
|
60
|
+
if (proxyObject.replaceUsage(path)) {
|
|
61
|
+
this.setChanged();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return this.hasChanged();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.ObjectSimplifier = ObjectSimplifier;
|
|
68
|
+
ObjectSimplifier.properties = {
|
|
69
|
+
key: 'objectSimplification',
|
|
70
|
+
rebuildScopeTree: true
|
|
71
|
+
};
|