js-confuser 2.0.0-alpha.3 → 2.0.0-alpha.4

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.
Files changed (49) hide show
  1. package/.prettierrc +4 -0
  2. package/CHANGELOG.md +18 -2
  3. package/Migration.md +23 -8
  4. package/README.md +2 -2
  5. package/dist/constants.js +6 -1
  6. package/dist/index.js +37 -6
  7. package/dist/obfuscator.js +5 -5
  8. package/dist/templates/integrityTemplate.js +1 -1
  9. package/dist/transforms/controlFlowFlattening.js +110 -77
  10. package/dist/transforms/deadCode.js +13 -7
  11. package/dist/transforms/dispatcher.js +61 -35
  12. package/dist/transforms/identifier/globalConcealing.js +2 -2
  13. package/dist/transforms/identifier/renameVariables.js +33 -0
  14. package/dist/transforms/lock/integrity.js +9 -1
  15. package/dist/transforms/lock/lock.js +7 -7
  16. package/dist/transforms/minify.js +50 -26
  17. package/dist/transforms/opaquePredicates.js +1 -1
  18. package/dist/transforms/pack.js +27 -5
  19. package/dist/transforms/preparation.js +25 -36
  20. package/dist/transforms/rgf.js +7 -5
  21. package/dist/transforms/string/stringConcealing.js +3 -1
  22. package/dist/transforms/variableMasking.js +2 -0
  23. package/dist/utils/NameGen.js +2 -0
  24. package/dist/utils/random-utils.js +10 -0
  25. package/index.d.ts +16 -2
  26. package/package.json +1 -1
  27. package/src/constants.ts +9 -0
  28. package/src/index.ts +15 -6
  29. package/src/obfuscationResult.ts +7 -1
  30. package/src/obfuscator.ts +5 -6
  31. package/src/options.ts +12 -2
  32. package/src/templates/integrityTemplate.ts +14 -19
  33. package/src/transforms/controlFlowFlattening.ts +137 -76
  34. package/src/transforms/deadCode.ts +16 -7
  35. package/src/transforms/dispatcher.ts +23 -3
  36. package/src/transforms/identifier/globalConcealing.ts +22 -15
  37. package/src/transforms/identifier/renameVariables.ts +38 -0
  38. package/src/transforms/lock/integrity.ts +11 -1
  39. package/src/transforms/lock/lock.ts +12 -7
  40. package/src/transforms/minify.ts +61 -36
  41. package/src/transforms/opaquePredicates.ts +1 -1
  42. package/src/transforms/pack.ts +35 -5
  43. package/src/transforms/preparation.ts +33 -46
  44. package/src/transforms/rgf.ts +13 -9
  45. package/src/transforms/string/stringConcealing.ts +2 -0
  46. package/src/transforms/variableMasking.ts +1 -0
  47. package/src/utils/NameGen.ts +9 -1
  48. package/src/utils/random-utils.ts +14 -0
  49. package/src/probability.ts +0 -0
package/.prettierrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "singleQuote": false
4
+ }
package/CHANGELOG.md CHANGED
@@ -69,9 +69,25 @@ const options = {
69
69
 
70
70
  - - `String Compression` now uses LZ-string compression ([lz-string](https://www.npmjs.com/package/lz-string))
71
71
 
72
+ - New Comment Syntax
73
+
74
+ - - `/* @js-confuser-var */ "name"` for improved variable mappings for eval() calls
75
+
76
+ ```js
77
+ // Input
78
+ var name = "Internet User";
79
+ eval( "console.log(" + /* @js-confuser-var */ "name" + ")" );
80
+
81
+ // Output
82
+ var zC3PLKu = "Internet User";
83
+ eval("console.log(" + "zC3PLKu" + ")");
84
+ ```
85
+
86
+ The function `__JS_CONFUSER_VAR__` is identical in outcome and still be used, however, the comment syntax is preferred as the comment syntax's preserves the original script's behavior.
87
+
72
88
  ### JS-Confuser.com Revamp
73
89
 
74
- A new UI for JS-Confuser.com, featuring an advanced playground and documentation pages.
90
+ A new UI for [JS-Confuser.com](https://js-confuser.com), featuring an advanced playground and documentation pages.
75
91
 
76
92
  The previous version will remain available: [old--confuser.netlify.com](https://old--confuser.netlify.app/)
77
93
 
@@ -83,7 +99,7 @@ The previous version will remain available: [old--confuser.netlify.com](https://
83
99
 
84
100
  - Removed `Shuffle`'s Hash option
85
101
 
86
- - Removed `Indent` option. [`@babel/generator`](https://www.npmjs.com/package/@babel/generator) does not allow customizing the indentation size. Use Prettier if you still wish for 4 space or tabs. Be mindful if you have `Integrity` or `Self Defending` enabled, as you should not alter the obfuscated code.
102
+ - Removed `Indent` option
87
103
 
88
104
 
89
105
  # `1.7.3`
package/Migration.md CHANGED
@@ -6,15 +6,20 @@ JS-Confuser 2.0 is complete rewrite of the original JS-Confuser created in 2020!
6
6
 
7
7
  ### JSConfuser.obfuscate() returns an object now
8
8
 
9
- The method `JSConfuser.obfuscate()` resolves to a object now instead of a string. This result object contains the obfuscated code on the `code` property.
9
+ The method `JSConfuser.obfuscate()` resolves to a object now instead of a string. This result object contains a property `code` which is the obfuscated code.
10
10
 
11
11
  ```diff
12
- +JSConfuser.obfuscate(sourceCode, options).then(result=>{
13
- + console.log(result.code);
14
- +});
15
- -JSConfuser.obfuscate(sourceCode, options).then(obfuscatedCode=>{
16
- - console.log(obfuscatedCode);
17
- -});
12
+ const sourceCode = `console.log("Hello World")`;
13
+ const options = {
14
+ target: "node",
15
+ preset: "high"
16
+ };
17
+
18
+ JSConfuser.obfuscate(sourceCode, options).then(result=>{
19
+ // 'result' is now an object
20
+ - console.log(result);
21
+ + console.log(result.code);
22
+ });
18
23
  ```
19
24
 
20
25
  ### Removed Anti Debug Lock / Browser Lock / OS Lock
@@ -54,4 +59,14 @@ These features have been removed but you can still add these locks using the `lo
54
59
 
55
60
  The option `stack` has been renamed to `variableMasking`
56
61
 
57
- [Similar to JScrambler's Variable Masking](https://docs.jscrambler.com/code-integrity/documentation/transformations/variable-masking)
62
+ [Similar to JScrambler's Variable Masking](https://docs.jscrambler.com/code-integrity/documentation/transformations/variable-masking)
63
+
64
+ ```diff
65
+ const options = {
66
+ target: "node",
67
+ preset: "high"
68
+
69
+ - stack: true,
70
+ + variableMasking: true
71
+ };
72
+ ```
package/README.md CHANGED
@@ -21,9 +21,9 @@ JS-Confuser is a JavaScript obfuscation tool to make your programs _impossible_
21
21
 
22
22
  - - [FAQ](https://new--confuser.netlify.app/docs/getting-started/faq)
23
23
 
24
- - [Options](https://new--confuser.netlify.app/docs)
24
+ - [Options](https://new--confuser.netlify.app/docs/options)
25
25
 
26
- - [Presets](https://new--confuser.netlify.app/docs)
26
+ - [Presets](https://new--confuser.netlify.app/docs/presets)
27
27
 
28
28
  ## API Usage
29
29
 
package/dist/constants.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.variableFunctionName = exports.reservedObjectPrototype = exports.reservedKeywords = exports.reservedIdentifiers = exports.predictableFunctionTag = 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;
6
+ exports.variableFunctionName = exports.reservedObjectPrototype = exports.reservedNodeModuleIdentifiers = exports.reservedKeywords = exports.reservedIdentifiers = exports.predictableFunctionTag = 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;
7
7
  var predictableFunctionTag = exports.predictableFunctionTag = "__JS_PREDICT__";
8
8
 
9
9
  /**
@@ -79,6 +79,11 @@ var placeholderVariablePrefix = exports.placeholderVariablePrefix = "__p_";
79
79
  * Identifiers that are not actually variables.
80
80
  */
81
81
  var reservedIdentifiers = exports.reservedIdentifiers = new Set(["undefined", "null", "NaN", "Infinity", "eval", "arguments"]);
82
+
83
+ /**
84
+ * Reserved Node.JS module identifiers.
85
+ */
86
+ var reservedNodeModuleIdentifiers = exports.reservedNodeModuleIdentifiers = new Set(["module", "exports", "require"]);
82
87
  var reservedObjectPrototype = exports.reservedObjectPrototype = new Set(["toString", "valueOf", "constructor", "__proto__", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString"]);
83
88
 
84
89
  /**
package/dist/index.js CHANGED
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "Obfuscator", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _obfuscator["default"];
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "Template", {
7
13
  enumerable: true,
8
14
  get: function get() {
@@ -65,15 +71,37 @@ function _obfuscateAST() {
65
71
  }));
66
72
  return _obfuscateAST.apply(this, arguments);
67
73
  }
68
- function obfuscateWithProfiler(_x5, _x6, _x7) {
74
+ function obfuscateWithProfiler(_x5, _x6) {
69
75
  return _obfuscateWithProfiler.apply(this, arguments);
70
76
  }
71
77
  function _obfuscateWithProfiler() {
72
- _obfuscateWithProfiler = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(sourceCode, options, _profiler) {
73
- var startTime, obfuscator, totalTransforms, transformMap, beforeParseTime, ast, parseTime, currentTransformTime, beforeCompileTime, code, compileTime, endTime, obfuscationTime;
78
+ _obfuscateWithProfiler = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(sourceCode, options) {
79
+ var _profiler,
80
+ startTime,
81
+ obfuscator,
82
+ totalTransforms,
83
+ transformMap,
84
+ beforeParseTime,
85
+ ast,
86
+ parseTime,
87
+ currentTransformTime,
88
+ beforeCompileTime,
89
+ code,
90
+ compileTime,
91
+ endTime,
92
+ obfuscationTime,
93
+ _args3 = arguments;
74
94
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
75
95
  while (1) switch (_context3.prev = _context3.next) {
76
96
  case 0:
97
+ _profiler = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : {};
98
+ if (!_profiler.performance) {
99
+ _profiler.performance = {
100
+ now: function now() {
101
+ return Date.now();
102
+ }
103
+ };
104
+ }
77
105
  startTime = performance.now();
78
106
  obfuscator = new _obfuscator["default"](options);
79
107
  totalTransforms = obfuscator.plugins.length;
@@ -84,13 +112,15 @@ function _obfuscateWithProfiler() {
84
112
  currentTransformTime = performance.now();
85
113
  ast = obfuscator.obfuscateAST(ast, {
86
114
  profiler: function profiler(log) {
115
+ var _profiler$callback;
87
116
  var nowTime = performance.now();
88
- transformMap[log.currentTransform] = {
117
+ var entry = {
89
118
  transformTime: nowTime - currentTransformTime,
90
119
  changeData: {}
91
120
  };
121
+ transformMap[log.currentTransform] = entry;
92
122
  currentTransformTime = nowTime;
93
- _profiler.callback(log);
123
+ (_profiler$callback = _profiler.callback) === null || _profiler$callback === void 0 || _profiler$callback.call(_profiler, log, entry, ast);
94
124
  }
95
125
  });
96
126
  obfuscator.plugins.forEach(function (_ref) {
@@ -115,7 +145,7 @@ function _obfuscateWithProfiler() {
115
145
  totalPossibleTransforms: obfuscator.totalPossibleTransforms
116
146
  }
117
147
  });
118
- case 16:
148
+ case 18:
119
149
  case "end":
120
150
  return _context3.stop();
121
151
  }
@@ -127,6 +157,7 @@ var JsConfuser = {
127
157
  obfuscate: obfuscate,
128
158
  obfuscateAST: obfuscateAST,
129
159
  obfuscateWithProfiler: obfuscateWithProfiler,
160
+ Obfuscator: _obfuscator["default"],
130
161
  presets: _presets["default"],
131
162
  Template: _template["default"]
132
163
  };
@@ -12,6 +12,7 @@ var _validateOptions = require("./validateOptions");
12
12
  var _NameGen = require("./utils/NameGen");
13
13
  var _order = require("./order");
14
14
  var _plugin = require("./transforms/plugin");
15
+ var _objectUtils = require("./utils/object-utils");
15
16
  var _preparation = _interopRequireDefault(require("./transforms/preparation"));
16
17
  var _renameVariables = _interopRequireDefault(require("./transforms/identifier/renameVariables"));
17
18
  var _variableMasking = _interopRequireDefault(require("./transforms/variableMasking"));
@@ -37,7 +38,6 @@ var _minify = _interopRequireDefault(require("./transforms/minify"));
37
38
  var _finalizer = _interopRequireDefault(require("./transforms/finalizer"));
38
39
  var _integrity = _interopRequireDefault(require("./transforms/lock/integrity"));
39
40
  var _pack = _interopRequireDefault(require("./transforms/pack"));
40
- var _objectUtils = require("./utils/object-utils");
41
41
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
42
42
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
43
43
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
@@ -165,7 +165,10 @@ var Obfuscator = exports["default"] = /*#__PURE__*/function () {
165
165
  }
166
166
  return _createClass(Obfuscator, [{
167
167
  key: "isInternalVariable",
168
- value: function isInternalVariable(name) {
168
+ value:
169
+ // Pack Interface for sharing globals across RGF functions
170
+
171
+ function isInternalVariable(name) {
169
172
  return Object.values(this.globalState.internals).includes(name);
170
173
  }
171
174
  }, {
@@ -233,9 +236,6 @@ var Obfuscator = exports["default"] = /*#__PURE__*/function () {
233
236
  var _this$plugins$i = this.plugins[i],
234
237
  plugin = _this$plugins$i.plugin,
235
238
  pluginInstance = _this$plugins$i.pluginInstance;
236
-
237
- // Skip pack if disabled
238
- if (pluginInstance.order === _order.Order.Pack && options !== null && options !== void 0 && options.disablePack) continue;
239
239
  if (this.options.verbose) {
240
240
  console.log("Applying ".concat(pluginInstance.name, " (").concat(i + 1, "/").concat(this.plugins.length, ")"));
241
241
  }
@@ -27,4 +27,4 @@ function HashFunction(str, seed) {
27
27
  }
28
28
 
29
29
  // In template form to be inserted into code
30
- var HashTemplate = exports.HashTemplate = new _template["default"]("\n// Must be Function Declaration for hoisting\n// Math.imul polyfill for ES5\nfunction {imul}(opA, opB) {\n var MathImul = Math[\"imul\"] || function(opA, opB){\n opB |= 0; // ensure that opB is an integer. opA will automatically be coerced.\n // floating points give us 53 bits of precision to work with plus 1 sign bit\n // automatically handled for our convienence:\n // 1. 0x003fffff /*opA & 0x000fffff*/ * 0x7fffffff /*opB*/ = 0x1fffff7fc00001\n // 0x1fffff7fc00001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/\n var result = (opA & 0x003fffff) * opB;\n // 2. We can remove an integer coersion from the statement above because:\n // 0x1fffff7fc00001 + 0xffc00000 = 0x1fffffff800001\n // 0x1fffffff800001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/\n if (opA & 0xffc00000 /*!== 0*/) result += (opA & 0xffc00000) * opB |0;\n return result |0;\n };\n\n var result = MathImul(opA, opB);\n\n return result;\n}\n\n\nfunction {hashingUtilFnName}(str, seed) {\n var h1 = 0xdeadbeef ^ seed;\n var h2 = 0x41c6ce57 ^ seed;\n for (var i = 0, ch; i < str.length; i++) {\n ch = str.charCodeAt(i);\n h1 = {imul}(h1 ^ ch, 2654435761);\n h2 = {imul}(h2 ^ ch, 1597334677);\n }\n h1 = {imul}(h1 ^ (h1>>>16), 2246822507) ^ {imul}(h2 ^ (h2>>>13), 3266489909);\n h2 = {imul}(h2 ^ (h2>>>16), 2246822507) ^ {imul}(h1 ^ (h1>>>13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1>>>0);\n};\n\n// Simple function that returns .toString() value with spaces replaced out\nfunction {name}(fnObject, seed, regex={sensitivityRegex}){\n var fnStringed = fnObject[\"toString\"]()[\"replace\"](regex, \"\");\n return {hashingUtilFnName}(fnStringed, seed);\n}\n").addSymbols(_constants.SKIP, _constants.MULTI_TRANSFORM);
30
+ var HashTemplate = exports.HashTemplate = new _template["default"]("\n// Must be Function Declaration for hoisting\n// Math.imul polyfill for ES5\nfunction MathImulPolyfill(opA, opB){\n opB |= 0; // ensure that opB is an integer. opA will automatically be coerced.\n // floating points give us 53 bits of precision to work with plus 1 sign bit\n // automatically handled for our convienence:\n // 1. 0x003fffff /*opA & 0x000fffff*/ * 0x7fffffff /*opB*/ = 0x1fffff7fc00001\n // 0x1fffff7fc00001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/\n var result = (opA & 0x003fffff) * opB;\n // 2. We can remove an integer coersion from the statement above because:\n // 0x1fffff7fc00001 + 0xffc00000 = 0x1fffffff800001\n // 0x1fffffff800001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/\n if (opA & 0xffc00000 /*!== 0*/) result += (opA & 0xffc00000) * opB |0;\n return result |0;\n};\n\nvar {imul} = Math[\"imul\"] || MathImulPolyfill;\n\nfunction {hashingUtilFnName}(str, seed) {\n var h1 = 0xdeadbeef ^ seed;\n var h2 = 0x41c6ce57 ^ seed;\n for (var i = 0, ch; i < str.length; i++) {\n ch = str.charCodeAt(i);\n h1 = {imul}(h1 ^ ch, 2654435761);\n h2 = {imul}(h2 ^ ch, 1597334677);\n }\n h1 = {imul}(h1 ^ (h1>>>16), 2246822507) ^ {imul}(h2 ^ (h2>>>13), 3266489909);\n h2 = {imul}(h2 ^ (h2>>>16), 2246822507) ^ {imul}(h1 ^ (h1>>>13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1>>>0);\n};\n\n// Simple function that returns .toString() value with spaces replaced out\nfunction {name}(fnObject, seed, regex={sensitivityRegex}){\n var fnStringed = fnObject[\"toString\"]()[\"replace\"](regex, \"\");\n return {hashingUtilFnName}(fnStringed, seed);\n}\n").addSymbols(_constants.SKIP, _constants.MULTI_TRANSFORM);
@@ -36,6 +36,9 @@ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r),
36
36
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
37
37
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
38
38
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
39
+ // Function deemed unsafe for CFF
40
+ var CFF_UNSAFE = Symbol("CFF_UNSAFE");
41
+
39
42
  /**
40
43
  * Breaks functions into DAGs (Directed Acyclic Graphs)
41
44
  *
@@ -79,6 +82,10 @@ var _default = exports["default"] = function _default(_ref) {
79
82
  // Amount of blocks changed by Control Flow Flattening
80
83
  var cffCounter = 0;
81
84
  var functionsModified = new Set();
85
+ function flagFunctionToAvoid(path, reason) {
86
+ var fnOrProgram = (0, _astUtils.getParentFunctionOrProgram)(path);
87
+ fnOrProgram.node[CFF_UNSAFE] = reason;
88
+ }
82
89
  return {
83
90
  post: function post() {
84
91
  functionsModified.forEach(function (node) {
@@ -86,6 +93,26 @@ var _default = exports["default"] = function _default(_ref) {
86
93
  });
87
94
  },
88
95
  visitor: {
96
+ // Unsafe detection
97
+ ThisExpression: function ThisExpression(path) {
98
+ flagFunctionToAvoid(path, "this");
99
+ },
100
+ VariableDeclaration: function VariableDeclaration(path) {
101
+ if (path.node.declarations.length !== 1) {
102
+ path.getAncestry().forEach(function (p) {
103
+ p.node[CFF_UNSAFE] = "multipleDeclarations";
104
+ });
105
+ }
106
+ },
107
+ Identifier: function Identifier(path) {
108
+ if (path.node.name === _constants.variableFunctionName || path.node.name === "arguments") {
109
+ flagFunctionToAvoid(path, "arguments");
110
+ }
111
+ },
112
+ "Super|MetaProperty|AwaitExpression|YieldExpression": function SuperMetaPropertyAwaitExpressionYieldExpression(path) {
113
+ flagFunctionToAvoid(path, "functionSpecific");
114
+ },
115
+ // Main CFF transformation
89
116
  "Program|Function": {
90
117
  exit: function exit(_path) {
91
118
  var programOrFunctionPath = _path;
@@ -94,6 +121,9 @@ var _default = exports["default"] = function _default(_ref) {
94
121
  if (programOrFunctionPath.find(function (p) {
95
122
  return p.isForStatement() || p.isWhile();
96
123
  })) return;
124
+
125
+ // Exclude 'CFF_UNSAFE' functions
126
+ if (programOrFunctionPath.node[CFF_UNSAFE]) return;
97
127
  var programPath = _path.isProgram() ? _path : null;
98
128
  var functionPath = _path.isFunction() ? _path : null;
99
129
  var blockPath;
@@ -118,32 +148,17 @@ var _default = exports["default"] = function _default(_ref) {
118
148
  if (!me.computeProbabilityMap(me.options.controlFlowFlattening)) {
119
149
  return;
120
150
  }
121
-
122
- // Avoid unsafe functions
123
- if (functionPath && functionPath.node[_constants.UNSAFE]) return;
151
+ if (functionPath) {
152
+ // Avoid unsafe functions
153
+ if (functionPath.node[_constants.UNSAFE]) return;
154
+ if (functionPath.node.async || functionPath.node.generator) return;
155
+ }
124
156
  programOrFunctionPath.scope.crawl();
125
157
  var blockFnParent = (0, _astUtils.getParentFunctionOrProgram)(blockPath);
126
158
  var hasIllegalNode = false;
127
159
  var bindingNames = new Set();
128
160
  blockPath.traverse({
129
- "Super|MetaProperty|AwaitExpression|YieldExpression": function SuperMetaPropertyAwaitExpressionYieldExpression(path) {
130
- if ((0, _astUtils.getParentFunctionOrProgram)(path).node === blockFnParent.node) {
131
- hasIllegalNode = true;
132
- path.stop();
133
- }
134
- },
135
- VariableDeclaration: function VariableDeclaration(path) {
136
- if (path.node.declarations.length !== 1) {
137
- hasIllegalNode = true;
138
- path.stop();
139
- }
140
- },
141
161
  Identifier: function Identifier(path) {
142
- if (path.node.name === _constants.variableFunctionName || path.node.name === "arguments") {
143
- hasIllegalNode = true;
144
- path.stop();
145
- return;
146
- }
147
162
  if (!path.isBindingIdentifier()) return;
148
163
  var binding = path.scope.getBinding(path.node.name);
149
164
  if (!binding) return;
@@ -270,7 +285,7 @@ var _default = exports["default"] = function _default(_ref) {
270
285
  }, {
271
286
  key: "getInitializingObjectExpression",
272
287
  value: function getInitializingObjectExpression() {
273
- return isDebug ? new _template["default"]("\n ({\n identity: \"".concat(this.propertyName, "\"\n })\n ")).expression() : new _template["default"]("Object[\"create\"](null)").expression();
288
+ return isDebug ? new _template["default"]("\n ({\n identity: \"".concat(this.propertyName, "\"\n })\n ")).expression() : new _template["default"]("({})").expression();
274
289
  }
275
290
  }, {
276
291
  key: "getMemberExpression",
@@ -301,6 +316,13 @@ var _default = exports["default"] = function _default(_ref) {
301
316
  for (var key in propertyMap) {
302
317
  properties.push(t.objectProperty(t.stringLiteral(key), propertyMap[key], true));
303
318
  }
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
+ }
304
326
  return t.objectExpression(properties);
305
327
  }
306
328
  }, {
@@ -537,7 +559,7 @@ var _default = exports["default"] = function _default(_ref) {
537
559
  if (statement.isFunctionDeclaration()) {
538
560
  var fnName = statement.node.id.name;
539
561
  var isIllegal = false;
540
- if (!flattenFunctionDeclarations || statement.node.async || statement.node.generator || statement.node[_constants.UNSAFE]) {
562
+ if (!flattenFunctionDeclarations || statement.node.async || statement.node.generator || statement.node[_constants.UNSAFE] || statement.node[CFF_UNSAFE] || (0, _astUtils.isStrictMode)(statement)) {
541
563
  isIllegal = true;
542
564
  }
543
565
  var oldBasicBlock = currentBasicBlock;
@@ -673,13 +695,6 @@ var _default = exports["default"] = function _default(_ref) {
673
695
  nextBlockPath: defaultBlockPath
674
696
  });
675
697
  basicBlocks.get(endLabel).allowWithDiscriminant = false;
676
-
677
- // Add with / reset with logic
678
- basicBlocks.get(startLabel).body.unshift(new _template["default"]("\n {resetWithMemberExpression} = function(newStateValues){\n {withMemberExpression} = undefined;\n {arrayPattern} = newStateValues\n }\n ").single({
679
- arrayPattern: t.arrayPattern((0, _node.deepClone)(stateVars)),
680
- resetWithMemberExpression: (0, _node.deepClone)(resetWithMemberExpression),
681
- withMemberExpression: (0, _node.deepClone)(withMemberExpression)
682
- }));
683
698
  if (!isDebug && addDeadCode) {
684
699
  // DEAD CODE 1/3: Add fake chunks that are never reached
685
700
  var fakeChunkCount = (0, _randomUtils.getRandomInteger)(1, 5);
@@ -767,7 +782,7 @@ var _default = exports["default"] = function _default(_ref) {
767
782
  var _iterator2 = _createForOfIteratorHelper(basicBlocks.values()),
768
783
  _step2;
769
784
  try {
770
- var _loop5 = function _loop5() {
785
+ var _loop4 = function _loop4() {
771
786
  var basicBlock = _step2.value;
772
787
  var currentStateValues = basicBlock.stateValues;
773
788
  // Wrap the statement in a Babel path to allow traversal
@@ -854,6 +869,12 @@ var _default = exports["default"] = function _default(_ref) {
854
869
  me.skip(memberExpression);
855
870
  path.replaceWith(memberExpression);
856
871
  path.skip();
872
+
873
+ // Preserve proper 'this' context when directly calling functions
874
+ // X.Y.Z() -> (1, X.Y.Z)()
875
+ if (path.parentPath.isCallExpression() && path.key === "callee") {
876
+ path.replaceWith(t.sequenceExpression([t.numericLiteral(1), path.node]));
877
+ }
857
878
  }
858
879
  },
859
880
  // Top-level returns set additional flag to indicate that the function has returned
@@ -889,18 +910,17 @@ var _default = exports["default"] = function _default(_ref) {
889
910
  needsIndividualAssignments = false;
890
911
  }
891
912
  if (needsIndividualAssignments) {
892
- for (var _i7 = 0; _i7 < stateVars.length; _i7++) {
893
- var oldValue = currentStateValues[_i7];
894
- var newValue = newStateValues[_i7];
913
+ for (var _i8 = 0; _i8 < stateVars.length; _i8++) {
914
+ var oldValue = currentStateValues[_i8];
915
+ var newValue = newStateValues[_i8];
895
916
 
896
917
  // console.log(oldValue, newValue);
897
918
  if (oldValue === newValue) continue; // No diff needed if the value doesn't change
898
919
 
899
- var leftValue = jumpBlock.withDiscriminant ? jumpBlock.withDiscriminant.getMemberExpression(stateVars[_i7].name) : (0, _node.deepClone)(stateVars[_i7]);
900
- var assignment = t.assignmentExpression("=", leftValue, (0, _node.numericLiteral)(newValue));
920
+ var assignment = t.assignmentExpression("=", (0, _node.deepClone)(stateVars[_i8]), (0, _node.numericLiteral)(newValue));
901
921
  if (!isDebug && addRelativeAssignments) {
902
922
  // Use diffs to create confusing code
903
- assignment = t.assignmentExpression("+=", (0, _node.deepClone)(stateVars[_i7]), (0, _node.numericLiteral)(newValue - oldValue));
923
+ assignment = t.assignmentExpression("+=", (0, _node.deepClone)(stateVars[_i8]), (0, _node.numericLiteral)(newValue - oldValue));
904
924
  }
905
925
  assignments.push(assignment);
906
926
  }
@@ -921,7 +941,7 @@ var _default = exports["default"] = function _default(_ref) {
921
941
  basicBlock.thisPath.traverse(visitor);
922
942
  };
923
943
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
924
- _loop5();
944
+ _loop4();
925
945
  }
926
946
 
927
947
  /**
@@ -939,32 +959,39 @@ var _default = exports["default"] = function _default(_ref) {
939
959
  }
940
960
  var mainScope = basicBlocks.get(startLabel).scopeManager;
941
961
  var predicateNumbers = new Map();
942
- var predicateNumberCount = isDebug || !addPredicateTests ? 0 : (0, _randomUtils.getRandomInteger)(2, 5);
943
- var _loop3 = function _loop3() {
944
- var name = mainScope.getNewName(me.getPlaceholder("predicate_" + _i2));
945
- var number = (0, _randomUtils.getRandomInteger)(-250, 250);
946
- predicateNumbers.set(name, number);
947
- var createAssignment = function createAssignment(value) {
948
- return new _template["default"]("\n {memberExpression} = {number}\n ").single({
949
- memberExpression: mainScope.getMemberExpression(name),
950
- number: (0, _node.numericLiteral)(number)
951
- });
952
- };
953
- basicBlocks.get(startLabel).body.unshift(createAssignment(number));
954
-
955
- // Add random assignments to impossible blocks
956
- fakeAssignmentCount = (0, _randomUtils.getRandomInteger)(0, 3);
957
- for (var _i8 = 0; _i8 < fakeAssignmentCount; _i8++) {
958
- impossibleBlock = (0, _randomUtils.choice)(getImpossibleBasicBlocks());
959
- if (impossibleBlock) {
960
- impossibleBlock.body.unshift(createAssignment((0, _randomUtils.getRandomInteger)(-250, 250)));
961
- }
962
- }
963
- },
964
- fakeAssignmentCount,
965
- impossibleBlock;
962
+ var predicateNumberCount = isDebug || !addPredicateTests ? 0 : (0, _randomUtils.getRandomInteger)(1, 4);
966
963
  for (var _i2 = 0; _i2 < predicateNumberCount; _i2++) {
967
- _loop3();
964
+ var name = mainScope.getNewName(me.getPlaceholder("predicate_" + _i2));
965
+ var number = (0, _randomUtils.getRandomInteger)(-250, 250);
966
+ predicateNumbers.set(name, number);
967
+ }
968
+ var predicateSymbol = Symbol("predicate");
969
+ var createAssignment = function createAssignment(values) {
970
+ var exprStmt = new _template["default"]("\n ({predicateVariables} = {values})\n ").single({
971
+ predicateVariables: t.arrayPattern(Array.from(predicateNumbers.keys()).map(function (name) {
972
+ return mainScope.getMemberExpression(name);
973
+ })),
974
+ values: t.arrayExpression(values.map(function (value) {
975
+ return (0, _node.numericLiteral)(value);
976
+ }))
977
+ });
978
+ exprStmt[predicateSymbol] = true;
979
+ return exprStmt;
980
+ };
981
+ basicBlocks.get(startLabel).body.unshift(createAssignment(Array.from(predicateNumbers.values())));
982
+
983
+ // Add random assignments to impossible blocks
984
+ var fakeAssignmentCount = (0, _randomUtils.getRandomInteger)(1, 3);
985
+ for (var _i3 = 0; _i3 < fakeAssignmentCount; _i3++) {
986
+ var impossibleBlock = (0, _randomUtils.choice)(getImpossibleBasicBlocks());
987
+ if (impossibleBlock) {
988
+ var _impossibleBlock$body;
989
+ if ((_impossibleBlock$body = impossibleBlock.body[0]) !== null && _impossibleBlock$body !== void 0 && _impossibleBlock$body[predicateSymbol]) continue;
990
+ var fakeValues = new Array(predicateNumberCount).fill(0).map(function () {
991
+ return (0, _randomUtils.getRandomInteger)(-250, 250);
992
+ });
993
+ impossibleBlock.body.unshift(createAssignment(fakeValues));
994
+ }
968
995
  }
969
996
 
970
997
  // Add scope initializations: scope["_0"] = {identity: "_0"}
@@ -988,8 +1015,8 @@ var _default = exports["default"] = function _default(_ref) {
988
1015
  if (!isDebug && addFakeTests) {
989
1016
  (0, _randomUtils.shuffle)(blocks);
990
1017
  }
991
- var _loop4 = function _loop4() {
992
- var block = _blocks[_i3];
1018
+ var _loop3 = function _loop3() {
1019
+ var block = _blocks[_i4];
993
1020
  if (block.label === endLabel) {
994
1021
  // ok(block.body.length === 0);
995
1022
  return 1; // continue
@@ -1001,8 +1028,8 @@ var _default = exports["default"] = function _default(_ref) {
1001
1028
  if (!isDebug && addPredicateTests && block.label !== startLabel && (0, _randomUtils.chance)(50)) {
1002
1029
  var predicateName = (0, _randomUtils.choice)(Array.from(predicateNumbers.keys()));
1003
1030
  if (predicateName) {
1004
- var number = predicateNumbers.get(predicateName);
1005
- var diff = block.totalState - number;
1031
+ var _number = predicateNumbers.get(predicateName);
1032
+ var diff = block.totalState - _number;
1006
1033
  test = t.binaryExpression("+", mainScope.getMemberExpression(predicateName), (0, _node.numericLiteral)(diff));
1007
1034
  }
1008
1035
  }
@@ -1054,20 +1081,20 @@ var _default = exports["default"] = function _default(_ref) {
1054
1081
  if (!isDebug && addFakeTests && (0, _randomUtils.chance)(50)) {
1055
1082
  // Add fake tests
1056
1083
  var fakeTestCount = (0, _randomUtils.getRandomInteger)(1, 3);
1057
- for (var _i4 = 0; _i4 < fakeTestCount; _i4++) {
1084
+ for (var _i5 = 0; _i5 < fakeTestCount; _i5++) {
1058
1085
  tests.push((0, _node.numericLiteral)(stateIntGen.generate()));
1059
1086
  }
1060
1087
  (0, _randomUtils.shuffle)(tests);
1061
1088
  }
1062
1089
  var lastTest = tests.pop();
1063
- for (var _i5 = 0, _tests = tests; _i5 < _tests.length; _i5++) {
1064
- var _test = _tests[_i5];
1090
+ for (var _i6 = 0, _tests = tests; _i6 < _tests.length; _i6++) {
1091
+ var _test = _tests[_i6];
1065
1092
  switchCases.push(t.switchCase(_test, []));
1066
1093
  }
1067
1094
  switchCases.push(t.switchCase(lastTest, block.thisPath.node.body));
1068
1095
  };
1069
- for (var _i3 = 0, _blocks = blocks; _i3 < _blocks.length; _i3++) {
1070
- if (_loop4()) continue;
1096
+ for (var _i4 = 0, _blocks = blocks; _i4 < _blocks.length; _i4++) {
1097
+ if (_loop3()) continue;
1071
1098
  }
1072
1099
  if (!isDebug && addFakeTests) {
1073
1100
  // A random test can be 'default'
@@ -1086,7 +1113,7 @@ var _default = exports["default"] = function _default(_ref) {
1086
1113
  var switchStatement = t.labeledStatement(t.identifier(switchLabel), t.switchStatement(discriminant, switchCases));
1087
1114
  var startStateValues = basicBlocks.get(startLabel).stateValues;
1088
1115
  var endTotalState = basicBlocks.get(endLabel).totalState;
1089
- var whileStatement = t.whileStatement(t.binaryExpression("!==", (0, _node.deepClone)(discriminant), (0, _node.numericLiteral)(endTotalState)), t.blockStatement([t.withStatement(new _template["default"]("{withDiscriminant} || Object[\"create\"](null)").expression({
1116
+ var whileStatement = t.whileStatement(t.binaryExpression("!==", (0, _node.deepClone)(discriminant), (0, _node.numericLiteral)(endTotalState)), t.blockStatement([t.withStatement(new _template["default"]("{withDiscriminant} || {}").expression({
1090
1117
  withDiscriminant: (0, _node.deepClone)(withMemberExpression)
1091
1118
  }), t.blockStatement([switchStatement]))]));
1092
1119
  var parameters = [].concat(_toConsumableArray(stateVars), [argVar, scopeVar]).map(function (id) {
@@ -1095,8 +1122,8 @@ var _default = exports["default"] = function _default(_ref) {
1095
1122
  var parametersNames = parameters.map(function (id) {
1096
1123
  return id.name;
1097
1124
  });
1098
- for (var _i6 = 0, _functionExpressions = functionExpressions; _i6 < _functionExpressions.length; _i6++) {
1099
- var _functionExpressions$ = _slicedToArray(_functionExpressions[_i6], 4),
1125
+ for (var _i7 = 0, _functionExpressions = functionExpressions; _i7 < _functionExpressions.length; _i7++) {
1126
+ var _functionExpressions$ = _slicedToArray(_functionExpressions[_i7], 4),
1100
1127
  originalFnName = _functionExpressions$[0],
1101
1128
  fnLabel = _functionExpressions$[1],
1102
1129
  basicBlock = _functionExpressions$[2],
@@ -1134,16 +1161,22 @@ var _default = exports["default"] = function _default(_ref) {
1134
1161
  callExpression: t.callExpression((0, _node.deepClone)(mainFnName), argumentsNodes)
1135
1162
  }));
1136
1163
  }
1164
+ var startProgramObjectExpression = basicBlocks.get(startLabel).scopeManager.getObjectExpression(startLabel);
1165
+ var mainParameters = parameters;
1166
+ var scopeParameter = mainParameters.pop();
1167
+ mainParameters.push(t.assignmentPattern(scopeParameter, startProgramObjectExpression));
1137
1168
  var mainFnDeclaration = t.functionDeclaration((0, _node.deepClone)(mainFnName), parameters, t.blockStatement([whileStatement]));
1138
1169
  mainFnDeclaration[_constants.PREDICTABLE] = true;
1139
1170
  var startProgramExpression = t.callExpression((0, _node.deepClone)(mainFnName), [].concat(_toConsumableArray(startStateValues.map(function (stateValue) {
1140
1171
  return (0, _node.numericLiteral)(stateValue);
1141
- })), [t.identifier("undefined"), basicBlocks.get(startLabel).scopeManager.getObjectExpression(startLabel)]));
1172
+ })), [t.identifier("undefined")]));
1142
1173
  var _resultVar = withIdentifier("result");
1143
- var allowReturns = blockPath.find(function (p) {
1174
+ var isTopLevel = blockPath.isProgram();
1175
+ var allowReturns = !isTopLevel && blockPath.find(function (p) {
1144
1176
  return p.isFunction();
1145
1177
  });
1146
- var startProgramStatements = new _template["default"]("\n ".concat(allowReturns ? "var {didReturnVar};" : "", "\n var {resultVar} = {startProgramExpression};\n ").concat(allowReturns ? "\n if({didReturnVar}){\n return {resultVar};\n }" : "", "\n ")).compile({
1178
+ var startPrefix = allowReturns ? "var {resultVar} = " : "";
1179
+ var startProgramStatements = new _template["default"]("\n ".concat(allowReturns ? "var {didReturnVar};" : "", "\n ").concat(startPrefix, "{startProgramExpression};\n ").concat(allowReturns ? "\n if({didReturnVar}){\n return {resultVar};\n }" : "", "\n ")).compile({
1147
1180
  startProgramExpression: startProgramExpression,
1148
1181
  didReturnVar: function didReturnVar() {
1149
1182
  return (0, _node.deepClone)(_didReturnVar);