js-confuser 2.0.0-alpha.4 → 2.0.0-alpha.5
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/dist/constants.js +2 -4
- package/dist/index.js +6 -1
- package/dist/transforms/controlFlowFlattening.js +64 -47
- package/dist/transforms/plugin.js +12 -3
- package/dist/utils/ast-utils.js +15 -33
- package/package.json +1 -1
- package/src/constants.ts +2 -2
- package/src/index.ts +6 -1
- package/src/templates/integrityTemplate.ts +1 -1
- package/src/transforms/controlFlowFlattening.ts +88 -74
- package/src/transforms/plugin.ts +19 -9
- package/src/utils/ast-utils.ts +10 -21
package/dist/constants.js
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.variableFunctionName = exports.reservedObjectPrototype = exports.reservedNodeModuleIdentifiers = exports.reservedKeywords = exports.reservedIdentifiers = exports.
|
|
7
|
-
var predictableFunctionTag = exports.predictableFunctionTag = "__JS_PREDICT__";
|
|
8
|
-
|
|
6
|
+
exports.variableFunctionName = exports.reservedObjectPrototype = exports.reservedNodeModuleIdentifiers = exports.reservedKeywords = exports.reservedIdentifiers = exports.placeholderVariablePrefix = exports.noRenameVariablePrefix = exports.WITH_STATEMENT = exports.UNSAFE = exports.SKIP = exports.PREDICTABLE = exports.NO_RENAME = exports.NO_REMOVE = exports.MULTI_TRANSFORM = exports.GEN_NODE = exports.FN_LENGTH = void 0;
|
|
9
7
|
/**
|
|
10
8
|
* A function is 'unsafe' if it requires 'eval', 'arguments' or 'this'
|
|
11
9
|
*
|
|
@@ -89,6 +87,6 @@ var reservedObjectPrototype = exports.reservedObjectPrototype = new Set(["toStri
|
|
|
89
87
|
/**
|
|
90
88
|
* For Zero Width generator - Mangled variable names
|
|
91
89
|
*/
|
|
92
|
-
var reservedKeywords = exports.reservedKeywords = ["if", "in", "for", "let", "new", "try", "var", "case", "else", "null", "break", "catch", "class", "const", "super", "throw", "while", "yield", "delete", "export", "import", "public", "return", "switch", "default", "finally", "private", "continue", "debugger", "function", "arguments", "protected", "instanceof", "await", "async",
|
|
90
|
+
var reservedKeywords = exports.reservedKeywords = ["if", "in", "do", "for", "let", "new", "try", "var", "case", "else", "null", "with", "break", "catch", "class", "const", "super", "throw", "while", "yield", "delete", "export", "import", "public", "return", "switch", "default", "finally", "private", "continue", "debugger", "function", "arguments", "protected", "instanceof", "await", "async",
|
|
93
91
|
// new key words and other fun stuff :P
|
|
94
92
|
"NaN", "undefined", "true", "false", "typeof", "this", "static", "void", "of"];
|
package/dist/index.js
CHANGED
|
@@ -119,8 +119,13 @@ function _obfuscateWithProfiler() {
|
|
|
119
119
|
changeData: {}
|
|
120
120
|
};
|
|
121
121
|
transformMap[log.currentTransform] = entry;
|
|
122
|
-
|
|
122
|
+
|
|
123
|
+
// (JS-Confuser.com can run performance benchmark tests here)
|
|
123
124
|
(_profiler$callback = _profiler.callback) === null || _profiler$callback === void 0 || _profiler$callback.call(_profiler, log, entry, ast);
|
|
125
|
+
|
|
126
|
+
// The profiler.callback() function may take a long time to execute,
|
|
127
|
+
// so we need to update the currentTransformTime here for accurate profiling.
|
|
128
|
+
currentTransformTime = performance.now();
|
|
124
129
|
}
|
|
125
130
|
});
|
|
126
131
|
obfuscator.plugins.forEach(function (_ref) {
|
|
@@ -154,7 +154,6 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
154
154
|
if (functionPath.node.async || functionPath.node.generator) return;
|
|
155
155
|
}
|
|
156
156
|
programOrFunctionPath.scope.crawl();
|
|
157
|
-
var blockFnParent = (0, _astUtils.getParentFunctionOrProgram)(blockPath);
|
|
158
157
|
var hasIllegalNode = false;
|
|
159
158
|
var bindingNames = new Set();
|
|
160
159
|
blockPath.traverse({
|
|
@@ -204,6 +203,7 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
204
203
|
return withIdentifier("state_".concat(i));
|
|
205
204
|
});
|
|
206
205
|
var argVar = withIdentifier("_arg");
|
|
206
|
+
var usedArgVar = false;
|
|
207
207
|
var _didReturnVar = withIdentifier("return");
|
|
208
208
|
var basicBlocks = new Map();
|
|
209
209
|
|
|
@@ -220,11 +220,6 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
220
220
|
var withProperty = isDebug ? "with" : scopeNameGen.generate(false);
|
|
221
221
|
var withMemberExpression = new _template["default"]("".concat(scopeVar.name, "[\"").concat(withProperty, "\"]")).expression();
|
|
222
222
|
withMemberExpression.object[_constants.NO_RENAME] = cffIndex;
|
|
223
|
-
|
|
224
|
-
// Create 'resetWith' function - Safely resets the 'with' object to none
|
|
225
|
-
var resetWithProperty = isDebug ? "resetWith" : scopeNameGen.generate(false);
|
|
226
|
-
var resetWithMemberExpression = new _template["default"]("".concat(scopeVar.name, "[\"").concat(resetWithProperty, "\"]")).expression();
|
|
227
|
-
resetWithMemberExpression.object[_constants.NO_RENAME] = cffIndex;
|
|
228
223
|
var ScopeManager = /*#__PURE__*/function () {
|
|
229
224
|
function ScopeManager(scope, initializingBasicBlock) {
|
|
230
225
|
_classCallCheck(this, ScopeManager);
|
|
@@ -234,14 +229,17 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
234
229
|
_defineProperty(this, "nameGen", addWithStatement ? me.obfuscator.nameGen : new _NameGen.NameGen(me.options.identifierGenerator));
|
|
235
230
|
this.scope = scope;
|
|
236
231
|
this.initializingBasicBlock = initializingBasicBlock;
|
|
237
|
-
this.propertyName = isDebug ? "_" + scopeCounter++ : scopeNameGen.generate();
|
|
232
|
+
this.propertyName = isDebug ? "_" + cffIndex + "_" + scopeCounter++ : scopeNameGen.generate();
|
|
238
233
|
}
|
|
239
234
|
return _createClass(ScopeManager, [{
|
|
240
235
|
key: "findBestWithDiscriminant",
|
|
241
236
|
value: function findBestWithDiscriminant(basicBlock) {
|
|
242
237
|
var _this$parent;
|
|
238
|
+
// This initializing block is forbidden to have a with discriminant
|
|
239
|
+
// (As no previous code is able to prepare the with discriminant)
|
|
243
240
|
if (basicBlock !== this.initializingBasicBlock) {
|
|
244
|
-
|
|
241
|
+
// If no variables were defined in this scope, don't use it
|
|
242
|
+
if (Object.keys(this.scope.bindings).length > 0) return this;
|
|
245
243
|
}
|
|
246
244
|
return (_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.findBestWithDiscriminant(basicBlock);
|
|
247
245
|
}
|
|
@@ -290,7 +288,8 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
290
288
|
}, {
|
|
291
289
|
key: "getMemberExpression",
|
|
292
290
|
value: function getMemberExpression(name) {
|
|
293
|
-
var
|
|
291
|
+
var object = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.getScopeObject();
|
|
292
|
+
var memberExpression = t.memberExpression(object, t.stringLiteral(name), true);
|
|
294
293
|
return memberExpression;
|
|
295
294
|
}
|
|
296
295
|
}, {
|
|
@@ -316,13 +315,6 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
316
315
|
for (var key in propertyMap) {
|
|
317
316
|
properties.push(t.objectProperty(t.stringLiteral(key), propertyMap[key], true));
|
|
318
317
|
}
|
|
319
|
-
if (this === mainScope) {
|
|
320
|
-
// Reset With logic
|
|
321
|
-
properties.push(t.objectProperty(t.stringLiteral(resetWithProperty), new _template["default"]("\n (function(newStateValues, alwaysUndefined){\n {withMemberExpression} = alwaysUndefined;\n {arrayPattern} = newStateValues\n })\n ").expression({
|
|
322
|
-
withMemberExpression: (0, _node.deepClone)(withMemberExpression),
|
|
323
|
-
arrayPattern: t.arrayPattern((0, _node.deepClone)(stateVars))
|
|
324
|
-
}), true));
|
|
325
|
-
}
|
|
326
318
|
return t.objectExpression(properties);
|
|
327
319
|
}
|
|
328
320
|
}, {
|
|
@@ -396,7 +388,7 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
396
388
|
return _createClass(BasicBlock, [{
|
|
397
389
|
key: "withDiscriminant",
|
|
398
390
|
get: function get() {
|
|
399
|
-
if (!this.allowWithDiscriminant) return
|
|
391
|
+
if (!this.allowWithDiscriminant) return;
|
|
400
392
|
return this.bestWithDiscriminant;
|
|
401
393
|
}
|
|
402
394
|
}, {
|
|
@@ -599,8 +591,9 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
599
591
|
fnTopBlock.body.unshift(t.expressionStatement(t.stringLiteral("Function " + statement.node.id.name + " -> Renamed to " + rename)));
|
|
600
592
|
}
|
|
601
593
|
|
|
602
|
-
// Unpack parameters
|
|
594
|
+
// Unpack parameters from the parameter 'argVar'
|
|
603
595
|
if (statement.node.params.length > 0) {
|
|
596
|
+
usedArgVar = true;
|
|
604
597
|
fnTopBlock.body.unshift(t.variableDeclaration("var", [t.variableDeclarator(t.arrayPattern(statement.node.params), (0, _node.deepClone)(argVar))]));
|
|
605
598
|
|
|
606
599
|
// Change bindings from 'param' to 'var'
|
|
@@ -838,6 +831,8 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
838
831
|
if (!(0, _astUtils.isVariableIdentifier)(path)) return;
|
|
839
832
|
if (me.isSkipped(path)) return;
|
|
840
833
|
if (path.node[_constants.NO_RENAME] === cffIndex) return;
|
|
834
|
+
// For identifiers using implicit with discriminant, skip
|
|
835
|
+
if (path.node[_constants.WITH_STATEMENT]) return;
|
|
841
836
|
var identifierName = path.node.name;
|
|
842
837
|
if (identifierName === gotoFunctionName) return;
|
|
843
838
|
var binding = path.scope.getBinding(identifierName);
|
|
@@ -847,22 +842,29 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
847
842
|
if (binding.kind === "var" || binding.kind === "let" || binding.kind === "const") {} else {
|
|
848
843
|
return;
|
|
849
844
|
}
|
|
850
|
-
|
|
851
|
-
// console.log("No binding found for " + identifierName);
|
|
852
|
-
|
|
853
845
|
var scopeManager = scopeToScopeManager.get(binding.scope);
|
|
854
846
|
if (!scopeManager) return;
|
|
855
847
|
var newName = scopeManager.getNewName(identifierName, path.node);
|
|
856
848
|
var memberExpression = scopeManager.getMemberExpression(newName);
|
|
857
849
|
scopeManager.isNotUsed = false;
|
|
850
|
+
|
|
851
|
+
// Scope object as with discriminant? Use identifier
|
|
852
|
+
if (typeof basicBlock.withDiscriminant === "undefined") {
|
|
853
|
+
var id = t.identifier(scopeManager.propertyName);
|
|
854
|
+
id[_constants.WITH_STATEMENT] = true;
|
|
855
|
+
id[_constants.NO_RENAME] = cffIndex;
|
|
856
|
+
memberExpression = scopeManager.getMemberExpression(newName, id);
|
|
857
|
+
}
|
|
858
858
|
if ((0, _astUtils.isDefiningIdentifier)(path)) {
|
|
859
859
|
(0, _astUtils.replaceDefiningIdentifierToMemberExpression)(path, memberExpression);
|
|
860
860
|
return;
|
|
861
861
|
}
|
|
862
862
|
if (!path.container) return;
|
|
863
|
-
var isModified = (0, _astUtils.isModifiedIdentifier)(path);
|
|
864
863
|
if (basicBlock.withDiscriminant && basicBlock.withDiscriminant === scopeManager && basicBlock.withDiscriminant.hasOwnName(identifierName)) {
|
|
865
|
-
|
|
864
|
+
// The defining mode must directly append to the scope object
|
|
865
|
+
// Subsequent uses can use the identifier
|
|
866
|
+
var isDefiningNode = path.node === binding.identifier;
|
|
867
|
+
if (!isDefiningNode) {
|
|
866
868
|
memberExpression = basicBlock.identifier(newName, scopeManager);
|
|
867
869
|
}
|
|
868
870
|
}
|
|
@@ -902,28 +904,28 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
902
904
|
var newStateValues = jumpBlock.stateValues,
|
|
903
905
|
newTotalState = jumpBlock.totalState;
|
|
904
906
|
var assignments = [];
|
|
905
|
-
var needsIndividualAssignments = true;
|
|
906
907
|
if (jumpBlock.withDiscriminant) {
|
|
907
908
|
assignments.push(t.assignmentExpression("=", (0, _node.deepClone)(withMemberExpression), jumpBlock.withDiscriminant.getScopeObject()));
|
|
908
909
|
} else if (basicBlock.withDiscriminant) {
|
|
909
|
-
|
|
910
|
-
|
|
910
|
+
// Reset the with discriminant to undefined using fake property
|
|
911
|
+
// scope["fake"] -> undefined
|
|
912
|
+
|
|
913
|
+
var fakeProperty = scopeNameGen.generate();
|
|
914
|
+
assignments.push(t.assignmentExpression("=", (0, _node.deepClone)(withMemberExpression), t.memberExpression((0, _node.deepClone)(scopeVar), t.stringLiteral(fakeProperty), true)));
|
|
911
915
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
assignment = t.assignmentExpression("+=", (0, _node.deepClone)(stateVars[_i8]), (0, _node.numericLiteral)(newValue - oldValue));
|
|
924
|
-
}
|
|
925
|
-
assignments.push(assignment);
|
|
916
|
+
for (var _i8 = 0; _i8 < stateVars.length; _i8++) {
|
|
917
|
+
var oldValue = currentStateValues[_i8];
|
|
918
|
+
var newValue = newStateValues[_i8];
|
|
919
|
+
|
|
920
|
+
// console.log(oldValue, newValue);
|
|
921
|
+
if (oldValue === newValue) continue; // No diff needed if the value doesn't change
|
|
922
|
+
|
|
923
|
+
var assignment = t.assignmentExpression("=", (0, _node.deepClone)(stateVars[_i8]), (0, _node.numericLiteral)(newValue));
|
|
924
|
+
if (!isDebug && addRelativeAssignments) {
|
|
925
|
+
// Use diffs to create confusing code
|
|
926
|
+
assignment = t.assignmentExpression("+=", (0, _node.deepClone)(stateVars[_i8]), (0, _node.numericLiteral)(newValue - oldValue));
|
|
926
927
|
}
|
|
928
|
+
assignments.push(assignment);
|
|
927
929
|
}
|
|
928
930
|
|
|
929
931
|
// Add debug label
|
|
@@ -1113,10 +1115,11 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
1113
1115
|
var switchStatement = t.labeledStatement(t.identifier(switchLabel), t.switchStatement(discriminant, switchCases));
|
|
1114
1116
|
var startStateValues = basicBlocks.get(startLabel).stateValues;
|
|
1115
1117
|
var endTotalState = basicBlocks.get(endLabel).totalState;
|
|
1116
|
-
var whileStatement = t.whileStatement(t.binaryExpression("!==", (0, _node.deepClone)(discriminant), (0, _node.numericLiteral)(endTotalState)), t.blockStatement([t.withStatement(new _template["default"]("{withDiscriminant} || {}").expression({
|
|
1117
|
-
withDiscriminant: (0, _node.deepClone)(withMemberExpression)
|
|
1118
|
+
var whileStatement = t.whileStatement(t.binaryExpression("!==", (0, _node.deepClone)(discriminant), (0, _node.numericLiteral)(endTotalState)), t.blockStatement([t.withStatement(new _template["default"]("{withDiscriminant} || {scopeVar}").expression({
|
|
1119
|
+
withDiscriminant: (0, _node.deepClone)(withMemberExpression),
|
|
1120
|
+
scopeVar: (0, _node.deepClone)(scopeVar)
|
|
1118
1121
|
}), t.blockStatement([switchStatement]))]));
|
|
1119
|
-
var parameters = [].concat(_toConsumableArray(stateVars), [
|
|
1122
|
+
var parameters = [].concat(_toConsumableArray(stateVars), [scopeVar, argVar]).map(function (id) {
|
|
1120
1123
|
return (0, _node.deepClone)(id);
|
|
1121
1124
|
});
|
|
1122
1125
|
var parametersNames = parameters.map(function (id) {
|
|
@@ -1152,24 +1155,38 @@ var _default = exports["default"] = function _default(_ref) {
|
|
|
1152
1155
|
(0, _assert.ok)(false);
|
|
1153
1156
|
}
|
|
1154
1157
|
}
|
|
1158
|
+
|
|
1159
|
+
// Ensure parameter is added (No effect if not added in this case)
|
|
1155
1160
|
} catch (err) {
|
|
1156
1161
|
_iterator4.e(err);
|
|
1157
1162
|
} finally {
|
|
1158
1163
|
_iterator4.f();
|
|
1159
1164
|
}
|
|
1165
|
+
usedArgVar = true;
|
|
1160
1166
|
Object.assign(fn, new _template["default"]("\n (function (...".concat(argumentsRestName, "){\n ").concat(isDebug ? "\"Calling ".concat(originalFnName, ", Label: ").concat(fnLabel, "\";") : "", "\n return {callExpression}\n })\n \n ")).expression({
|
|
1161
1167
|
callExpression: t.callExpression((0, _node.deepClone)(mainFnName), argumentsNodes)
|
|
1162
1168
|
}));
|
|
1163
1169
|
}
|
|
1164
1170
|
var startProgramObjectExpression = basicBlocks.get(startLabel).scopeManager.getObjectExpression(startLabel);
|
|
1165
1171
|
var mainParameters = parameters;
|
|
1166
|
-
|
|
1167
|
-
|
|
1172
|
+
|
|
1173
|
+
// First state values use the default parameter for initialization
|
|
1174
|
+
// function main(..., scope = { mainScope: {} }, ...){...}
|
|
1175
|
+
mainParameters.splice(mainParameters.findIndex(function (p) {
|
|
1176
|
+
return p.name === scopeVar.name;
|
|
1177
|
+
}), 1, t.assignmentPattern((0, _node.deepClone)(scopeVar), startProgramObjectExpression));
|
|
1178
|
+
|
|
1179
|
+
// Remove parameter 'argVar' if never used (No function calls obfuscated)
|
|
1180
|
+
if (!usedArgVar) {
|
|
1181
|
+
mainParameters.pop();
|
|
1182
|
+
}
|
|
1168
1183
|
var mainFnDeclaration = t.functionDeclaration((0, _node.deepClone)(mainFnName), parameters, t.blockStatement([whileStatement]));
|
|
1184
|
+
|
|
1185
|
+
// The main function is always called with same number of arguments
|
|
1169
1186
|
mainFnDeclaration[_constants.PREDICTABLE] = true;
|
|
1170
|
-
var startProgramExpression = t.callExpression((0, _node.deepClone)(mainFnName),
|
|
1187
|
+
var startProgramExpression = t.callExpression((0, _node.deepClone)(mainFnName), _toConsumableArray(startStateValues.map(function (stateValue) {
|
|
1171
1188
|
return (0, _node.numericLiteral)(stateValue);
|
|
1172
|
-
}))
|
|
1189
|
+
})));
|
|
1173
1190
|
var _resultVar = withIdentifier("result");
|
|
1174
1191
|
var isTopLevel = blockPath.isProgram();
|
|
1175
1192
|
var allowReturns = !isTopLevel && blockPath.find(function (p) {
|
|
@@ -89,10 +89,19 @@ var PluginInstance = exports.PluginInstance = /*#__PURE__*/function () {
|
|
|
89
89
|
fnName: this.setFunctionLengthName
|
|
90
90
|
})));
|
|
91
91
|
}
|
|
92
|
+
var createCallArguments = function createCallArguments(node) {
|
|
93
|
+
var args = [node];
|
|
94
|
+
|
|
95
|
+
// 1 is the default value in the setFunction template, can exclude it
|
|
96
|
+
if (originalLength !== 1) {
|
|
97
|
+
args.push((0, _node.numericLiteral)(originalLength));
|
|
98
|
+
}
|
|
99
|
+
return args;
|
|
100
|
+
};
|
|
92
101
|
if (t.isFunctionDeclaration(path.node)) {
|
|
93
|
-
(0, _astUtils.prepend)(path.parentPath, t.expressionStatement(t.callExpression(t.identifier(this.setFunctionLengthName),
|
|
102
|
+
(0, _astUtils.prepend)(path.parentPath, t.expressionStatement(t.callExpression(t.identifier(this.setFunctionLengthName), createCallArguments(t.identifier(path.node.id.name)))));
|
|
94
103
|
} else if (t.isFunctionExpression(path.node) || t.isArrowFunctionExpression(path.node)) {
|
|
95
|
-
path.replaceWith(t.callExpression(t.identifier(this.setFunctionLengthName),
|
|
104
|
+
path.replaceWith(t.callExpression(t.identifier(this.setFunctionLengthName), createCallArguments(path.node)));
|
|
96
105
|
} else {
|
|
97
106
|
// TODO
|
|
98
107
|
}
|
|
@@ -154,7 +163,7 @@ var PluginInstance = exports.PluginInstance = /*#__PURE__*/function () {
|
|
|
154
163
|
for (var _len3 = arguments.length, messages = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
155
164
|
messages[_key3] = arguments[_key3];
|
|
156
165
|
}
|
|
157
|
-
throw new Error("[".concat(this.name, "] ").concat(messages.join("
|
|
166
|
+
throw new Error("[".concat(this.name, "] ").concat(messages.join(" ")));
|
|
158
167
|
}
|
|
159
168
|
}]);
|
|
160
169
|
}();
|
package/dist/utils/ast-utils.js
CHANGED
|
@@ -212,24 +212,6 @@ function getMemberExpressionPropertyAsString(member) {
|
|
|
212
212
|
}
|
|
213
213
|
return null; // If the property cannot be determined
|
|
214
214
|
}
|
|
215
|
-
function registerPaths(paths) {
|
|
216
|
-
var _iterator3 = _createForOfIteratorHelper(paths),
|
|
217
|
-
_step3;
|
|
218
|
-
try {
|
|
219
|
-
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
220
|
-
var path = _step3.value;
|
|
221
|
-
if (path.isVariableDeclaration() && path.node.kind === "var") {
|
|
222
|
-
getParentFunctionOrProgram(path).scope.registerDeclaration(path);
|
|
223
|
-
}
|
|
224
|
-
path.scope.registerDeclaration(path);
|
|
225
|
-
}
|
|
226
|
-
} catch (err) {
|
|
227
|
-
_iterator3.e(err);
|
|
228
|
-
} finally {
|
|
229
|
-
_iterator3.f();
|
|
230
|
-
}
|
|
231
|
-
return paths;
|
|
232
|
-
}
|
|
233
215
|
function nodeListToNodes(nodesIn) {
|
|
234
216
|
var nodes = [];
|
|
235
217
|
if (Array.isArray(nodesIn[0])) {
|
|
@@ -258,11 +240,11 @@ function append(path) {
|
|
|
258
240
|
if (listParent.isProgram()) {
|
|
259
241
|
var lastExpression = listParent.get("body").at(-1);
|
|
260
242
|
if (lastExpression.isExpressionStatement()) {
|
|
261
|
-
return
|
|
243
|
+
return lastExpression.insertBefore(nodes);
|
|
262
244
|
}
|
|
263
245
|
}
|
|
264
246
|
if (listParent.isSwitchCase()) {
|
|
265
|
-
return
|
|
247
|
+
return listParent.pushContainer("consequent", nodes);
|
|
266
248
|
}
|
|
267
249
|
if (listParent.isFunction()) {
|
|
268
250
|
var body = listParent.get("body");
|
|
@@ -272,10 +254,10 @@ function append(path) {
|
|
|
272
254
|
}
|
|
273
255
|
}
|
|
274
256
|
(0, _assert.ok)(body.isBlockStatement());
|
|
275
|
-
return
|
|
257
|
+
return body.pushContainer("body", nodes);
|
|
276
258
|
}
|
|
277
259
|
(0, _assert.ok)(listParent.isBlock());
|
|
278
|
-
return
|
|
260
|
+
return listParent.pushContainer("body", nodes);
|
|
279
261
|
}
|
|
280
262
|
|
|
281
263
|
/**
|
|
@@ -304,28 +286,28 @@ function prepend(path) {
|
|
|
304
286
|
// Filter out import declarations
|
|
305
287
|
var _body = listParent.get("body");
|
|
306
288
|
var afterImport = 0;
|
|
307
|
-
var
|
|
308
|
-
|
|
289
|
+
var _iterator3 = _createForOfIteratorHelper(_body),
|
|
290
|
+
_step3;
|
|
309
291
|
try {
|
|
310
|
-
for (
|
|
311
|
-
var stmt =
|
|
292
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
293
|
+
var stmt = _step3.value;
|
|
312
294
|
if (!stmt.isImportDeclaration()) {
|
|
313
295
|
break;
|
|
314
296
|
}
|
|
315
297
|
afterImport++;
|
|
316
298
|
}
|
|
317
299
|
} catch (err) {
|
|
318
|
-
|
|
300
|
+
_iterator3.e(err);
|
|
319
301
|
} finally {
|
|
320
|
-
|
|
302
|
+
_iterator3.f();
|
|
321
303
|
}
|
|
322
304
|
if (afterImport === 0) {
|
|
323
305
|
// No import declarations, so we can safely unshift everything
|
|
324
|
-
return
|
|
306
|
+
return listParent.unshiftContainer("body", nodes);
|
|
325
307
|
}
|
|
326
308
|
|
|
327
309
|
// Insert the nodes after the last import declaration
|
|
328
|
-
return
|
|
310
|
+
return _body[afterImport - 1].insertAfter(nodes);
|
|
329
311
|
}
|
|
330
312
|
if (listParent.isFunction()) {
|
|
331
313
|
var body = listParent.get("body");
|
|
@@ -335,13 +317,13 @@ function prepend(path) {
|
|
|
335
317
|
}
|
|
336
318
|
}
|
|
337
319
|
(0, _assert.ok)(body.isBlockStatement());
|
|
338
|
-
return
|
|
320
|
+
return body.unshiftContainer("body", nodes);
|
|
339
321
|
}
|
|
340
322
|
if (listParent.isBlock()) {
|
|
341
|
-
return
|
|
323
|
+
return listParent.unshiftContainer("body", nodes);
|
|
342
324
|
}
|
|
343
325
|
if (listParent.isSwitchCase()) {
|
|
344
|
-
return
|
|
326
|
+
return listParent.unshiftContainer("consequent", nodes);
|
|
345
327
|
}
|
|
346
328
|
(0, _assert.ok)(false);
|
|
347
329
|
}
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export const predictableFunctionTag = "__JS_PREDICT__";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* A function is 'unsafe' if it requires 'eval', 'arguments' or 'this'
|
|
5
3
|
*
|
|
@@ -121,6 +119,7 @@ export const reservedObjectPrototype = new Set([
|
|
|
121
119
|
export const reservedKeywords = [
|
|
122
120
|
"if",
|
|
123
121
|
"in",
|
|
122
|
+
"do",
|
|
124
123
|
"for",
|
|
125
124
|
"let",
|
|
126
125
|
"new",
|
|
@@ -129,6 +128,7 @@ export const reservedKeywords = [
|
|
|
129
128
|
"case",
|
|
130
129
|
"else",
|
|
131
130
|
"null",
|
|
131
|
+
"with",
|
|
132
132
|
"break",
|
|
133
133
|
"catch",
|
|
134
134
|
"class",
|
package/src/index.ts
CHANGED
|
@@ -66,8 +66,13 @@ export async function obfuscateWithProfiler(
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
transformMap[log.currentTransform] = entry;
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
// (JS-Confuser.com can run performance benchmark tests here)
|
|
70
71
|
profiler.callback?.(log, entry, ast);
|
|
72
|
+
|
|
73
|
+
// The profiler.callback() function may take a long time to execute,
|
|
74
|
+
// so we need to update the currentTransformTime here for accurate profiling.
|
|
75
|
+
currentTransformTime = performance.now();
|
|
71
76
|
},
|
|
72
77
|
});
|
|
73
78
|
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
ensureComputedExpression,
|
|
6
6
|
getParentFunctionOrProgram,
|
|
7
7
|
isDefiningIdentifier,
|
|
8
|
-
isModifiedIdentifier,
|
|
9
8
|
isStrictMode,
|
|
10
9
|
isVariableIdentifier,
|
|
11
10
|
replaceDefiningIdentifierToMemberExpression,
|
|
@@ -163,8 +162,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
163
162
|
}
|
|
164
163
|
programOrFunctionPath.scope.crawl();
|
|
165
164
|
|
|
166
|
-
const blockFnParent = getParentFunctionOrProgram(blockPath);
|
|
167
|
-
|
|
168
165
|
let hasIllegalNode = false;
|
|
169
166
|
const bindingNames = new Set<string>();
|
|
170
167
|
blockPath.traverse({
|
|
@@ -231,6 +228,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
231
228
|
.map((_, i) => withIdentifier(`state_${i}`));
|
|
232
229
|
|
|
233
230
|
const argVar = withIdentifier("_arg");
|
|
231
|
+
let usedArgVar = false;
|
|
234
232
|
|
|
235
233
|
const didReturnVar = withIdentifier("return");
|
|
236
234
|
|
|
@@ -255,16 +253,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
255
253
|
).expression<t.MemberExpression>();
|
|
256
254
|
withMemberExpression.object[NO_RENAME] = cffIndex;
|
|
257
255
|
|
|
258
|
-
// Create 'resetWith' function - Safely resets the 'with' object to none
|
|
259
|
-
const resetWithProperty = isDebug
|
|
260
|
-
? "resetWith"
|
|
261
|
-
: scopeNameGen.generate(false);
|
|
262
|
-
|
|
263
|
-
const resetWithMemberExpression = new Template(
|
|
264
|
-
`${scopeVar.name}["${resetWithProperty}"]`
|
|
265
|
-
).expression<t.MemberExpression>();
|
|
266
|
-
resetWithMemberExpression.object[NO_RENAME] = cffIndex;
|
|
267
|
-
|
|
268
256
|
class ScopeManager {
|
|
269
257
|
isNotUsed = true;
|
|
270
258
|
requiresInitializing = true;
|
|
@@ -275,8 +263,11 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
275
263
|
: new NameGen(me.options.identifierGenerator);
|
|
276
264
|
|
|
277
265
|
findBestWithDiscriminant(basicBlock: BasicBlock): ScopeManager {
|
|
266
|
+
// This initializing block is forbidden to have a with discriminant
|
|
267
|
+
// (As no previous code is able to prepare the with discriminant)
|
|
278
268
|
if (basicBlock !== this.initializingBasicBlock) {
|
|
279
|
-
|
|
269
|
+
// If no variables were defined in this scope, don't use it
|
|
270
|
+
if (Object.keys(this.scope.bindings).length > 0) return this;
|
|
280
271
|
}
|
|
281
272
|
|
|
282
273
|
return this.parent?.findBestWithDiscriminant(basicBlock);
|
|
@@ -337,9 +328,12 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
337
328
|
: new Template(`({})`).expression();
|
|
338
329
|
}
|
|
339
330
|
|
|
340
|
-
getMemberExpression(
|
|
331
|
+
getMemberExpression(
|
|
332
|
+
name: string,
|
|
333
|
+
object: t.Expression = this.getScopeObject()
|
|
334
|
+
) {
|
|
341
335
|
const memberExpression = t.memberExpression(
|
|
342
|
-
|
|
336
|
+
object,
|
|
343
337
|
t.stringLiteral(name),
|
|
344
338
|
true
|
|
345
339
|
);
|
|
@@ -353,7 +347,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
353
347
|
public initializingBasicBlock: BasicBlock
|
|
354
348
|
) {
|
|
355
349
|
this.propertyName = isDebug
|
|
356
|
-
? "_" + scopeCounter++
|
|
350
|
+
? "_" + cffIndex + "_" + scopeCounter++
|
|
357
351
|
: scopeNameGen.generate();
|
|
358
352
|
}
|
|
359
353
|
|
|
@@ -390,25 +384,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
390
384
|
);
|
|
391
385
|
}
|
|
392
386
|
|
|
393
|
-
if (this === mainScope) {
|
|
394
|
-
// Reset With logic
|
|
395
|
-
properties.push(
|
|
396
|
-
t.objectProperty(
|
|
397
|
-
t.stringLiteral(resetWithProperty),
|
|
398
|
-
new Template(`
|
|
399
|
-
(function(newStateValues, alwaysUndefined){
|
|
400
|
-
{withMemberExpression} = alwaysUndefined;
|
|
401
|
-
{arrayPattern} = newStateValues
|
|
402
|
-
})
|
|
403
|
-
`).expression({
|
|
404
|
-
withMemberExpression: deepClone(withMemberExpression),
|
|
405
|
-
arrayPattern: t.arrayPattern(deepClone(stateVars)),
|
|
406
|
-
}),
|
|
407
|
-
true
|
|
408
|
-
)
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
387
|
return t.objectExpression(properties);
|
|
413
388
|
}
|
|
414
389
|
|
|
@@ -434,7 +409,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
434
409
|
bestWithDiscriminant: ScopeManager;
|
|
435
410
|
|
|
436
411
|
get withDiscriminant() {
|
|
437
|
-
if (!this.allowWithDiscriminant) return
|
|
412
|
+
if (!this.allowWithDiscriminant) return;
|
|
438
413
|
|
|
439
414
|
return this.bestWithDiscriminant;
|
|
440
415
|
}
|
|
@@ -774,8 +749,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
774
749
|
);
|
|
775
750
|
}
|
|
776
751
|
|
|
777
|
-
// Unpack parameters
|
|
752
|
+
// Unpack parameters from the parameter 'argVar'
|
|
778
753
|
if (statement.node.params.length > 0) {
|
|
754
|
+
usedArgVar = true;
|
|
779
755
|
fnTopBlock.body.unshift(
|
|
780
756
|
t.variableDeclaration("var", [
|
|
781
757
|
t.variableDeclarator(
|
|
@@ -1099,6 +1075,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1099
1075
|
if (!isVariableIdentifier(path)) return;
|
|
1100
1076
|
if (me.isSkipped(path)) return;
|
|
1101
1077
|
if ((path.node as NodeSymbol)[NO_RENAME] === cffIndex) return;
|
|
1078
|
+
// For identifiers using implicit with discriminant, skip
|
|
1079
|
+
if ((path.node as NodeSymbol)[WITH_STATEMENT]) return;
|
|
1102
1080
|
|
|
1103
1081
|
const identifierName = path.node.name;
|
|
1104
1082
|
if (identifierName === gotoFunctionName) return;
|
|
@@ -1117,8 +1095,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1117
1095
|
return;
|
|
1118
1096
|
}
|
|
1119
1097
|
|
|
1120
|
-
// console.log("No binding found for " + identifierName);
|
|
1121
|
-
|
|
1122
1098
|
var scopeManager = scopeToScopeManager.get(binding.scope);
|
|
1123
1099
|
if (!scopeManager) return;
|
|
1124
1100
|
|
|
@@ -1132,6 +1108,18 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1132
1108
|
|
|
1133
1109
|
scopeManager.isNotUsed = false;
|
|
1134
1110
|
|
|
1111
|
+
// Scope object as with discriminant? Use identifier
|
|
1112
|
+
if (typeof basicBlock.withDiscriminant === "undefined") {
|
|
1113
|
+
const id = t.identifier(scopeManager.propertyName);
|
|
1114
|
+
(id as NodeSymbol)[WITH_STATEMENT] = true;
|
|
1115
|
+
(id as NodeSymbol)[NO_RENAME] = cffIndex;
|
|
1116
|
+
|
|
1117
|
+
memberExpression = scopeManager.getMemberExpression(
|
|
1118
|
+
newName,
|
|
1119
|
+
id
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1135
1123
|
if (isDefiningIdentifier(path)) {
|
|
1136
1124
|
replaceDefiningIdentifierToMemberExpression(
|
|
1137
1125
|
path,
|
|
@@ -1142,14 +1130,16 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1142
1130
|
|
|
1143
1131
|
if (!path.container) return;
|
|
1144
1132
|
|
|
1145
|
-
var isModified = isModifiedIdentifier(path);
|
|
1146
|
-
|
|
1147
1133
|
if (
|
|
1148
1134
|
basicBlock.withDiscriminant &&
|
|
1149
1135
|
basicBlock.withDiscriminant === scopeManager &&
|
|
1150
1136
|
basicBlock.withDiscriminant.hasOwnName(identifierName)
|
|
1151
1137
|
) {
|
|
1152
|
-
|
|
1138
|
+
// The defining mode must directly append to the scope object
|
|
1139
|
+
// Subsequent uses can use the identifier
|
|
1140
|
+
const isDefiningNode = path.node === binding.identifier;
|
|
1141
|
+
|
|
1142
|
+
if (!isDefiningNode) {
|
|
1153
1143
|
memberExpression = basicBlock.identifier(
|
|
1154
1144
|
newName,
|
|
1155
1145
|
scopeManager
|
|
@@ -1218,7 +1208,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1218
1208
|
} = jumpBlock;
|
|
1219
1209
|
|
|
1220
1210
|
const assignments: t.Expression[] = [];
|
|
1221
|
-
let needsIndividualAssignments = true;
|
|
1222
1211
|
|
|
1223
1212
|
if (jumpBlock.withDiscriminant) {
|
|
1224
1213
|
assignments.push(
|
|
@@ -1229,39 +1218,47 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1229
1218
|
)
|
|
1230
1219
|
);
|
|
1231
1220
|
} else if (basicBlock.withDiscriminant) {
|
|
1221
|
+
// Reset the with discriminant to undefined using fake property
|
|
1222
|
+
// scope["fake"] -> undefined
|
|
1223
|
+
|
|
1224
|
+
const fakeProperty = scopeNameGen.generate();
|
|
1225
|
+
|
|
1232
1226
|
assignments.push(
|
|
1233
|
-
t.
|
|
1234
|
-
|
|
1235
|
-
|
|
1227
|
+
t.assignmentExpression(
|
|
1228
|
+
"=",
|
|
1229
|
+
deepClone(withMemberExpression),
|
|
1230
|
+
t.memberExpression(
|
|
1231
|
+
deepClone(scopeVar),
|
|
1232
|
+
t.stringLiteral(fakeProperty),
|
|
1233
|
+
true
|
|
1234
|
+
)
|
|
1235
|
+
)
|
|
1236
1236
|
);
|
|
1237
|
-
needsIndividualAssignments = false;
|
|
1238
1237
|
}
|
|
1239
1238
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
const newValue = newStateValues[i];
|
|
1239
|
+
for (let i = 0; i < stateVars.length; i++) {
|
|
1240
|
+
const oldValue = currentStateValues[i];
|
|
1241
|
+
const newValue = newStateValues[i];
|
|
1244
1242
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1243
|
+
// console.log(oldValue, newValue);
|
|
1244
|
+
if (oldValue === newValue) continue; // No diff needed if the value doesn't change
|
|
1247
1245
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1246
|
+
let assignment = t.assignmentExpression(
|
|
1247
|
+
"=",
|
|
1248
|
+
deepClone(stateVars[i]),
|
|
1249
|
+
numericLiteral(newValue)
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1252
|
+
if (!isDebug && addRelativeAssignments) {
|
|
1253
|
+
// Use diffs to create confusing code
|
|
1254
|
+
assignment = t.assignmentExpression(
|
|
1255
|
+
"+=",
|
|
1250
1256
|
deepClone(stateVars[i]),
|
|
1251
|
-
numericLiteral(newValue)
|
|
1257
|
+
numericLiteral(newValue - oldValue)
|
|
1252
1258
|
);
|
|
1253
|
-
|
|
1254
|
-
if (!isDebug && addRelativeAssignments) {
|
|
1255
|
-
// Use diffs to create confusing code
|
|
1256
|
-
assignment = t.assignmentExpression(
|
|
1257
|
-
"+=",
|
|
1258
|
-
deepClone(stateVars[i]),
|
|
1259
|
-
numericLiteral(newValue - oldValue)
|
|
1260
|
-
);
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
assignments.push(assignment);
|
|
1264
1259
|
}
|
|
1260
|
+
|
|
1261
|
+
assignments.push(assignment);
|
|
1265
1262
|
}
|
|
1266
1263
|
|
|
1267
1264
|
// Add debug label
|
|
@@ -1515,8 +1512,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1515
1512
|
),
|
|
1516
1513
|
t.blockStatement([
|
|
1517
1514
|
t.withStatement(
|
|
1518
|
-
new Template(`{withDiscriminant} || {}`).expression({
|
|
1515
|
+
new Template(`{withDiscriminant} || {scopeVar}`).expression({
|
|
1519
1516
|
withDiscriminant: deepClone(withMemberExpression),
|
|
1517
|
+
scopeVar: deepClone(scopeVar),
|
|
1520
1518
|
}),
|
|
1521
1519
|
t.blockStatement([switchStatement])
|
|
1522
1520
|
),
|
|
@@ -1525,8 +1523,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1525
1523
|
|
|
1526
1524
|
const parameters: t.Identifier[] = [
|
|
1527
1525
|
...stateVars,
|
|
1528
|
-
argVar,
|
|
1529
1526
|
scopeVar,
|
|
1527
|
+
argVar,
|
|
1530
1528
|
].map((id) => deepClone(id));
|
|
1531
1529
|
|
|
1532
1530
|
const parametersNames: string[] = parameters.map((id) => id.name);
|
|
@@ -1558,6 +1556,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1558
1556
|
}
|
|
1559
1557
|
}
|
|
1560
1558
|
|
|
1559
|
+
// Ensure parameter is added (No effect if not added in this case)
|
|
1560
|
+
usedArgVar = true;
|
|
1561
|
+
|
|
1561
1562
|
Object.assign(
|
|
1562
1563
|
fn,
|
|
1563
1564
|
new Template(`
|
|
@@ -1584,23 +1585,36 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1584
1585
|
.scopeManager.getObjectExpression(startLabel);
|
|
1585
1586
|
|
|
1586
1587
|
const mainParameters: t.FunctionDeclaration["params"] = parameters;
|
|
1587
|
-
const scopeParameter = mainParameters.pop() as t.Identifier;
|
|
1588
1588
|
|
|
1589
|
-
|
|
1590
|
-
|
|
1589
|
+
// First state values use the default parameter for initialization
|
|
1590
|
+
// function main(..., scope = { mainScope: {} }, ...){...}
|
|
1591
|
+
mainParameters.splice(
|
|
1592
|
+
(mainParameters as t.Identifier[]).findIndex(
|
|
1593
|
+
(p) => p.name === scopeVar.name
|
|
1594
|
+
),
|
|
1595
|
+
1,
|
|
1596
|
+
t.assignmentPattern(
|
|
1597
|
+
deepClone(scopeVar),
|
|
1598
|
+
startProgramObjectExpression
|
|
1599
|
+
)
|
|
1591
1600
|
);
|
|
1592
1601
|
|
|
1602
|
+
// Remove parameter 'argVar' if never used (No function calls obfuscated)
|
|
1603
|
+
if (!usedArgVar) {
|
|
1604
|
+
mainParameters.pop();
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1593
1607
|
const mainFnDeclaration = t.functionDeclaration(
|
|
1594
1608
|
deepClone(mainFnName),
|
|
1595
1609
|
parameters,
|
|
1596
1610
|
t.blockStatement([whileStatement])
|
|
1597
1611
|
);
|
|
1598
1612
|
|
|
1613
|
+
// The main function is always called with same number of arguments
|
|
1599
1614
|
(mainFnDeclaration as NodeSymbol)[PREDICTABLE] = true;
|
|
1600
1615
|
|
|
1601
1616
|
var startProgramExpression = t.callExpression(deepClone(mainFnName), [
|
|
1602
1617
|
...startStateValues.map((stateValue) => numericLiteral(stateValue)),
|
|
1603
|
-
t.identifier("undefined"),
|
|
1604
1618
|
]);
|
|
1605
1619
|
|
|
1606
1620
|
const resultVar = withIdentifier("result");
|
package/src/transforms/plugin.ts
CHANGED
|
@@ -97,14 +97,24 @@ export class PluginInstance {
|
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
const createCallArguments = (node: t.Expression): t.Expression[] => {
|
|
101
|
+
var args = [node];
|
|
102
|
+
|
|
103
|
+
// 1 is the default value in the setFunction template, can exclude it
|
|
104
|
+
if (originalLength !== 1) {
|
|
105
|
+
args.push(numericLiteral(originalLength));
|
|
106
|
+
}
|
|
107
|
+
return args;
|
|
108
|
+
};
|
|
109
|
+
|
|
100
110
|
if (t.isFunctionDeclaration(path.node)) {
|
|
101
111
|
prepend(
|
|
102
112
|
path.parentPath,
|
|
103
113
|
t.expressionStatement(
|
|
104
|
-
t.callExpression(
|
|
105
|
-
t.identifier(
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
t.callExpression(
|
|
115
|
+
t.identifier(this.setFunctionLengthName),
|
|
116
|
+
createCallArguments(t.identifier(path.node.id.name))
|
|
117
|
+
)
|
|
108
118
|
)
|
|
109
119
|
);
|
|
110
120
|
} else if (
|
|
@@ -112,10 +122,10 @@ export class PluginInstance {
|
|
|
112
122
|
t.isArrowFunctionExpression(path.node)
|
|
113
123
|
) {
|
|
114
124
|
path.replaceWith(
|
|
115
|
-
t.callExpression(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
t.callExpression(
|
|
126
|
+
t.identifier(this.setFunctionLengthName),
|
|
127
|
+
createCallArguments(path.node)
|
|
128
|
+
)
|
|
119
129
|
);
|
|
120
130
|
} else {
|
|
121
131
|
// TODO
|
|
@@ -158,6 +168,6 @@ export class PluginInstance {
|
|
|
158
168
|
* @param messages
|
|
159
169
|
*/
|
|
160
170
|
error(...messages: any[]): never {
|
|
161
|
-
throw new Error(`[${this.name}] ${messages.join("
|
|
171
|
+
throw new Error(`[${this.name}] ${messages.join(" ")}`);
|
|
162
172
|
}
|
|
163
173
|
}
|
package/src/utils/ast-utils.ts
CHANGED
|
@@ -215,17 +215,6 @@ export function getMemberExpressionPropertyAsString(
|
|
|
215
215
|
return null; // If the property cannot be determined
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
function registerPaths(paths: NodePath[]) {
|
|
219
|
-
for (var path of paths) {
|
|
220
|
-
if (path.isVariableDeclaration() && path.node.kind === "var") {
|
|
221
|
-
getParentFunctionOrProgram(path).scope.registerDeclaration(path);
|
|
222
|
-
}
|
|
223
|
-
path.scope.registerDeclaration(path);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return paths;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
218
|
function nodeListToNodes(nodesIn: (t.Statement | t.Statement[])[]) {
|
|
230
219
|
var nodes: t.Statement[] = [];
|
|
231
220
|
if (Array.isArray(nodesIn[0])) {
|
|
@@ -257,12 +246,12 @@ export function append(
|
|
|
257
246
|
if (listParent.isProgram()) {
|
|
258
247
|
var lastExpression = listParent.get("body").at(-1);
|
|
259
248
|
if (lastExpression.isExpressionStatement()) {
|
|
260
|
-
return
|
|
249
|
+
return lastExpression.insertBefore(nodes);
|
|
261
250
|
}
|
|
262
251
|
}
|
|
263
252
|
|
|
264
253
|
if (listParent.isSwitchCase()) {
|
|
265
|
-
return
|
|
254
|
+
return listParent.pushContainer("consequent", nodes);
|
|
266
255
|
}
|
|
267
256
|
|
|
268
257
|
if (listParent.isFunction()) {
|
|
@@ -278,11 +267,11 @@ export function append(
|
|
|
278
267
|
|
|
279
268
|
ok(body.isBlockStatement());
|
|
280
269
|
|
|
281
|
-
return
|
|
270
|
+
return body.pushContainer("body", nodes);
|
|
282
271
|
}
|
|
283
272
|
|
|
284
273
|
ok(listParent.isBlock());
|
|
285
|
-
return
|
|
274
|
+
return listParent.pushContainer("body", nodes);
|
|
286
275
|
}
|
|
287
276
|
|
|
288
277
|
/**
|
|
@@ -322,11 +311,11 @@ export function prepend(
|
|
|
322
311
|
|
|
323
312
|
if (afterImport === 0) {
|
|
324
313
|
// No import declarations, so we can safely unshift everything
|
|
325
|
-
return
|
|
314
|
+
return listParent.unshiftContainer("body", nodes);
|
|
326
315
|
}
|
|
327
316
|
|
|
328
317
|
// Insert the nodes after the last import declaration
|
|
329
|
-
return
|
|
318
|
+
return body[afterImport - 1].insertAfter(nodes);
|
|
330
319
|
}
|
|
331
320
|
|
|
332
321
|
if (listParent.isFunction()) {
|
|
@@ -342,15 +331,15 @@ export function prepend(
|
|
|
342
331
|
|
|
343
332
|
ok(body.isBlockStatement());
|
|
344
333
|
|
|
345
|
-
return
|
|
334
|
+
return body.unshiftContainer("body", nodes);
|
|
346
335
|
}
|
|
347
336
|
|
|
348
337
|
if (listParent.isBlock()) {
|
|
349
|
-
return
|
|
338
|
+
return listParent.unshiftContainer("body", nodes);
|
|
350
339
|
}
|
|
351
340
|
|
|
352
341
|
if (listParent.isSwitchCase()) {
|
|
353
|
-
return
|
|
342
|
+
return listParent.unshiftContainer("consequent", nodes);
|
|
354
343
|
}
|
|
355
344
|
|
|
356
345
|
ok(false);
|
|
@@ -564,7 +553,7 @@ export function isModifiedIdentifier(identifierPath: NodePath<t.Identifier>) {
|
|
|
564
553
|
|
|
565
554
|
export function replaceDefiningIdentifierToMemberExpression(
|
|
566
555
|
path: NodePath<t.Identifier>,
|
|
567
|
-
memberExpression: t.MemberExpression
|
|
556
|
+
memberExpression: t.MemberExpression | t.Identifier
|
|
568
557
|
) {
|
|
569
558
|
// function id(){} -> var id = function() {}
|
|
570
559
|
if (path.key === "id" && path.parentPath.isFunctionDeclaration()) {
|