js-confuser 1.7.2 → 2.0.0-alpha.0

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 (263) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +6 -4
  2. package/.github/workflows/node.js.yml +1 -1
  3. package/CHANGELOG.md +105 -0
  4. package/Migration.md +57 -0
  5. package/README.md +23 -913
  6. package/dist/constants.js +69 -13
  7. package/dist/index.js +108 -152
  8. package/dist/obfuscator.js +316 -118
  9. package/dist/options.js +1 -109
  10. package/dist/order.js +30 -30
  11. package/dist/presets.js +47 -45
  12. package/dist/probability.js +25 -32
  13. package/dist/templates/bufferToStringTemplate.js +9 -0
  14. package/dist/templates/deadCodeTemplates.js +9 -0
  15. package/dist/templates/getGlobalTemplate.js +19 -0
  16. package/dist/templates/integrityTemplate.js +30 -0
  17. package/dist/templates/setFunctionLengthTemplate.js +9 -0
  18. package/dist/templates/stringCompressionTemplate.js +10 -0
  19. package/dist/templates/tamperProtectionTemplates.js +21 -0
  20. package/dist/templates/template.js +213 -93
  21. package/dist/transforms/astScrambler.js +100 -0
  22. package/dist/transforms/calculator.js +70 -127
  23. package/dist/transforms/controlFlowFlattening.js +1182 -0
  24. package/dist/transforms/deadCode.js +62 -577
  25. package/dist/transforms/dispatcher.js +300 -309
  26. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +88 -189
  27. package/dist/transforms/extraction/objectExtraction.js +131 -215
  28. package/dist/transforms/finalizer.js +56 -59
  29. package/dist/transforms/flatten.js +275 -276
  30. package/dist/transforms/functionOutlining.js +230 -0
  31. package/dist/transforms/identifier/globalConcealing.js +217 -103
  32. package/dist/transforms/identifier/movedDeclarations.js +167 -91
  33. package/dist/transforms/identifier/renameVariables.js +240 -187
  34. package/dist/transforms/lock/integrity.js +61 -184
  35. package/dist/transforms/lock/lock.js +263 -303
  36. package/dist/transforms/minify.js +431 -436
  37. package/dist/transforms/opaquePredicates.js +65 -118
  38. package/dist/transforms/pack.js +160 -0
  39. package/dist/transforms/plugin.js +179 -0
  40. package/dist/transforms/preparation.js +263 -163
  41. package/dist/transforms/renameLabels.js +132 -56
  42. package/dist/transforms/rgf.js +142 -240
  43. package/dist/transforms/shuffle.js +52 -145
  44. package/dist/transforms/string/encoding.js +45 -173
  45. package/dist/transforms/string/stringCompression.js +81 -126
  46. package/dist/transforms/string/stringConcealing.js +189 -224
  47. package/dist/transforms/string/stringEncoding.js +32 -40
  48. package/dist/transforms/string/stringSplitting.js +54 -55
  49. package/dist/transforms/variableMasking.js +232 -0
  50. package/dist/utils/ControlObject.js +125 -0
  51. package/dist/utils/IntGen.js +46 -0
  52. package/dist/utils/NameGen.js +106 -0
  53. package/dist/utils/ast-utils.js +560 -0
  54. package/dist/utils/function-utils.js +56 -0
  55. package/dist/utils/gen-utils.js +48 -0
  56. package/dist/utils/node.js +77 -0
  57. package/dist/utils/object-utils.js +21 -0
  58. package/dist/utils/random-utils.js +91 -0
  59. package/dist/utils/static-utils.js +64 -0
  60. package/dist/validateOptions.js +122 -0
  61. package/index.d.ts +1 -17
  62. package/package.json +27 -22
  63. package/src/constants.ts +139 -77
  64. package/src/index.ts +70 -163
  65. package/src/obfuscationResult.ts +43 -0
  66. package/src/obfuscator.ts +328 -135
  67. package/src/options.ts +154 -623
  68. package/src/order.ts +14 -14
  69. package/src/presets.ts +39 -34
  70. package/src/probability.ts +21 -36
  71. package/src/templates/{bufferToString.ts → bufferToStringTemplate.ts} +5 -54
  72. package/src/templates/deadCodeTemplates.ts +1185 -0
  73. package/src/templates/getGlobalTemplate.ts +72 -0
  74. package/src/templates/integrityTemplate.ts +69 -0
  75. package/src/templates/setFunctionLengthTemplate.ts +11 -0
  76. package/src/templates/stringCompressionTemplate.ts +42 -0
  77. package/src/templates/tamperProtectionTemplates.ts +116 -0
  78. package/src/templates/template.ts +183 -92
  79. package/src/transforms/astScrambler.ts +99 -0
  80. package/src/transforms/calculator.ts +96 -224
  81. package/src/transforms/controlFlowFlattening.ts +1594 -0
  82. package/src/transforms/deadCode.ts +85 -628
  83. package/src/transforms/dispatcher.ts +431 -636
  84. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +147 -299
  85. package/src/transforms/extraction/objectExtraction.ts +160 -333
  86. package/src/transforms/finalizer.ts +63 -64
  87. package/src/transforms/flatten.ts +439 -557
  88. package/src/transforms/functionOutlining.ts +225 -0
  89. package/src/transforms/identifier/globalConcealing.ts +261 -189
  90. package/src/transforms/identifier/movedDeclarations.ts +228 -142
  91. package/src/transforms/identifier/renameVariables.ts +252 -258
  92. package/src/transforms/lock/integrity.ts +84 -260
  93. package/src/transforms/lock/lock.ts +342 -491
  94. package/src/transforms/minify.ts +523 -663
  95. package/src/transforms/opaquePredicates.ts +90 -229
  96. package/src/transforms/pack.ts +195 -0
  97. package/src/transforms/plugin.ts +185 -0
  98. package/src/transforms/preparation.ts +337 -215
  99. package/src/transforms/renameLabels.ts +176 -77
  100. package/src/transforms/rgf.ts +293 -386
  101. package/src/transforms/shuffle.ts +80 -254
  102. package/src/transforms/string/encoding.ts +26 -129
  103. package/src/transforms/string/stringCompression.ts +118 -236
  104. package/src/transforms/string/stringConcealing.ts +255 -339
  105. package/src/transforms/string/stringEncoding.ts +28 -47
  106. package/src/transforms/string/stringSplitting.ts +61 -75
  107. package/src/transforms/variableMasking.ts +257 -0
  108. package/src/utils/ControlObject.ts +141 -0
  109. package/src/utils/IntGen.ts +33 -0
  110. package/src/utils/NameGen.ts +106 -0
  111. package/src/utils/ast-utils.ts +667 -0
  112. package/src/utils/function-utils.ts +50 -0
  113. package/src/utils/gen-utils.ts +48 -0
  114. package/src/utils/node.ts +78 -0
  115. package/src/utils/object-utils.ts +21 -0
  116. package/src/utils/random-utils.ts +79 -0
  117. package/src/utils/static-utils.ts +66 -0
  118. package/src/validateOptions.ts +256 -0
  119. package/tsconfig.json +13 -8
  120. package/babel.config.js +0 -12
  121. package/dev.js +0 -8
  122. package/dist/compiler.js +0 -34
  123. package/dist/parser.js +0 -59
  124. package/dist/precedence.js +0 -66
  125. package/dist/templates/bufferToString.js +0 -108
  126. package/dist/templates/crash.js +0 -59
  127. package/dist/templates/es5.js +0 -137
  128. package/dist/templates/functionLength.js +0 -34
  129. package/dist/templates/globals.js +0 -9
  130. package/dist/transforms/antiTooling.js +0 -88
  131. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +0 -1281
  132. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +0 -131
  133. package/dist/transforms/es5/antiClass.js +0 -164
  134. package/dist/transforms/es5/antiDestructuring.js +0 -193
  135. package/dist/transforms/es5/antiES6Object.js +0 -185
  136. package/dist/transforms/es5/antiSpreadOperator.js +0 -35
  137. package/dist/transforms/es5/antiTemplate.js +0 -66
  138. package/dist/transforms/es5/es5.js +0 -123
  139. package/dist/transforms/extraction/classExtraction.js +0 -83
  140. package/dist/transforms/identifier/globalAnalysis.js +0 -70
  141. package/dist/transforms/identifier/variableAnalysis.js +0 -104
  142. package/dist/transforms/lock/antiDebug.js +0 -76
  143. package/dist/transforms/stack.js +0 -343
  144. package/dist/transforms/transform.js +0 -350
  145. package/dist/traverse.js +0 -110
  146. package/dist/util/compare.js +0 -145
  147. package/dist/util/gen.js +0 -564
  148. package/dist/util/guard.js +0 -9
  149. package/dist/util/identifiers.js +0 -355
  150. package/dist/util/insert.js +0 -362
  151. package/dist/util/math.js +0 -19
  152. package/dist/util/object.js +0 -40
  153. package/dist/util/random.js +0 -130
  154. package/dist/util/scope.js +0 -20
  155. package/docs/ControlFlowFlattening.md +0 -595
  156. package/docs/Countermeasures.md +0 -63
  157. package/docs/ES5.md +0 -197
  158. package/docs/Integrity.md +0 -75
  159. package/docs/RGF.md +0 -419
  160. package/samples/example.js +0 -15
  161. package/samples/high.js +0 -1
  162. package/samples/input.js +0 -3
  163. package/samples/javascriptobfuscator.com.js +0 -8
  164. package/samples/jscrambler_advanced.js +0 -1894
  165. package/samples/jscrambler_light.js +0 -1134
  166. package/samples/low.js +0 -1
  167. package/samples/medium.js +0 -1
  168. package/samples/obfuscator.io.js +0 -1686
  169. package/samples/preemptive.com.js +0 -16
  170. package/src/compiler.ts +0 -35
  171. package/src/parser.ts +0 -49
  172. package/src/precedence.ts +0 -61
  173. package/src/templates/crash.ts +0 -55
  174. package/src/templates/es5.ts +0 -131
  175. package/src/templates/functionLength.ts +0 -32
  176. package/src/templates/globals.ts +0 -3
  177. package/src/transforms/antiTooling.ts +0 -102
  178. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +0 -2146
  179. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +0 -179
  180. package/src/transforms/es5/antiClass.ts +0 -272
  181. package/src/transforms/es5/antiDestructuring.ts +0 -294
  182. package/src/transforms/es5/antiES6Object.ts +0 -267
  183. package/src/transforms/es5/antiSpreadOperator.ts +0 -56
  184. package/src/transforms/es5/antiTemplate.ts +0 -98
  185. package/src/transforms/es5/es5.ts +0 -149
  186. package/src/transforms/extraction/classExtraction.ts +0 -168
  187. package/src/transforms/identifier/globalAnalysis.ts +0 -85
  188. package/src/transforms/identifier/variableAnalysis.ts +0 -118
  189. package/src/transforms/lock/antiDebug.ts +0 -112
  190. package/src/transforms/stack.ts +0 -551
  191. package/src/transforms/transform.ts +0 -453
  192. package/src/traverse.ts +0 -120
  193. package/src/types.ts +0 -131
  194. package/src/util/compare.ts +0 -181
  195. package/src/util/gen.ts +0 -651
  196. package/src/util/guard.ts +0 -7
  197. package/src/util/identifiers.ts +0 -494
  198. package/src/util/insert.ts +0 -419
  199. package/src/util/math.ts +0 -15
  200. package/src/util/object.ts +0 -39
  201. package/src/util/random.ts +0 -141
  202. package/src/util/scope.ts +0 -21
  203. package/test/code/Cash.src.js +0 -1011
  204. package/test/code/Cash.test.ts +0 -49
  205. package/test/code/Dynamic.src.js +0 -118
  206. package/test/code/Dynamic.test.ts +0 -49
  207. package/test/code/ES6.src.js +0 -235
  208. package/test/code/ES6.test.ts +0 -42
  209. package/test/code/NewFeatures.test.ts +0 -19
  210. package/test/code/StrictMode.src.js +0 -65
  211. package/test/code/StrictMode.test.js +0 -37
  212. package/test/compare.test.ts +0 -104
  213. package/test/index.test.ts +0 -249
  214. package/test/options.test.ts +0 -132
  215. package/test/presets.test.ts +0 -22
  216. package/test/probability.test.ts +0 -44
  217. package/test/templates/template.test.ts +0 -14
  218. package/test/transforms/antiTooling.test.ts +0 -52
  219. package/test/transforms/calculator.test.ts +0 -78
  220. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +0 -1274
  221. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +0 -192
  222. package/test/transforms/deadCode.test.ts +0 -85
  223. package/test/transforms/dispatcher.test.ts +0 -457
  224. package/test/transforms/es5/antiClass.test.ts +0 -427
  225. package/test/transforms/es5/antiDestructuring.test.ts +0 -157
  226. package/test/transforms/es5/antiES6Object.test.ts +0 -245
  227. package/test/transforms/es5/antiTemplate.test.ts +0 -116
  228. package/test/transforms/es5/es5.test.ts +0 -110
  229. package/test/transforms/extraction/classExtraction.test.ts +0 -86
  230. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +0 -200
  231. package/test/transforms/extraction/objectExtraction.test.ts +0 -491
  232. package/test/transforms/flatten.test.ts +0 -721
  233. package/test/transforms/hexadecimalNumbers.test.ts +0 -62
  234. package/test/transforms/identifier/globalConcealing.test.ts +0 -72
  235. package/test/transforms/identifier/movedDeclarations.test.ts +0 -275
  236. package/test/transforms/identifier/renameVariables.test.ts +0 -621
  237. package/test/transforms/lock/antiDebug.test.ts +0 -66
  238. package/test/transforms/lock/browserLock.test.ts +0 -129
  239. package/test/transforms/lock/countermeasures.test.ts +0 -100
  240. package/test/transforms/lock/integrity.test.ts +0 -161
  241. package/test/transforms/lock/lock.test.ts +0 -204
  242. package/test/transforms/lock/osLock.test.ts +0 -312
  243. package/test/transforms/lock/selfDefending.test.ts +0 -68
  244. package/test/transforms/minify.test.ts +0 -575
  245. package/test/transforms/opaquePredicates.test.ts +0 -43
  246. package/test/transforms/preparation.test.ts +0 -157
  247. package/test/transforms/renameLabels.test.ts +0 -95
  248. package/test/transforms/rgf.test.ts +0 -378
  249. package/test/transforms/shuffle.test.ts +0 -135
  250. package/test/transforms/stack.test.ts +0 -573
  251. package/test/transforms/string/stringCompression.test.ts +0 -120
  252. package/test/transforms/string/stringConcealing.test.ts +0 -299
  253. package/test/transforms/string/stringEncoding.test.ts +0 -95
  254. package/test/transforms/string/stringSplitting.test.ts +0 -135
  255. package/test/transforms/transform.test.ts +0 -66
  256. package/test/traverse.test.ts +0 -139
  257. package/test/util/compare.test.ts +0 -34
  258. package/test/util/gen.test.ts +0 -121
  259. package/test/util/identifiers.test.ts +0 -253
  260. package/test/util/insert.test.ts +0 -142
  261. package/test/util/math.test.ts +0 -5
  262. package/test/util/random.test.ts +0 -71
  263. /package/dist/{types.js → obfuscationResult.js} +0 -0
@@ -0,0 +1,1182 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _traverse = _interopRequireWildcard(require("@babel/traverse"));
8
+ var _order = require("../order");
9
+ var _probability = require("../probability");
10
+ var _astUtils = require("../utils/ast-utils");
11
+ var t = _interopRequireWildcard(require("@babel/types"));
12
+ var _node = require("../utils/node");
13
+ var _template = _interopRequireDefault(require("../templates/template"));
14
+ var _randomUtils = require("../utils/random-utils");
15
+ var _IntGen = require("../utils/IntGen");
16
+ var _assert = require("assert");
17
+ var _NameGen = require("../utils/NameGen");
18
+ var _constants = require("../constants");
19
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
22
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
23
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
24
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
25
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
26
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
27
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
28
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
29
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
30
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
31
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
32
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
33
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
34
+ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
35
+ function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
36
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
37
+ 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; }
38
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
39
+ 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); }
40
+ /**
41
+ * Breaks functions into DAGs (Directed Acyclic Graphs)
42
+ *
43
+ * - 1. Break functions into chunks
44
+ * - 2. Shuffle chunks but remember their original position
45
+ * - 3. Create a Switch statement inside a While loop, each case is a chunk, and the while loops exits on the last transition.
46
+ *
47
+ * The Switch statement:
48
+ *
49
+ * - 1. The state variable controls which case will run next
50
+ * - 2. At the end of each case, the state variable is updated to the next block of code.
51
+ * - 3. The while loop continues until the the state variable is the end state.
52
+ */
53
+ var _default = exports["default"] = function _default(_ref) {
54
+ var Plugin = _ref.Plugin;
55
+ var me = Plugin(_order.Order.ControlFlowFlattening, {
56
+ changeData: {
57
+ functions: 0,
58
+ blocks: 0,
59
+ ifStatements: 0,
60
+ deadCode: 0,
61
+ variables: 0
62
+ }
63
+ });
64
+
65
+ // in Debug mode, the output is much easier to read
66
+ var isDebug = false;
67
+ var flattenIfStatements = true; // Converts IF-statements into equivalent 'goto style of code'
68
+ var flattenFunctionDeclarations = true; // Converts Function Declarations into equivalent 'goto style of code'
69
+ var addRelativeAssignments = true; // state += (NEW_STATE - CURRENT_STATE)
70
+ var addDeadCode = true; // add fakes chunks of code
71
+ var addFakeTests = true; // case 100: case 490: case 510: ...
72
+ var addComplexTests = true; // case s != 49 && s - 10:
73
+ var addPredicateTests = true; // case scope.A + 10: ...
74
+ var mangleNumericalLiterals = true; // 50 => state + X
75
+ var mangleBooleanLiterals = true; // true => state == X
76
+ var addWithStatement = true; // Disabling not supported yet
77
+
78
+ var cffPrefix = me.getPlaceholder();
79
+
80
+ // Amount of blocks changed by Control Flow Flattening
81
+ var cffCounter = 0;
82
+ var functionsModified = new Set();
83
+ return {
84
+ post: function post() {
85
+ functionsModified.forEach(function (node) {
86
+ node[_constants.UNSAFE] = true;
87
+ });
88
+ },
89
+ visitor: {
90
+ "Program|Function": {
91
+ exit: function exit(_path) {
92
+ var programOrFunctionPath = _path;
93
+
94
+ // Exclude loops
95
+ if (programOrFunctionPath.find(function (p) {
96
+ return p.isForStatement() || p.isWhile();
97
+ })) return;
98
+ var programPath = _path.isProgram() ? _path : null;
99
+ var functionPath = _path.isFunction() ? _path : null;
100
+ var blockPath;
101
+ if (programPath) {
102
+ blockPath = programPath;
103
+ } else {
104
+ var fnBlockPath = functionPath.get("body");
105
+ if (!fnBlockPath.isBlock()) return;
106
+ blockPath = fnBlockPath;
107
+ }
108
+
109
+ // Don't apply to strict mode blocks
110
+ var strictModeEnforcingBlock = programOrFunctionPath.find(function (path) {
111
+ return (0, _astUtils.isStrictMode)(path);
112
+ });
113
+ if (strictModeEnforcingBlock) return;
114
+
115
+ // Must be at least 3 statements or more
116
+ if (blockPath.node.body.length < 3) return;
117
+
118
+ // Check user's threshold setting
119
+ if (!(0, _probability.computeProbabilityMap)(me.options.controlFlowFlattening)) {
120
+ return;
121
+ }
122
+
123
+ // Avoid unsafe functions
124
+ if (functionPath && functionPath.node[_constants.UNSAFE]) return;
125
+ programOrFunctionPath.scope.crawl();
126
+ var blockFnParent = (0, _astUtils.getParentFunctionOrProgram)(blockPath);
127
+ var hasIllegalNode = false;
128
+ var bindingNames = new Set();
129
+ blockPath.traverse({
130
+ "Super|MetaProperty|AwaitExpression|YieldExpression": function SuperMetaPropertyAwaitExpressionYieldExpression(path) {
131
+ if ((0, _astUtils.getParentFunctionOrProgram)(path).node === blockFnParent.node) {
132
+ hasIllegalNode = true;
133
+ path.stop();
134
+ }
135
+ },
136
+ VariableDeclaration: function VariableDeclaration(path) {
137
+ if (path.node.declarations.length !== 1) {
138
+ hasIllegalNode = true;
139
+ path.stop();
140
+ }
141
+ },
142
+ Identifier: function Identifier(path) {
143
+ if (path.node.name === _constants.variableFunctionName || path.node.name === "arguments") {
144
+ hasIllegalNode = true;
145
+ path.stop();
146
+ return;
147
+ }
148
+ if (!path.isBindingIdentifier()) return;
149
+ var binding = path.scope.getBinding(path.node.name);
150
+ if (!binding) return;
151
+ var fnParent = path.getFunctionParent();
152
+ if (path.key === "id" && path.parentPath.isFunctionDeclaration()) {
153
+ fnParent = path.parentPath.getFunctionParent();
154
+ }
155
+ if (fnParent !== functionPath) return;
156
+ if (!(0, _astUtils.isDefiningIdentifier)(path)) {
157
+ return;
158
+ }
159
+ if (bindingNames.has(path.node.name)) {
160
+ hasIllegalNode = true;
161
+ path.stop();
162
+ return;
163
+ }
164
+ bindingNames.add(path.node.name);
165
+ }
166
+ });
167
+ if (hasIllegalNode) {
168
+ return;
169
+ }
170
+ me.changeData.blocks++;
171
+
172
+ // Limit how many numbers get entangled
173
+ var mangledLiteralsCreated = 0;
174
+ var cffIndex = ++cffCounter; // Start from 1
175
+ var prefix = cffPrefix + "_" + cffIndex;
176
+ var withIdentifier = function withIdentifier(suffix) {
177
+ var name;
178
+ if (isDebug) {
179
+ name = prefix + "_" + suffix;
180
+ } else {
181
+ name = me.obfuscator.nameGen.generate(false);
182
+ }
183
+ var id = t.identifier(name);
184
+ id[_constants.NO_RENAME] = cffIndex;
185
+ return id;
186
+ };
187
+ var mainFnName = withIdentifier("main");
188
+ var scopeVar = withIdentifier("scope");
189
+ var stateVars = new Array(isDebug ? 1 : (0, _randomUtils.getRandomInteger)(2, 5)).fill("").map(function (_, i) {
190
+ return withIdentifier("state_".concat(i));
191
+ });
192
+ var argVar = withIdentifier("_arg");
193
+ var _didReturnVar = withIdentifier("return");
194
+ var basicBlocks = new Map();
195
+
196
+ // Map labels to states
197
+ var stateIntGen = new _IntGen.IntGen();
198
+ var defaultBlockPath = blockPath;
199
+ var scopeCounter = 0;
200
+ var scopeNameGen = new _NameGen.NameGen(me.options.identifierGenerator);
201
+ if (!isDebug) {
202
+ scopeNameGen = me.obfuscator.nameGen;
203
+ }
204
+
205
+ // Create 'with' object - Determines which scope gets top-level variable access
206
+ var withProperty = isDebug ? "with" : scopeNameGen.generate(false);
207
+ var withMemberExpression = new _template["default"]("".concat(scopeVar.name, "[\"").concat(withProperty, "\"]")).expression();
208
+ withMemberExpression.object[_constants.NO_RENAME] = cffIndex;
209
+
210
+ // Create 'resetWith' function - Safely resets the 'with' object to none
211
+ var resetWithProperty = isDebug ? "resetWith" : scopeNameGen.generate(false);
212
+ var resetWithMemberExpression = new _template["default"]("".concat(scopeVar.name, "[\"").concat(resetWithProperty, "\"]")).expression();
213
+ resetWithMemberExpression.object[_constants.NO_RENAME] = cffIndex;
214
+ var ScopeManager = /*#__PURE__*/function () {
215
+ function ScopeManager(scope, initializingBasicBlock) {
216
+ _classCallCheck(this, ScopeManager);
217
+ _defineProperty(this, "isNotUsed", true);
218
+ _defineProperty(this, "requiresInitializing", true);
219
+ _defineProperty(this, "nameMap", new Map());
220
+ _defineProperty(this, "nameGen", addWithStatement ? me.obfuscator.nameGen : new _NameGen.NameGen(me.options.identifierGenerator));
221
+ this.scope = scope;
222
+ this.initializingBasicBlock = initializingBasicBlock;
223
+ this.propertyName = isDebug ? "_" + scopeCounter++ : scopeNameGen.generate();
224
+ }
225
+ return _createClass(ScopeManager, [{
226
+ key: "findBestWithDiscriminant",
227
+ value: function findBestWithDiscriminant(basicBlock) {
228
+ var _this$parent;
229
+ if (basicBlock !== this.initializingBasicBlock) {
230
+ if (this.nameMap.size > 0) return this;
231
+ }
232
+ return (_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.findBestWithDiscriminant(basicBlock);
233
+ }
234
+ }, {
235
+ key: "getNewName",
236
+ value: function getNewName(name, originalNode) {
237
+ if (!this.nameMap.has(name)) {
238
+ var newName = this.nameGen.generate(false);
239
+ if (isDebug) {
240
+ newName = "_" + name;
241
+ }
242
+
243
+ // console.log(name, newName);
244
+
245
+ this.nameMap.set(name, newName);
246
+ me.changeData.variables++;
247
+
248
+ // console.log(
249
+ // "Renaming " +
250
+ // name +
251
+ // " to " +
252
+ // newName +
253
+ // " : " +
254
+ // this.scope.path.type
255
+ // );
256
+
257
+ return newName;
258
+ }
259
+ return this.nameMap.get(name);
260
+ }
261
+ }, {
262
+ key: "getScopeObject",
263
+ value: function getScopeObject() {
264
+ return t.memberExpression((0, _node.deepClone)(scopeVar), t.stringLiteral(this.propertyName), true);
265
+ }
266
+ }, {
267
+ key: "getInitializingStatement",
268
+ value: function getInitializingStatement() {
269
+ return t.expressionStatement(t.assignmentExpression("=", this.getScopeObject(), this.getInitializingObjectExpression()));
270
+ }
271
+ }, {
272
+ key: "getInitializingObjectExpression",
273
+ value: function getInitializingObjectExpression() {
274
+ return isDebug ? new _template["default"]("\n ({\n identity: \"".concat(this.propertyName, "\"\n })\n ")).expression() : new _template["default"]("Object[\"create\"](null)").expression();
275
+ }
276
+ }, {
277
+ key: "getMemberExpression",
278
+ value: function getMemberExpression(name) {
279
+ var memberExpression = t.memberExpression(this.getScopeObject(), t.stringLiteral(name), true);
280
+ return memberExpression;
281
+ }
282
+ }, {
283
+ key: "parent",
284
+ get: function get() {
285
+ return scopeToScopeManager.get(this.scope.parent);
286
+ }
287
+ }, {
288
+ key: "getObjectExpression",
289
+ value: function getObjectExpression(refreshLabel) {
290
+ var refreshScope = basicBlocks.get(refreshLabel).scopeManager;
291
+ var propertyMap = {};
292
+ var cursor = this.scope;
293
+ while (cursor) {
294
+ var parentScopeManager = scopeToScopeManager.get(cursor);
295
+ if (parentScopeManager) {
296
+ propertyMap[parentScopeManager.propertyName] = t.memberExpression((0, _node.deepClone)(scopeVar), t.stringLiteral(parentScopeManager.propertyName), true);
297
+ }
298
+ cursor = cursor.parent;
299
+ }
300
+ propertyMap[refreshScope.propertyName] = refreshScope.getInitializingObjectExpression();
301
+ var properties = [];
302
+ for (var key in propertyMap) {
303
+ properties.push(t.objectProperty(t.stringLiteral(key), propertyMap[key], true));
304
+ }
305
+ return t.objectExpression(properties);
306
+ }
307
+ }, {
308
+ key: "hasOwnName",
309
+ value: function hasOwnName(name) {
310
+ return this.nameMap.has(name);
311
+ }
312
+ }]);
313
+ }();
314
+ var getImpossibleBasicBlocks = function getImpossibleBasicBlocks() {
315
+ return Array.from(basicBlocks.values()).filter(function (block) {
316
+ return block.options.impossible;
317
+ });
318
+ };
319
+ var scopeToScopeManager = new Map();
320
+ /**
321
+ * A Basic Block is a sequence of instructions with no diversion except at the entry and exit points.
322
+ */
323
+ var BasicBlock = /*#__PURE__*/function () {
324
+ function BasicBlock(label, parentPath) {
325
+ var _this = this;
326
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
327
+ _classCallCheck(this, BasicBlock);
328
+ _defineProperty(this, "allowWithDiscriminant", true);
329
+ this.label = label;
330
+ this.parentPath = parentPath;
331
+ this.options = options;
332
+ this.createPath();
333
+ if (isDebug) {
334
+ // States in debug mode are just 1, 2, 3, ...
335
+ this.totalState = basicBlocks.size + 1;
336
+ } else {
337
+ this.totalState = stateIntGen.generate();
338
+ }
339
+
340
+ // Correct state values
341
+ // Start with random numbers
342
+ this.stateValues = stateVars.map(function () {
343
+ return (0, _randomUtils.getRandomInteger)(-250, 250);
344
+ });
345
+
346
+ // Try to re-use old state values to make diffs smaller
347
+ if (basicBlocks.size > 1) {
348
+ var lastBlock = _toConsumableArray(basicBlocks.values()).at(-1);
349
+ this.stateValues = lastBlock.stateValues.map(function (oldValue, i) {
350
+ return (0, _randomUtils.choice)([oldValue, _this.stateValues[i]]);
351
+ });
352
+ }
353
+
354
+ // Correct one of the values so that the accumulated sum is equal to the state
355
+ var correctIndex = (0, _randomUtils.getRandomInteger)(0, this.stateValues.length);
356
+ var getCurrentState = function getCurrentState() {
357
+ return _this.stateValues.reduce(function (a, b) {
358
+ return a + b;
359
+ }, 0);
360
+ };
361
+
362
+ // Correct the value
363
+ this.stateValues[correctIndex] = this.totalState - (getCurrentState() - this.stateValues[correctIndex]);
364
+ (0, _assert.ok)(getCurrentState() === this.totalState);
365
+
366
+ // Store basic block
367
+ basicBlocks.set(label, this);
368
+
369
+ // Create a new scope manager if it doesn't exist
370
+ if (!scopeToScopeManager.has(this.scope)) {
371
+ scopeToScopeManager.set(this.scope, new ScopeManager(this.scope, this));
372
+ }
373
+ this.initializedScope = this.scopeManager;
374
+ }
375
+ return _createClass(BasicBlock, [{
376
+ key: "withDiscriminant",
377
+ get: function get() {
378
+ if (!this.allowWithDiscriminant) return null;
379
+ return this.bestWithDiscriminant;
380
+ }
381
+ }, {
382
+ key: "createPath",
383
+ value: function createPath() {
384
+ var newPath = _traverse.NodePath.get({
385
+ hub: this.parentPath.hub,
386
+ parentPath: this.parentPath,
387
+ parent: this.parentPath.node,
388
+ container: this.parentPath.node.body,
389
+ listKey: "body",
390
+ // Set the correct list key
391
+ key: "virtual" // Set the index of the new node
392
+ });
393
+ newPath.scope = this.parentPath.scope;
394
+ newPath.parentPath = this.parentPath;
395
+ newPath.node = t.blockStatement([]);
396
+ this.thisPath = newPath;
397
+ this.thisNode = newPath.node;
398
+ }
399
+ }, {
400
+ key: "insertAfter",
401
+ value: function insertAfter(newNode) {
402
+ this.body.push(newNode);
403
+ }
404
+ }, {
405
+ key: "scope",
406
+ get: function get() {
407
+ return this.parentPath.scope;
408
+ }
409
+ }, {
410
+ key: "scopeManager",
411
+ get: function get() {
412
+ return scopeToScopeManager.get(this.scope);
413
+ }
414
+ }, {
415
+ key: "body",
416
+ get: function get() {
417
+ return this.thisPath.node.body;
418
+ }
419
+ }, {
420
+ key: "createFalsePredicate",
421
+ value: function createFalsePredicate() {
422
+ var predicate = this.createPredicate();
423
+ if (predicate.value) {
424
+ // Make predicate false
425
+ return t.unaryExpression("!", predicate.node);
426
+ }
427
+ return predicate.node;
428
+ }
429
+ }, {
430
+ key: "createTruePredicate",
431
+ value: function createTruePredicate() {
432
+ var predicate = this.createPredicate();
433
+ if (!predicate.value) {
434
+ // Make predicate true
435
+ return t.unaryExpression("!", predicate.node);
436
+ }
437
+ return predicate.node;
438
+ }
439
+ }, {
440
+ key: "createPredicate",
441
+ value: function createPredicate() {
442
+ var stateVarIndex = (0, _randomUtils.getRandomInteger)(0, stateVars.length);
443
+ var stateValue = this.stateValues[stateVarIndex];
444
+ var compareValue = (0, _randomUtils.choice)([stateValue, (0, _randomUtils.getRandomInteger)(-250, 250)]);
445
+ var operator = (0, _randomUtils.choice)(["==", "!=", "<", ">"]);
446
+ var compareResult;
447
+ switch (operator) {
448
+ case "==":
449
+ compareResult = stateValue === compareValue;
450
+ break;
451
+ case "!=":
452
+ compareResult = stateValue !== compareValue;
453
+ break;
454
+ case "<":
455
+ compareResult = stateValue < compareValue;
456
+ break;
457
+ case ">":
458
+ compareResult = stateValue > compareValue;
459
+ break;
460
+ }
461
+ return {
462
+ node: t.binaryExpression(operator, (0, _node.deepClone)(stateVars[stateVarIndex]), (0, _node.numericLiteral)(compareValue)),
463
+ value: compareResult
464
+ };
465
+ }
466
+ }, {
467
+ key: "identifier",
468
+ value: function identifier(identifierName, scopeManager) {
469
+ if (this.withDiscriminant && this.withDiscriminant === scopeManager) {
470
+ var id = t.identifier(identifierName);
471
+ id[_constants.NO_RENAME] = cffIndex;
472
+ id[_constants.WITH_STATEMENT] = true;
473
+ return id;
474
+ }
475
+ return scopeManager.getMemberExpression(identifierName);
476
+ }
477
+ }]);
478
+ }();
479
+ /**
480
+ * Stage 1: Flatten the code into Basic Blocks
481
+ *
482
+ * This involves transforming the Control Flow / Scopes into blocks with 'goto' statements
483
+ *
484
+ * - A block is simply a sequence of statements
485
+ * - A block can have a 'goto' statement to another block
486
+ * - A block original scope is preserved
487
+ *
488
+ * 'goto' & Scopes are transformed in Stage 2
489
+ */
490
+ var switchLabel = me.getPlaceholder();
491
+ var breakStatement = function breakStatement() {
492
+ return t.breakStatement(t.identifier(switchLabel));
493
+ };
494
+ var startLabel = me.getPlaceholder();
495
+ var endLabel = me.getPlaceholder();
496
+ var currentBasicBlock = new BasicBlock(startLabel, blockPath);
497
+ currentBasicBlock.allowWithDiscriminant = false;
498
+ var gotoFunctionName = "GOTO__" + me.getPlaceholder() + "__IF_YOU_CAN_READ_THIS_THERE_IS_A_BUG";
499
+ function GotoControlStatement(label) {
500
+ return new _template["default"]("\n ".concat(gotoFunctionName, "(\"").concat(label, "\");\n ")).single();
501
+ }
502
+
503
+ // Ends the current block and starts a new one
504
+ function endCurrentBasicBlock() {
505
+ var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
506
+ _ref2$jumpToNext = _ref2.jumpToNext,
507
+ jumpToNext = _ref2$jumpToNext === void 0 ? true : _ref2$jumpToNext,
508
+ _ref2$nextLabel = _ref2.nextLabel,
509
+ nextLabel = _ref2$nextLabel === void 0 ? me.getPlaceholder() : _ref2$nextLabel,
510
+ _ref2$prevJumpTo = _ref2.prevJumpTo,
511
+ prevJumpTo = _ref2$prevJumpTo === void 0 ? null : _ref2$prevJumpTo,
512
+ _ref2$nextBlockPath = _ref2.nextBlockPath,
513
+ nextBlockPath = _ref2$nextBlockPath === void 0 ? null : _ref2$nextBlockPath;
514
+ (0, _assert.ok)(nextBlockPath);
515
+ if (prevJumpTo) {
516
+ currentBasicBlock.insertAfter(GotoControlStatement(prevJumpTo));
517
+ } else if (jumpToNext) {
518
+ currentBasicBlock.insertAfter(GotoControlStatement(nextLabel));
519
+ }
520
+ currentBasicBlock = new BasicBlock(nextLabel, nextBlockPath);
521
+ }
522
+ var prependNodes = [];
523
+ var functionExpressions = [];
524
+ function flattenIntoBasicBlocks(bodyIn) {
525
+ // if (!Array.isArray(bodyIn) && bodyIn.isBlock()) {
526
+ // currentBasicBlock.parentPath = bodyIn;
527
+ // }
528
+ var body = Array.isArray(bodyIn) ? bodyIn : bodyIn.get("body");
529
+ var nextBlockPath = Array.isArray(bodyIn) ? currentBasicBlock.parentPath : bodyIn;
530
+ var _loop = function _loop() {
531
+ var statement = body[index];
532
+
533
+ // Keep Imports before everything else
534
+ if (statement.isImportDeclaration()) {
535
+ prependNodes.push(statement.node);
536
+ return 0; // continue
537
+ }
538
+ if (statement.isFunctionDeclaration()) {
539
+ var fnName = statement.node.id.name;
540
+ var isIllegal = false;
541
+ if (!flattenFunctionDeclarations || statement.node.async || statement.node.generator || statement.node[_constants.UNSAFE]) {
542
+ isIllegal = true;
543
+ }
544
+ var oldBasicBlock = currentBasicBlock;
545
+ var _fnLabel = me.getPlaceholder();
546
+ var sm = currentBasicBlock.scopeManager;
547
+ var rename = sm.getNewName(fnName);
548
+ sm.scope.bindings[fnName].kind = "var";
549
+ var hoistedBasicBlock = Array.from(basicBlocks.values()).find(function (block) {
550
+ return block.parentPath === currentBasicBlock.parentPath;
551
+ });
552
+ if (isIllegal) {
553
+ hoistedBasicBlock.body.unshift(statement.node);
554
+ return 0; // continue
555
+ }
556
+ me.changeData.functions++;
557
+ var functionExpression = t.functionExpression(null, [], t.blockStatement([]));
558
+ functionExpressions.push([fnName, _fnLabel, currentBasicBlock, functionExpression]);
559
+
560
+ // Change the function declaration to a variable declaration
561
+ hoistedBasicBlock.body.unshift(t.variableDeclaration("var", [t.variableDeclarator(t.identifier(fnName), functionExpression)]));
562
+ var blockStatement = statement.get("body");
563
+ endCurrentBasicBlock({
564
+ nextLabel: _fnLabel,
565
+ nextBlockPath: blockStatement,
566
+ jumpToNext: false
567
+ });
568
+ var fnTopBlock = currentBasicBlock;
569
+
570
+ // Implicit return
571
+ blockStatement.node.body.push(t.returnStatement(t.identifier("undefined")));
572
+ flattenIntoBasicBlocks(blockStatement);
573
+ scopeToScopeManager.get(statement.scope).requiresInitializing = false;
574
+ basicBlocks.get(_fnLabel).allowWithDiscriminant = false;
575
+
576
+ // Debug label
577
+ if (isDebug) {
578
+ fnTopBlock.body.unshift(t.expressionStatement(t.stringLiteral("Function " + statement.node.id.name + " -> Renamed to " + rename)));
579
+ }
580
+
581
+ // Unpack parameters
582
+ if (statement.node.params.length > 0) {
583
+ fnTopBlock.body.unshift(t.variableDeclaration("var", [t.variableDeclarator(t.arrayPattern(statement.node.params), (0, _node.deepClone)(argVar))]));
584
+
585
+ // Change bindings from 'param' to 'var'
586
+ statement.get("params").forEach(function (param) {
587
+ var ids = param.getBindingIdentifierPaths();
588
+ // Loop over the record of binding identifiers
589
+ for (var identifierName in ids) {
590
+ var identifierPath = ids[identifierName];
591
+ if (identifierPath.getFunctionParent() === statement) {
592
+ var binding = statement.scope.getBinding(identifierName);
593
+ if (binding) {
594
+ binding.kind = "var";
595
+ }
596
+ }
597
+ }
598
+ });
599
+ }
600
+ currentBasicBlock = oldBasicBlock;
601
+ return 0; // continue
602
+ }
603
+
604
+ // Convert IF statements into Basic Blocks
605
+ if (statement.isIfStatement() && flattenIfStatements) {
606
+ var test = statement.get("test");
607
+ var consequent = statement.get("consequent");
608
+ var alternate = statement.get("alternate");
609
+
610
+ // Both consequent and alternate are blocks
611
+ if (consequent.isBlockStatement() && (!alternate.node || alternate.isBlockStatement())) {
612
+ me.changeData.ifStatements++;
613
+ var consequentLabel = me.getPlaceholder();
614
+ var alternateLabel = alternate.node ? me.getPlaceholder() : null;
615
+ var afterPath = me.getPlaceholder();
616
+ currentBasicBlock.insertAfter(t.ifStatement(test.node, GotoControlStatement(consequentLabel), alternateLabel ? GotoControlStatement(alternateLabel) : GotoControlStatement(afterPath)));
617
+ var _oldBasicBlock = currentBasicBlock;
618
+ endCurrentBasicBlock({
619
+ jumpToNext: false,
620
+ nextLabel: consequentLabel,
621
+ nextBlockPath: consequent
622
+ });
623
+ flattenIntoBasicBlocks(consequent);
624
+ currentBasicBlock.initializedScope = _oldBasicBlock.scopeManager;
625
+ if (alternate.isBlockStatement()) {
626
+ endCurrentBasicBlock({
627
+ prevJumpTo: afterPath,
628
+ nextLabel: alternateLabel,
629
+ nextBlockPath: alternate
630
+ });
631
+ flattenIntoBasicBlocks(alternate);
632
+ }
633
+ endCurrentBasicBlock({
634
+ prevJumpTo: afterPath,
635
+ nextLabel: afterPath,
636
+ nextBlockPath: _oldBasicBlock.parentPath
637
+ });
638
+ return 0; // continue
639
+ }
640
+ }
641
+ if (Number(index) === body.length - 1 && statement.isExpressionStatement() && statement.findParent(function (p) {
642
+ return p.isBlock();
643
+ }) === blockPath) {
644
+ // Return the result of the last expression for eval() purposes
645
+ currentBasicBlock.insertAfter(t.returnStatement(statement.get("expression").node));
646
+ return 0; // continue
647
+ }
648
+
649
+ // 3 or more statements should be split more
650
+ if (currentBasicBlock.body.length > 1 && (0, _randomUtils.chance)(50 + currentBasicBlock.body.length)) {
651
+ endCurrentBasicBlock({
652
+ nextBlockPath: nextBlockPath
653
+ });
654
+ }
655
+
656
+ // console.log(currentBasicBlock.thisPath.type);
657
+ // console.log(currentBasicBlock.body);
658
+ currentBasicBlock.body.push(statement.node);
659
+ },
660
+ _ret;
661
+ for (var index in body) {
662
+ _ret = _loop();
663
+ if (_ret === 0) continue;
664
+ }
665
+ }
666
+
667
+ // Convert our code into Basic Blocks
668
+ flattenIntoBasicBlocks(blockPath.get("body"));
669
+
670
+ // Ensure always jumped to the Program end
671
+ endCurrentBasicBlock({
672
+ jumpToNext: true,
673
+ nextLabel: endLabel,
674
+ nextBlockPath: defaultBlockPath
675
+ });
676
+ basicBlocks.get(endLabel).allowWithDiscriminant = false;
677
+
678
+ // Add with / reset with logic
679
+ basicBlocks.get(startLabel).body.unshift(new _template["default"]("\n {resetWithMemberExpression} = function(newStateValues){\n {withMemberExpression} = undefined;\n {arrayPattern} = newStateValues\n }\n ").single({
680
+ arrayPattern: t.arrayPattern((0, _node.deepClone)(stateVars)),
681
+ resetWithMemberExpression: (0, _node.deepClone)(resetWithMemberExpression),
682
+ withMemberExpression: (0, _node.deepClone)(withMemberExpression)
683
+ }));
684
+ if (!isDebug && addDeadCode) {
685
+ // DEAD CODE 1/3: Add fake chunks that are never reached
686
+ var fakeChunkCount = (0, _randomUtils.getRandomInteger)(1, 5);
687
+ for (var i = 0; i < fakeChunkCount; i++) {
688
+ // These chunks just jump somewhere random, they are never executed
689
+ // so it could contain any code
690
+ var fakeBlock = new BasicBlock(me.getPlaceholder(), blockPath, {
691
+ impossible: true
692
+ });
693
+ var fakeJump = void 0;
694
+ do {
695
+ fakeJump = (0, _randomUtils.choice)(Array.from(basicBlocks.keys()));
696
+ } while (fakeJump === fakeBlock.label);
697
+ fakeBlock.insertAfter(GotoControlStatement(fakeJump));
698
+ me.changeData.deadCode++;
699
+ }
700
+
701
+ // DEAD CODE 2/3: Add fake jumps to really mess with deobfuscators
702
+ // "irreducible control flow"
703
+ basicBlocks.forEach(function (basicBlock) {
704
+ if ((0, _randomUtils.chance)(30 - basicBlocks.size)) {
705
+ var randomLabel = (0, _randomUtils.choice)(Array.from(basicBlocks.keys()));
706
+
707
+ // The `false` literal will be mangled
708
+ basicBlock.insertAfter(new _template["default"]("\n if({predicate}){\n {goto}\n }\n ").single({
709
+ "goto": GotoControlStatement(randomLabel),
710
+ predicate: basicBlock.createFalsePredicate()
711
+ }));
712
+ me.changeData.deadCode++;
713
+ }
714
+ });
715
+ // DEAD CODE 3/3: Clone chunks but these chunks are never ran
716
+ var cloneChunkCount = (0, _randomUtils.getRandomInteger)(1, 5);
717
+ var _loop2 = function _loop2() {
718
+ var randomChunk = (0, _randomUtils.choice)(Array.from(basicBlocks.values()));
719
+
720
+ // Don't double define functions
721
+ var hasDeclaration = randomChunk.body.find(function (stmt) {
722
+ return t.isDeclaration(stmt);
723
+ });
724
+ if (!hasDeclaration) {
725
+ var clonedChunk = new BasicBlock(me.getPlaceholder(), randomChunk.parentPath, {
726
+ impossible: true
727
+ });
728
+ randomChunk.thisNode.body.map(function (x) {
729
+ return (0, _node.deepClone)(x);
730
+ }).forEach(function (node) {
731
+ if (node.type === "EmptyStatement") return;
732
+ clonedChunk.insertAfter(node);
733
+ });
734
+ me.changeData.deadCode++;
735
+ }
736
+ };
737
+ for (var _i = 0; _i < cloneChunkCount; _i++) {
738
+ _loop2();
739
+ }
740
+ }
741
+
742
+ // Select scope managers for the with statement
743
+ var _iterator = _createForOfIteratorHelper(basicBlocks.values()),
744
+ _step;
745
+ try {
746
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
747
+ var _basicBlock2$initiali;
748
+ var _basicBlock2 = _step.value;
749
+ _basicBlock2.bestWithDiscriminant = (_basicBlock2$initiali = _basicBlock2.initializedScope) === null || _basicBlock2$initiali === void 0 ? void 0 : _basicBlock2$initiali.findBestWithDiscriminant(_basicBlock2);
750
+ if (isDebug && _basicBlock2.withDiscriminant) {
751
+ _basicBlock2.body.unshift(t.expressionStatement(t.stringLiteral("With " + _basicBlock2.withDiscriminant.propertyName)));
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Stage 2: Transform 'goto' statements into valid JavaScript
757
+ *
758
+ * - 'goto' is replaced with equivalent state updates and break statements
759
+ * - Original identifiers are converted into member expressions
760
+ */
761
+
762
+ // Remap 'GotoStatement' to actual state assignments and Break statements
763
+ } catch (err) {
764
+ _iterator.e(err);
765
+ } finally {
766
+ _iterator.f();
767
+ }
768
+ var _iterator2 = _createForOfIteratorHelper(basicBlocks.values()),
769
+ _step2;
770
+ try {
771
+ var _loop5 = function _loop5() {
772
+ var basicBlock = _step2.value;
773
+ var currentStateValues = basicBlock.stateValues;
774
+ // Wrap the statement in a Babel path to allow traversal
775
+
776
+ var outerFn = (0, _astUtils.getParentFunctionOrProgram)(basicBlock.parentPath);
777
+ function isWithinSameFunction(path) {
778
+ var fn = (0, _astUtils.getParentFunctionOrProgram)(path);
779
+ return fn.node === outerFn.node;
780
+ }
781
+ var visitor = {
782
+ BooleanLiteral: {
783
+ exit: function exit(boolPath) {
784
+ // Don't mangle booleans in debug mode
785
+ if (isDebug || !mangleBooleanLiterals || me.isSkipped(boolPath)) return;
786
+ if (!isWithinSameFunction(boolPath)) return;
787
+ if ((0, _randomUtils.chance)(50 + mangledLiteralsCreated)) return;
788
+ mangledLiteralsCreated++;
789
+ var index = (0, _randomUtils.getRandomInteger)(0, stateVars.length - 1);
790
+ var stateVar = stateVars[index];
791
+ var stateVarValue = currentStateValues[index];
792
+ var compareValue = (0, _randomUtils.choice)([(0, _randomUtils.getRandomInteger)(-250, 250), stateVarValue]);
793
+ var compareResult = stateVarValue === compareValue;
794
+ var newExpression = t.binaryExpression(boolPath.node.value === compareResult ? "==" : "!=", (0, _node.deepClone)(stateVar), (0, _node.numericLiteral)(compareValue));
795
+ (0, _astUtils.ensureComputedExpression)(boolPath);
796
+ boolPath.replaceWith(newExpression);
797
+ }
798
+ },
799
+ // Mangle numbers with the state values
800
+ NumericLiteral: {
801
+ exit: function exit(numPath) {
802
+ // Don't mangle numbers in debug mode
803
+ if (isDebug || !mangleNumericalLiterals || me.isSkipped(numPath)) return;
804
+ var num = numPath.node.value;
805
+ if (Math.floor(num) !== num || Math.abs(num) > 100000 || !Number.isFinite(num) || Number.isNaN(num)) return;
806
+ if (!isWithinSameFunction(numPath)) return;
807
+ if ((0, _randomUtils.chance)(50 + mangledLiteralsCreated)) return;
808
+ mangledLiteralsCreated++;
809
+ var index = (0, _randomUtils.getRandomInteger)(0, stateVars.length - 1);
810
+ var stateVar = stateVars[index];
811
+
812
+ // num = 50
813
+ // stateVar = 30
814
+ // stateVar + 30
815
+
816
+ var diff = t.binaryExpression("+", (0, _node.deepClone)(stateVar), me.skip((0, _node.numericLiteral)(num - currentStateValues[index])));
817
+ (0, _astUtils.ensureComputedExpression)(numPath);
818
+ numPath.replaceWith(diff);
819
+ numPath.skip();
820
+ }
821
+ },
822
+ Identifier: {
823
+ exit: function exit(path) {
824
+ if (!(0, _astUtils.isVariableIdentifier)(path)) return;
825
+ if (me.isSkipped(path)) return;
826
+ if (path.node[_constants.NO_RENAME] === cffIndex) return;
827
+ var identifierName = path.node.name;
828
+ if (identifierName === gotoFunctionName) return;
829
+ var binding = basicBlock.scope.getBinding(identifierName);
830
+ if (!binding) {
831
+ return;
832
+ }
833
+ if (binding.kind === "var" || binding.kind === "let" || binding.kind === "const") {} else {
834
+ return;
835
+ }
836
+
837
+ // console.log("No binding found for " + identifierName);
838
+
839
+ var scopeManager = scopeToScopeManager.get(binding.scope);
840
+ if (!scopeManager) return;
841
+ var newName = scopeManager.getNewName(identifierName, path.node);
842
+ var memberExpression = scopeManager.getMemberExpression(newName);
843
+ scopeManager.isNotUsed = false;
844
+ if ((0, _astUtils.isDefiningIdentifier)(path)) {
845
+ (0, _astUtils.replaceDefiningIdentifierToMemberExpression)(path, memberExpression);
846
+ return;
847
+ }
848
+ if (!path.container) return;
849
+ var isModified = (0, _astUtils.isModifiedIdentifier)(path);
850
+ if (basicBlock.withDiscriminant && basicBlock.withDiscriminant === scopeManager && basicBlock.withDiscriminant.hasOwnName(identifierName)) {
851
+ if (!isModified) {
852
+ memberExpression = basicBlock.identifier(newName, scopeManager);
853
+ }
854
+ }
855
+ me.skip(memberExpression);
856
+ path.replaceWith(memberExpression);
857
+ path.skip();
858
+ }
859
+ },
860
+ // Top-level returns set additional flag to indicate that the function has returned
861
+ ReturnStatement: {
862
+ exit: function exit(path) {
863
+ var functionParent = path.getFunctionParent();
864
+ if (!functionParent || functionParent.get("body") !== blockPath) return;
865
+ var returnArgument = path.node.argument || t.identifier("undefined");
866
+ path.node.argument = new _template["default"]("\n ({didReturnVar} = true, {returnArgument})\n ").expression({
867
+ returnArgument: returnArgument,
868
+ didReturnVar: (0, _node.deepClone)(_didReturnVar)
869
+ });
870
+ }
871
+ },
872
+ // goto() calls are replaced with state updates and break statements
873
+ CallExpression: {
874
+ exit: function exit(path) {
875
+ if (t.isIdentifier(path.node.callee) && path.node.callee.name === gotoFunctionName) {
876
+ var _path$node$arguments = _slicedToArray(path.node.arguments, 1),
877
+ labelNode = _path$node$arguments[0];
878
+ (0, _assert.ok)(t.isStringLiteral(labelNode));
879
+ var _label = labelNode.value;
880
+ var jumpBlock = basicBlocks.get(_label);
881
+ (0, _assert.ok)(jumpBlock, "Label not found: " + _label);
882
+ var newStateValues = jumpBlock.stateValues,
883
+ newTotalState = jumpBlock.totalState;
884
+ var assignments = [];
885
+ var needsIndividualAssignments = true;
886
+ if (jumpBlock.withDiscriminant) {
887
+ assignments.push(t.assignmentExpression("=", (0, _node.deepClone)(withMemberExpression), jumpBlock.withDiscriminant.getScopeObject()));
888
+ } else if (basicBlock.withDiscriminant) {
889
+ assignments.push(t.callExpression((0, _node.deepClone)(resetWithMemberExpression), [t.arrayExpression(newStateValues.map(_node.numericLiteral))]));
890
+ needsIndividualAssignments = false;
891
+ }
892
+ if (needsIndividualAssignments) {
893
+ for (var _i7 = 0; _i7 < stateVars.length; _i7++) {
894
+ var oldValue = currentStateValues[_i7];
895
+ var newValue = newStateValues[_i7];
896
+
897
+ // console.log(oldValue, newValue);
898
+ if (oldValue === newValue) continue; // No diff needed if the value doesn't change
899
+
900
+ var leftValue = jumpBlock.withDiscriminant ? jumpBlock.withDiscriminant.getMemberExpression(stateVars[_i7].name) : (0, _node.deepClone)(stateVars[_i7]);
901
+ var assignment = t.assignmentExpression("=", leftValue, (0, _node.numericLiteral)(newValue));
902
+ if (!isDebug && addRelativeAssignments) {
903
+ // Use diffs to create confusing code
904
+ assignment = t.assignmentExpression("+=", (0, _node.deepClone)(stateVars[_i7]), (0, _node.numericLiteral)(newValue - oldValue));
905
+ }
906
+ assignments.push(assignment);
907
+ }
908
+ }
909
+
910
+ // Add debug label
911
+ if (isDebug) {
912
+ assignments.unshift(t.stringLiteral("Goto " + newTotalState));
913
+ }
914
+ path.parentPath.replaceWith(t.expressionStatement(t.sequenceExpression(assignments)))[0].skip();
915
+
916
+ // Add break after updating state variables
917
+ path.insertAfter(breakStatement());
918
+ }
919
+ }
920
+ }
921
+ };
922
+ basicBlock.thisPath.traverse(visitor);
923
+ };
924
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
925
+ _loop5();
926
+ }
927
+
928
+ /**
929
+ * Stage 3: Create a switch statement to handle the control flow
930
+ *
931
+ * - Add fake / impossible blocks
932
+ * - Add fake / predicates to the switch cases tests
933
+ */
934
+
935
+ // Create global numbers for predicates
936
+ } catch (err) {
937
+ _iterator2.e(err);
938
+ } finally {
939
+ _iterator2.f();
940
+ }
941
+ var mainScope = basicBlocks.get(startLabel).scopeManager;
942
+ var predicateNumbers = new Map();
943
+ var predicateNumberCount = isDebug || !addPredicateTests ? 0 : (0, _randomUtils.getRandomInteger)(2, 5);
944
+ var _loop3 = function _loop3() {
945
+ var name = mainScope.getNewName(me.getPlaceholder("predicate_" + _i2));
946
+ var number = (0, _randomUtils.getRandomInteger)(-250, 250);
947
+ predicateNumbers.set(name, number);
948
+ var createAssignment = function createAssignment(value) {
949
+ return new _template["default"]("\n {memberExpression} = {number}\n ").single({
950
+ memberExpression: mainScope.getMemberExpression(name),
951
+ number: (0, _node.numericLiteral)(number)
952
+ });
953
+ };
954
+ basicBlocks.get(startLabel).body.unshift(createAssignment(number));
955
+
956
+ // Add random assignments to impossible blocks
957
+ fakeAssignmentCount = (0, _randomUtils.getRandomInteger)(0, 3);
958
+ for (var _i8 = 0; _i8 < fakeAssignmentCount; _i8++) {
959
+ impossibleBlock = (0, _randomUtils.choice)(getImpossibleBasicBlocks());
960
+ if (impossibleBlock) {
961
+ impossibleBlock.body.unshift(createAssignment((0, _randomUtils.getRandomInteger)(-250, 250)));
962
+ }
963
+ }
964
+ },
965
+ fakeAssignmentCount,
966
+ impossibleBlock;
967
+ for (var _i2 = 0; _i2 < predicateNumberCount; _i2++) {
968
+ _loop3();
969
+ }
970
+
971
+ // Add scope initializations: scope["_0"] = {identity: "_0"}
972
+ var _iterator3 = _createForOfIteratorHelper(scopeToScopeManager.values()),
973
+ _step3;
974
+ try {
975
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
976
+ var _scopeManager = _step3.value;
977
+ if (_scopeManager.isNotUsed) continue;
978
+ if (!_scopeManager.requiresInitializing) continue;
979
+ if (_scopeManager.initializingBasicBlock.label === startLabel) continue;
980
+ _scopeManager.initializingBasicBlock.body.unshift(_scopeManager.getInitializingStatement());
981
+ }
982
+ } catch (err) {
983
+ _iterator3.e(err);
984
+ } finally {
985
+ _iterator3.f();
986
+ }
987
+ var switchCases = [];
988
+ var blocks = Array.from(basicBlocks.values());
989
+ if (!isDebug && addFakeTests) {
990
+ (0, _randomUtils.shuffle)(blocks);
991
+ }
992
+ var _loop4 = function _loop4() {
993
+ var block = _blocks[_i3];
994
+ if (block.label === endLabel) {
995
+ // ok(block.body.length === 0);
996
+ return 1; // continue
997
+ }
998
+ var test = (0, _node.numericLiteral)(block.totalState);
999
+
1000
+ // Predicate tests cannot apply to the start label
1001
+ // As that's when the numbers are initialized
1002
+ if (!isDebug && addPredicateTests && block.label !== startLabel && (0, _randomUtils.chance)(50)) {
1003
+ var predicateName = (0, _randomUtils.choice)(Array.from(predicateNumbers.keys()));
1004
+ if (predicateName) {
1005
+ var number = predicateNumbers.get(predicateName);
1006
+ var diff = block.totalState - number;
1007
+ test = t.binaryExpression("+", mainScope.getMemberExpression(predicateName), (0, _node.numericLiteral)(diff));
1008
+ }
1009
+ }
1010
+
1011
+ // Add complex tests
1012
+ if (!isDebug && addComplexTests && (0, _randomUtils.chance)(50)) {
1013
+ // Create complex test expressions for each switch case
1014
+
1015
+ // case STATE+X:
1016
+ var stateVarIndex = (0, _randomUtils.getRandomInteger)(0, stateVars.length);
1017
+ var stateValues = block.stateValues;
1018
+ var difference = stateValues[stateVarIndex] - block.totalState;
1019
+ var conditionNodes = [];
1020
+ var alreadyConditionedItems = new Set();
1021
+
1022
+ // This code finds clash conditions and adds them to 'conditionNodes' array
1023
+ Array.from(basicBlocks.keys()).forEach(function (label) {
1024
+ if (label !== block.label) {
1025
+ var labelStates = basicBlocks.get(label).stateValues;
1026
+ var totalState = labelStates.reduce(function (a, b) {
1027
+ return a + b;
1028
+ }, 0);
1029
+ if (totalState === labelStates[stateVarIndex] - difference) {
1030
+ var differentIndex = labelStates.findIndex(function (v, i) {
1031
+ return v !== stateValues[i];
1032
+ });
1033
+ if (differentIndex !== -1) {
1034
+ var expressionAsString = stateVars[differentIndex].name + "!=" + labelStates[differentIndex];
1035
+ if (!alreadyConditionedItems.has(expressionAsString)) {
1036
+ alreadyConditionedItems.add(expressionAsString);
1037
+ conditionNodes.push(t.binaryExpression("!=", (0, _node.deepClone)(stateVars[differentIndex]), (0, _node.numericLiteral)(labelStates[differentIndex])));
1038
+ }
1039
+ } else {
1040
+ conditionNodes.push(t.binaryExpression("!=", (0, _node.deepClone)(discriminant), (0, _node.numericLiteral)(totalState)));
1041
+ }
1042
+ }
1043
+ }
1044
+ });
1045
+
1046
+ // case STATE!=Y && STATE+X
1047
+ test = t.binaryExpression("-", (0, _node.deepClone)(stateVars[stateVarIndex]), (0, _node.numericLiteral)(difference));
1048
+
1049
+ // Use the 'conditionNodes' to not cause state clashing issues
1050
+ conditionNodes.forEach(function (conditionNode) {
1051
+ test = t.logicalExpression("&&", conditionNode, test);
1052
+ });
1053
+ }
1054
+ var tests = [test];
1055
+ if (!isDebug && addFakeTests && (0, _randomUtils.chance)(50)) {
1056
+ // Add fake tests
1057
+ var fakeTestCount = (0, _randomUtils.getRandomInteger)(1, 3);
1058
+ for (var _i4 = 0; _i4 < fakeTestCount; _i4++) {
1059
+ tests.push((0, _node.numericLiteral)(stateIntGen.generate()));
1060
+ }
1061
+ (0, _randomUtils.shuffle)(tests);
1062
+ }
1063
+ var lastTest = tests.pop();
1064
+ for (var _i5 = 0, _tests = tests; _i5 < _tests.length; _i5++) {
1065
+ var _test = _tests[_i5];
1066
+ switchCases.push(t.switchCase(_test, []));
1067
+ }
1068
+ switchCases.push(t.switchCase(lastTest, block.thisPath.node.body));
1069
+ };
1070
+ for (var _i3 = 0, _blocks = blocks; _i3 < _blocks.length; _i3++) {
1071
+ if (_loop4()) continue;
1072
+ }
1073
+ if (!isDebug && addFakeTests) {
1074
+ // A random test can be 'default'
1075
+ (0, _randomUtils.choice)(switchCases).test = null;
1076
+ }
1077
+ var discriminant = new _template["default"]("\n ".concat(stateVars.map(function (x) {
1078
+ return x.name;
1079
+ }).join(" + "), "\n ")).expression();
1080
+ (0, _traverse["default"])(t.program([t.expressionStatement(discriminant)]), {
1081
+ Identifier: function Identifier(path) {
1082
+ path.node[_constants.NO_RENAME] = cffIndex;
1083
+ }
1084
+ });
1085
+
1086
+ // Create a new SwitchStatement
1087
+ var switchStatement = t.labeledStatement(t.identifier(switchLabel), t.switchStatement(discriminant, switchCases));
1088
+ var startStateValues = basicBlocks.get(startLabel).stateValues;
1089
+ var endTotalState = basicBlocks.get(endLabel).totalState;
1090
+ 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({
1091
+ withDiscriminant: (0, _node.deepClone)(withMemberExpression)
1092
+ }), t.blockStatement([switchStatement]))]));
1093
+ var parameters = [].concat(_toConsumableArray(stateVars), [argVar, scopeVar]).map(function (id) {
1094
+ return (0, _node.deepClone)(id);
1095
+ });
1096
+ var parametersNames = parameters.map(function (id) {
1097
+ return id.name;
1098
+ });
1099
+ for (var _i6 = 0, _functionExpressions = functionExpressions; _i6 < _functionExpressions.length; _i6++) {
1100
+ var _functionExpressions$ = _slicedToArray(_functionExpressions[_i6], 4),
1101
+ originalFnName = _functionExpressions$[0],
1102
+ fnLabel = _functionExpressions$[1],
1103
+ basicBlock = _functionExpressions$[2],
1104
+ fn = _functionExpressions$[3];
1105
+ var _basicBlock = basicBlock,
1106
+ scopeManager = _basicBlock.scopeManager;
1107
+ var _basicBlocks$get = basicBlocks.get(fnLabel),
1108
+ stateValues = _basicBlocks$get.stateValues;
1109
+ var argumentsRestName = me.getPlaceholder();
1110
+ var argumentsNodes = [];
1111
+ var _iterator4 = _createForOfIteratorHelper(parametersNames),
1112
+ _step4;
1113
+ try {
1114
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1115
+ var parameterName = _step4.value;
1116
+ var stateIndex = stateVars.map(function (x) {
1117
+ return x.name;
1118
+ }).indexOf(parameterName);
1119
+ if (stateIndex !== -1) {
1120
+ argumentsNodes.push((0, _node.numericLiteral)(stateValues[stateIndex]));
1121
+ } else if (parameterName === argVar.name) {
1122
+ argumentsNodes.push(t.identifier(argumentsRestName));
1123
+ } else if (parameterName === scopeVar.name) {
1124
+ argumentsNodes.push(scopeManager.getObjectExpression(fnLabel));
1125
+ } else {
1126
+ (0, _assert.ok)(false);
1127
+ }
1128
+ }
1129
+ } catch (err) {
1130
+ _iterator4.e(err);
1131
+ } finally {
1132
+ _iterator4.f();
1133
+ }
1134
+ 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({
1135
+ callExpression: t.callExpression((0, _node.deepClone)(mainFnName), argumentsNodes)
1136
+ }));
1137
+ }
1138
+ var mainFnDeclaration = t.functionDeclaration((0, _node.deepClone)(mainFnName), parameters, t.blockStatement([whileStatement]));
1139
+ mainFnDeclaration[_constants.PREDICTABLE] = true;
1140
+ var startProgramExpression = t.callExpression((0, _node.deepClone)(mainFnName), [].concat(_toConsumableArray(startStateValues.map(function (stateValue) {
1141
+ return (0, _node.numericLiteral)(stateValue);
1142
+ })), [t.identifier("undefined"), basicBlocks.get(startLabel).scopeManager.getObjectExpression(startLabel)]));
1143
+ var _resultVar = withIdentifier("result");
1144
+ var allowReturns = blockPath.find(function (p) {
1145
+ return p.isFunction();
1146
+ });
1147
+ 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({
1148
+ startProgramExpression: startProgramExpression,
1149
+ didReturnVar: function didReturnVar() {
1150
+ return (0, _node.deepClone)(_didReturnVar);
1151
+ },
1152
+ resultVar: function resultVar() {
1153
+ return (0, _node.deepClone)(_resultVar);
1154
+ }
1155
+ });
1156
+ blockPath.node.body = [].concat(prependNodes, [mainFnDeclaration], _toConsumableArray(startProgramStatements));
1157
+ functionsModified.add(programOrFunctionPath.node);
1158
+
1159
+ // Reset all bindings here
1160
+ blockPath.scope.bindings = Object.create(null);
1161
+
1162
+ // Bindings changed - breaking control objects
1163
+ delete blockPath.node[_constants.CONTROL_OBJECTS];
1164
+
1165
+ // Register new declarations
1166
+ var _iterator5 = _createForOfIteratorHelper(blockPath.get("body")),
1167
+ _step5;
1168
+ try {
1169
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1170
+ var node = _step5.value;
1171
+ blockPath.scope.registerDeclaration(node);
1172
+ }
1173
+ } catch (err) {
1174
+ _iterator5.e(err);
1175
+ } finally {
1176
+ _iterator5.f();
1177
+ }
1178
+ }
1179
+ }
1180
+ }
1181
+ };
1182
+ };