js-confuser 1.5.8 → 1.6.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 (139) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +69 -0
  3. package/README.md +143 -7
  4. package/dist/index.js +33 -4
  5. package/dist/obfuscator.js +30 -31
  6. package/dist/options.js +4 -5
  7. package/dist/order.js +4 -6
  8. package/dist/probability.js +2 -4
  9. package/dist/templates/bufferToString.js +13 -0
  10. package/dist/templates/crash.js +2 -2
  11. package/dist/templates/es5.js +18 -0
  12. package/dist/transforms/antiTooling.js +1 -1
  13. package/dist/transforms/calculator.js +77 -21
  14. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  15. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
  16. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  17. package/dist/transforms/deadCode.js +33 -25
  18. package/dist/transforms/dispatcher.js +7 -6
  19. package/dist/transforms/es5/antiClass.js +6 -2
  20. package/dist/transforms/es5/antiDestructuring.js +3 -1
  21. package/dist/transforms/es5/es5.js +31 -34
  22. package/dist/transforms/eval.js +11 -0
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
  24. package/dist/transforms/extraction/objectExtraction.js +6 -1
  25. package/dist/transforms/finalizer.js +82 -0
  26. package/dist/transforms/flatten.js +82 -55
  27. package/dist/transforms/hexadecimalNumbers.js +34 -9
  28. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  29. package/dist/transforms/identifier/globalConcealing.js +10 -83
  30. package/dist/transforms/identifier/movedDeclarations.js +2 -8
  31. package/dist/transforms/identifier/renameVariables.js +39 -27
  32. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  33. package/dist/transforms/minify.js +80 -61
  34. package/dist/transforms/opaquePredicates.js +1 -1
  35. package/dist/transforms/preparation/preparation.js +2 -2
  36. package/dist/transforms/preparation.js +231 -0
  37. package/dist/transforms/renameLabels.js +1 -1
  38. package/dist/transforms/rgf.js +4 -5
  39. package/dist/transforms/stack.js +87 -26
  40. package/dist/transforms/string/encoding.js +150 -179
  41. package/dist/transforms/string/stringCompression.js +14 -15
  42. package/dist/transforms/string/stringConcealing.js +25 -8
  43. package/dist/transforms/string/stringEncoding.js +13 -24
  44. package/dist/transforms/transform.js +11 -18
  45. package/dist/traverse.js +24 -18
  46. package/dist/util/compare.js +2 -2
  47. package/dist/util/gen.js +15 -0
  48. package/dist/util/insert.js +31 -7
  49. package/dist/util/random.js +15 -0
  50. package/package.json +5 -5
  51. package/src/index.ts +57 -19
  52. package/src/obfuscator.ts +26 -29
  53. package/src/options.ts +17 -21
  54. package/src/order.ts +4 -8
  55. package/src/probability.ts +2 -3
  56. package/src/templates/bufferToString.ts +68 -0
  57. package/src/templates/crash.ts +5 -9
  58. package/src/templates/es5.ts +131 -0
  59. package/src/transforms/antiTooling.ts +1 -1
  60. package/src/transforms/calculator.ts +122 -59
  61. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  62. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
  63. package/src/transforms/deadCode.ts +383 -26
  64. package/src/transforms/dispatcher.ts +8 -6
  65. package/src/transforms/es5/antiClass.ts +10 -1
  66. package/src/transforms/es5/antiDestructuring.ts +3 -1
  67. package/src/transforms/es5/es5.ts +32 -77
  68. package/src/transforms/eval.ts +18 -0
  69. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
  70. package/src/transforms/extraction/objectExtraction.ts +12 -5
  71. package/src/transforms/finalizer.ts +75 -0
  72. package/src/transforms/flatten.ts +194 -151
  73. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  74. package/src/transforms/identifier/globalConcealing.ts +14 -103
  75. package/src/transforms/identifier/movedDeclarations.ts +4 -11
  76. package/src/transforms/identifier/renameVariables.ts +37 -30
  77. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  78. package/src/transforms/minify.ts +116 -77
  79. package/src/transforms/opaquePredicates.ts +2 -2
  80. package/src/transforms/preparation.ts +238 -0
  81. package/src/transforms/renameLabels.ts +2 -2
  82. package/src/transforms/rgf.ts +6 -7
  83. package/src/transforms/stack.ts +97 -37
  84. package/src/transforms/string/encoding.ts +115 -212
  85. package/src/transforms/string/stringCompression.ts +27 -18
  86. package/src/transforms/string/stringConcealing.ts +41 -11
  87. package/src/transforms/string/stringEncoding.ts +18 -18
  88. package/src/transforms/transform.ts +15 -21
  89. package/src/traverse.ts +24 -12
  90. package/src/types.ts +11 -2
  91. package/src/util/compare.ts +2 -2
  92. package/src/util/gen.ts +21 -1
  93. package/src/util/insert.ts +49 -9
  94. package/src/util/random.ts +13 -0
  95. package/test/code/Cash.test.ts +1 -1
  96. package/test/code/Dynamic.test.ts +12 -10
  97. package/test/code/ES6.src.js +136 -0
  98. package/test/code/ES6.test.ts +28 -2
  99. package/test/code/NewFeatures.test.ts +19 -0
  100. package/test/index.test.ts +15 -2
  101. package/test/probability.test.ts +44 -0
  102. package/test/templates/template.test.ts +1 -1
  103. package/test/transforms/antiTooling.test.ts +52 -0
  104. package/test/transforms/calculator.test.ts +40 -0
  105. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
  106. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  107. package/test/transforms/deadCode.test.ts +66 -15
  108. package/test/transforms/dispatcher.test.ts +44 -1
  109. package/test/transforms/es5/antiClass.test.ts +33 -0
  110. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  111. package/test/transforms/eval.test.ts +53 -0
  112. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  113. package/test/transforms/flatten.test.ts +195 -3
  114. package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
  115. package/test/transforms/identifier/renameVariables.test.ts +108 -0
  116. package/test/transforms/lock/antiDebug.test.ts +2 -2
  117. package/test/transforms/minify.test.ts +151 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +56 -29
  120. package/test/transforms/stack.test.ts +91 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +115 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/compare.test.ts +23 -1
  127. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  128. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  129. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  130. package/src/transforms/hexadecimalNumbers.ts +0 -31
  131. package/src/transforms/hideInitializingCode.ts +0 -432
  132. package/src/transforms/label.ts +0 -64
  133. package/src/transforms/preparation/nameConflicts.ts +0 -102
  134. package/src/transforms/preparation/preparation.ts +0 -176
  135. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  136. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  137. package/test/transforms/hideInitializingCode.test.ts +0 -336
  138. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  139. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -30,28 +30,29 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
30
30
  /**
31
31
  * Rename variables to randomly generated names.
32
32
  *
33
- * - Attempts to re-use already generated names in nested scopes.
33
+ * - 1. First collect data on identifiers in all scope using 'VariableAnalysis'
34
+ * - 2. After 'VariableAnalysis' is finished start applying to each scope (top-down)
35
+ * - 3. Each scope, find the all names used here and exclude those names from being re-named
36
+ * - 4. Now loop through all the defined names in this scope and set it to a random name (or re-use previously generated name)
37
+ * - 5. Update all the Identifiers node's 'name' property to reflect this change
34
38
  */
35
39
  class RenameVariables extends _transform.default {
36
- // Generator object
37
40
  // Names already used
38
41
  // Map of Context->Object of changes
39
42
  // Ref to VariableAnalysis data
40
43
  constructor(o) {
41
44
  super(o, _order.ObfuscateOrder.RenameVariables);
42
45
 
43
- _defineProperty(this, "gen", void 0);
44
-
45
46
  _defineProperty(this, "generated", void 0);
46
47
 
47
48
  _defineProperty(this, "changed", void 0);
48
49
 
49
50
  _defineProperty(this, "variableAnalysis", void 0);
50
51
 
51
- this.changed = new Map();
52
+ this.changed = new Map(); // 1.
53
+
52
54
  this.variableAnalysis = new _variableAnalysis.default(o);
53
55
  this.before.push(this.variableAnalysis);
54
- this.gen = this.getGenerator();
55
56
  this.generated = [];
56
57
  }
57
58
 
@@ -60,22 +61,24 @@ class RenameVariables extends _transform.default {
60
61
  }
61
62
 
62
63
  transform(object, parents) {
64
+ // 2. Notice this is on 'onEnter' (top-down)
63
65
  var isGlobal = object.type == "Program";
64
66
  var type = isGlobal ? "root" : (0, _insert.isVarContext)(object) ? "var" : (0, _insert.isLexContext)(object) ? "lex" : undefined;
65
67
  (0, _assert.ok)(type);
66
68
  var newNames = Object.create(null);
67
69
  var defined = this.variableAnalysis.defined.get(object) || new Set();
68
- var references = this.variableAnalysis.references.get(object) || new Set();
70
+ var references = this.variableAnalysis.references.get(object) || new Set(); // No changes needed here
69
71
 
70
72
  if (!defined && !this.changed.has(object)) {
71
73
  this.changed.set(object, Object.create(null));
72
74
  return;
73
- }
75
+ } // Names possible to be re-used here
76
+
74
77
 
75
- var possible = new Set();
78
+ var possible = new Set(); // 3. Try to re-use names when possible
76
79
 
77
80
  if (this.generated.length && !isGlobal) {
78
- var allReferences = new Set(references || []);
81
+ var allReferences = new Set();
79
82
  var nope = new Set(defined);
80
83
  (0, _traverse.walk)(object, [], (o, p) => {
81
84
  var ref = this.variableAnalysis.references.get(o);
@@ -98,7 +101,7 @@ class RenameVariables extends _transform.default {
98
101
  Object.keys(changes).forEach(x => {
99
102
  var name = changes[x];
100
103
 
101
- if (!allReferences.has(x)) {
104
+ if (!allReferences.has(x) && !references.has(x)) {
102
105
  passed.add(name);
103
106
  } else {
104
107
  nope.add(name);
@@ -108,38 +111,51 @@ class RenameVariables extends _transform.default {
108
111
  });
109
112
  nope.forEach(x => passed.delete(x));
110
113
  possible = passed;
111
- }
114
+ } // 4. Defined names to new names
115
+
112
116
 
113
- defined.forEach(name => {
114
- if ((isGlobal && !name.startsWith("__p_") ? (0, _probability.ComputeProbabilityMap)(this.options.renameGlobals, x => x, name) : true) && (0, _probability.ComputeProbabilityMap)(this.options.renameVariables, x => x, name, isGlobal)) {
115
- // Fix 2. Ensure global names aren't overridden
117
+ for (var name of defined) {
118
+ if (!name.startsWith("__NO_JS_CONFUSER_RENAME__") && ( // Variables prefixed with '__NO_JS_CONFUSER_RENAME__' are never renamed
119
+ isGlobal && !name.startsWith("__p_") // Variables prefixed with '__p_' are created by the obfuscator, always renamed
120
+ ? (0, _probability.ComputeProbabilityMap)(this.options.renameGlobals, x => x, name) : true) && (0, _probability.ComputeProbabilityMap)( // Check the user's option for renaming variables
121
+ this.options.renameVariables, x => x, name, isGlobal)) {
122
+ // Create a new name from (1) or (2) methods
116
123
  var newName;
117
124
 
118
125
  do {
119
126
  if (possible.size) {
127
+ // (1) Re-use previously generated name
120
128
  var first = possible.values().next().value;
121
129
  possible.delete(first);
122
130
  newName = first;
123
131
  } else {
124
- // Fix 1. Use `generateIdentifier` over `gen.generate()` so Integrity can get unique variable names
125
- var g = this.generateIdentifier();
126
- newName = g;
127
- this.generated.push(g);
132
+ // (2) Create a new name with `generateIdentifier` function
133
+ var generatedName = this.generateIdentifier();
134
+ newName = generatedName;
135
+ this.generated.push(generatedName);
128
136
  }
129
- } while (this.variableAnalysis.globals.has(newName));
137
+ } while (this.variableAnalysis.globals.has(newName)); // Ensure global names aren't overridden
138
+
130
139
 
131
140
  newNames[name] = newName;
132
141
  } else {
142
+ // This variable name was deemed not to be renamed.
133
143
  newNames[name] = name;
134
144
  }
135
- });
136
- this.changed.set(object, newNames);
145
+ }
146
+
147
+ this.changed.set(object, newNames); // 5. Update Identifier node's 'name' property
148
+
137
149
  (0, _traverse.walk)(object, parents, (o, p) => {
138
150
  if (o.type == "Identifier") {
139
151
  if (_constants.reservedIdentifiers.has(o.name) || this.options.globalVariables.has(o.name)) {
140
152
  return;
141
153
  }
142
154
 
155
+ if (o.$renamed) {
156
+ return;
157
+ }
158
+
143
159
  var info = (0, _identifiers.getIdentifierInfo)(o, p);
144
160
 
145
161
  if (info.spec.isExported) {
@@ -163,11 +179,7 @@ class RenameVariables extends _transform.default {
163
179
  }
164
180
 
165
181
  if (newName && typeof newName === "string") {
166
- if (o.$renamed) {
167
- return;
168
- } // Strange behavior where the `local` and `imported` objects are the same
169
-
170
-
182
+ // Strange behavior where the `local` and `imported` objects are the same
171
183
  if (info.isImportSpecifier) {
172
184
  var importSpecifierIndex = p.findIndex(x => x.type === "ImportSpecifier");
173
185
 
@@ -9,8 +9,6 @@ var _assert = require("assert");
9
9
 
10
10
  var _constants = require("../../constants");
11
11
 
12
- var _traverse = require("../../traverse");
13
-
14
12
  var _compare = require("../../util/compare");
15
13
 
16
14
  var _identifiers = require("../../util/identifiers");
@@ -37,10 +35,12 @@ class VariableAnalysis extends _transform.default {
37
35
 
38
36
  /**
39
37
  * Set of global identifiers to never be redefined
38
+ *
39
+ * - Used to not accidentally block access to a global variable
40
40
  */
41
41
 
42
42
  /**
43
- * Set of identifers that are defined within the program
43
+ * Set of identifiers that are defined within the program
44
44
  */
45
45
  constructor(o) {
46
46
  super(o);
@@ -60,72 +60,68 @@ class VariableAnalysis extends _transform.default {
60
60
  }
61
61
 
62
62
  match(object, parents) {
63
- return (0, _insert.isContext)(object);
63
+ return object.type === "Identifier";
64
64
  }
65
65
 
66
66
  transform(object, parents) {
67
- (0, _traverse.walk)(object, parents, (o, p) => {
68
- if (o.type == "Identifier") {
69
- var name = o.name;
70
- (0, _assert.ok)(typeof name === "string");
71
-
72
- if (!(0, _compare.isValidIdentifier)(name)) {
73
- return;
74
- }
75
-
76
- if (_constants.reservedIdentifiers.has(name)) {
77
- return;
78
- }
79
-
80
- if (this.options.globalVariables.has(name)) {
81
- return;
82
- }
83
-
84
- var info = (0, _identifiers.getIdentifierInfo)(o, p);
85
-
86
- if (!info.spec.isReferenced) {
87
- return;
88
- }
89
-
90
- if (info.spec.isExported) {
91
- return;
67
+ var name = object.name;
68
+ (0, _assert.ok)(typeof name === "string");
69
+
70
+ if (!(0, _compare.isValidIdentifier)(name)) {
71
+ return;
72
+ }
73
+
74
+ if (_constants.reservedIdentifiers.has(name)) {
75
+ return;
76
+ }
77
+
78
+ if (this.options.globalVariables.has(name)) {
79
+ return;
80
+ }
81
+
82
+ var info = (0, _identifiers.getIdentifierInfo)(object, parents);
83
+
84
+ if (!info.spec.isReferenced) {
85
+ return;
86
+ }
87
+
88
+ if (info.spec.isExported) {
89
+ return;
90
+ }
91
+
92
+ var isDefined = info.spec.isDefined; // Keep track of defined names within the program
93
+
94
+ if (isDefined) {
95
+ this.notGlobals.add(object.name);
96
+ this.globals.delete(object.name);
97
+ } else if (!this.notGlobals.has(object.name)) {
98
+ this.globals.add(object.name);
99
+ }
100
+
101
+ var definingContexts = info.spec.isDefined ? (0, _insert.getAllDefiningContexts)(object, parents) : (0, _insert.getReferencingContexts)(object, parents, info);
102
+ (0, _assert.ok)(definingContexts.length);
103
+ definingContexts.forEach(definingContext => {
104
+ // ok(
105
+ // isContext(definingContext),
106
+ // `${definingContext.type} is not a context`
107
+ // );
108
+ if (isDefined) {
109
+ // Add to defined Map
110
+ if (!this.defined.has(definingContext)) {
111
+ this.defined.set(definingContext, new Set());
92
112
  }
93
113
 
94
- var isDefined = info.spec.isDefined; // Keep track of defined names within the program
114
+ this.defined.get(definingContext).add(name);
115
+ this.references.has(definingContext) && this.references.get(definingContext).delete(name);
116
+ } else {
117
+ // Add to references Map
118
+ if (!this.defined.has(definingContext) || !this.defined.get(definingContext).has(name)) {
119
+ if (!this.references.has(definingContext)) {
120
+ this.references.set(definingContext, new Set());
121
+ }
95
122
 
96
- if (isDefined) {
97
- this.notGlobals.add(o.name);
98
- this.globals.delete(o.name);
99
- } else if (!this.notGlobals.has(o.name)) {
100
- this.globals.add(o.name);
123
+ this.references.get(definingContext).add(name);
101
124
  }
102
-
103
- var definingContexts = info.spec.isDefined ? (0, _insert.getAllDefiningContexts)(o, p) : (0, _insert.getReferencingContexts)(o, p, info);
104
- (0, _assert.ok)(definingContexts.length);
105
- definingContexts.forEach(definingContext => {
106
- // ok(
107
- // isContext(definingContext),
108
- // `${definingContext.type} is not a context`
109
- // );
110
- if (isDefined) {
111
- // Add to defined Map
112
- if (!this.defined.has(definingContext)) {
113
- this.defined.set(definingContext, new Set());
114
- }
115
-
116
- this.defined.get(definingContext).add(name);
117
- this.references.has(definingContext) && this.references.get(definingContext).delete(name);
118
- } else {
119
- // Add to references Map
120
- if (!this.defined.has(definingContext) || !this.defined.get(definingContext).has(name)) {
121
- if (!this.references.has(definingContext)) {
122
- this.references.set(definingContext, new Set());
123
- }
124
-
125
- this.references.get(definingContext).add(name);
126
- }
127
- }
128
- });
129
125
  }
130
126
  });
131
127
  }
@@ -21,6 +21,8 @@ var _assert = require("assert");
21
21
 
22
22
  var _scope = require("../util/scope");
23
23
 
24
+ var _template = _interopRequireDefault(require("../templates/template"));
25
+
24
26
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
27
 
26
28
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -34,12 +36,13 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
34
36
  * - `x['y']` **->** `x.y`
35
37
  */
36
38
  class Minify extends _transform.default {
39
+ /**
40
+ * A helper function that is introduced preserve function semantics
41
+ */
37
42
  constructor(o) {
38
43
  super(o, _order.ObfuscateOrder.Minify);
39
44
 
40
- _defineProperty(this, "variables", void 0);
41
-
42
- this.variables = new Map();
45
+ _defineProperty(this, "arrowFunctionName", void 0);
43
46
  }
44
47
 
45
48
  match(object, parents) {
@@ -75,7 +78,7 @@ class Minify extends _transform.default {
75
78
  var startIndex = -1;
76
79
  var sequences = [];
77
80
  body.forEach((stmt, i) => {
78
- if (stmt.type == "ExpressionStatement") {
81
+ if (stmt.type == "ExpressionStatement" && !stmt.directive) {
79
82
  exprs.push(stmt.expression);
80
83
 
81
84
  if (startIndex == -1) {
@@ -105,48 +108,44 @@ class Minify extends _transform.default {
105
108
  (0, _assert.ok)(seq.index != -1);
106
109
  body.splice(seq.index, seq.exprs.length, (0, _gen.ExpressionStatement)(seq.exprs.length == 1 ? seq.exprs[0] : (0, _gen.SequenceExpression)(seq.exprs)));
107
110
  });
108
- }
111
+ } // Unnecessary return
109
112
 
110
- if (object.type != "SwitchCase") {
111
- // Unnecessary return
112
- if (body.length && body[body.length - 1]) {
113
- var last = body[body.length - 1];
114
113
 
115
- if (last.type == "ReturnStatement") {
116
- var isUndefined = last.argument == null;
114
+ if (parents[0] && (0, _insert.isVarContext)(parents[0]) && body.length && body[body.length - 1]) {
115
+ var last = body[body.length - 1];
117
116
 
118
- if (isUndefined) {
119
- if ((0, _insert.getFunction)(object, parents).body == object) {
120
- body.pop();
121
- }
122
- }
117
+ if (last.type == "ReturnStatement") {
118
+ var isUndefined = last.argument == null;
119
+
120
+ if (isUndefined) {
121
+ body.pop();
123
122
  }
124
- } // Variable declaration grouping
125
- // var a = 1;
126
- // var b = 1;
127
- // var c = 1;
128
- //
129
- // var a=1,b=1,c=1;
130
-
131
-
132
- var lastDec = null;
133
- var remove = [];
134
- body.forEach((x, i) => {
135
- if (x.type === "VariableDeclaration") {
136
- if (!lastDec || lastDec.kind !== x.kind || !lastDec.declarations.length) {
137
- lastDec = x;
138
- } else {
139
- lastDec.declarations.push(...(0, _insert.clone)(x.declarations));
140
- remove.unshift(i);
141
- }
123
+ }
124
+ } // Variable declaration grouping
125
+ // var a = 1;
126
+ // var b = 1;
127
+ // var c = 1;
128
+ //
129
+ // var a=1,b=1,c=1;
130
+
131
+
132
+ var lastDec = null;
133
+ var remove = [];
134
+ body.forEach((x, i) => {
135
+ if (x.type === "VariableDeclaration") {
136
+ if (!lastDec || lastDec.kind !== x.kind || !lastDec.declarations.length) {
137
+ lastDec = x;
142
138
  } else {
143
- lastDec = null;
139
+ lastDec.declarations.push(...(0, _insert.clone)(x.declarations));
140
+ remove.unshift(i);
144
141
  }
145
- });
146
- remove.forEach(x => {
147
- body.splice(x, 1);
148
- });
149
- }
142
+ } else {
143
+ lastDec = null;
144
+ }
145
+ });
146
+ remove.forEach(x => {
147
+ body.splice(x, 1);
148
+ });
150
149
  };
151
150
  }
152
151
  /**
@@ -169,29 +168,30 @@ class Minify extends _transform.default {
169
168
  }
170
169
  }
171
170
 
172
- var blockIndex = parents.findIndex(x => (0, _insert.isLexContext)(x));
173
-
174
- if (blockIndex !== -1) {
175
- var block = parents[blockIndex];
176
- var body = block.body;
171
+ if (object.type === "FunctionDeclaration") {
172
+ var body = parents[0];
177
173
 
178
174
  if (!Array.isArray(body)) {
179
175
  return;
180
176
  }
181
177
 
182
- var stmt = parents[blockIndex - 2] || object;
183
- var index = body.indexOf(stmt);
178
+ var index = body.indexOf(object);
184
179
 
185
180
  if (index == -1) {
186
181
  return;
187
182
  }
188
183
 
189
184
  var before = body.slice(0, index);
190
- (0, _assert.ok)(!before.includes(stmt));
191
- var set = new Set(before.map(x => x.type));
192
- set.delete("FunctionDeclaration");
185
+ (0, _assert.ok)(!before.includes(object));
186
+ var beforeTypes = new Set(before.map(x => x.type));
187
+ beforeTypes.delete("FunctionDeclaration");
188
+
189
+ if (beforeTypes.size > 0) {
190
+ return;
191
+ } // Test Variant #25: Don't break redefined function declaration
193
192
 
194
- if (set.size) {
193
+
194
+ if (object.id && body.find(x => x.type === "FunctionDeclaration" && x !== object && x.id && x.id.name === object.id.name)) {
195
195
  return;
196
196
  }
197
197
  }
@@ -212,15 +212,28 @@ class Minify extends _transform.default {
212
212
  });
213
213
 
214
214
  if (canTransform) {
215
+ if (!this.arrowFunctionName) {
216
+ this.arrowFunctionName = this.getPlaceholder();
217
+ (0, _insert.append)(parents[parents.length - 1] || object, (0, _template.default)("\n function ".concat(this.arrowFunctionName, "(arrowFn){\n return function(){ return arrowFn(...arguments) }\n }\n ")).single());
218
+ }
219
+
220
+ const wrap = object => {
221
+ return (0, _gen.CallExpression)((0, _gen.Identifier)(this.arrowFunctionName), [(0, _insert.clone)(object)]);
222
+ };
223
+
215
224
  if (object.type == "FunctionExpression") {
216
225
  object.type = "ArrowFunctionExpression";
226
+ this.replace(object, wrap((0, _insert.clone)(object)));
217
227
  } else {
218
228
  var arrow = { ...(0, _insert.clone)(object),
219
229
  type: "ArrowFunctionExpression"
220
230
  };
221
- this.replace(object, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(object.id.name, arrow)));
231
+ this.replace(object, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(object.id.name, wrap(arrow))));
222
232
  var x = this.transform(arrow, []);
223
- x();
233
+
234
+ if (typeof x === "function") {
235
+ x();
236
+ }
224
237
  }
225
238
  }
226
239
  };
@@ -237,7 +250,7 @@ class Minify extends _transform.default {
237
250
 
238
251
  if (body.length == 1 && stmt1.type == "ReturnStatement") {
239
252
  // x=>{a: 1} // Invalid syntax
240
- if (stmt1.argument.type != "ObjectExpression") {
253
+ if (stmt1.argument && stmt1.argument.type != "ObjectExpression") {
241
254
  object.body = stmt1.argument;
242
255
  object.expression = true;
243
256
  }
@@ -372,7 +385,7 @@ class Minify extends _transform.default {
372
385
  object.alternate = null;
373
386
  }
374
387
 
375
- if (object.consequent.body.length == 1 && object.alternate && object.alternate.body.length == 1) {
388
+ if (object.consequent && object.consequent.body && object.consequent.body.length == 1 && object.alternate && object.alternate.body.length == 1) {
376
389
  var stmt1 = (0, _insert.clone)(object.consequent.body[0]);
377
390
  var stmt2 = (0, _insert.clone)(object.alternate.body[0]); // if (a) {return b;} else {return c;} -> return a ? b : c;
378
391
 
@@ -405,8 +418,16 @@ class Minify extends _transform.default {
405
418
  if (property.type == "Literal" && (0, _compare.isValidIdentifier)(property.value)) {
406
419
  object.computed = false;
407
420
  object.property.type = "Identifier";
408
- object.property.name = (0, _insert.clone)(object.property.value);
409
- obj.name && this.log(obj.name + "['" + object.property.name + "'] -> " + obj.name + "." + object.property.name);
421
+ object.property.name = (0, _insert.clone)(object.property.value); // obj.name &&
422
+ // this.log(
423
+ // obj.name +
424
+ // "['" +
425
+ // object.property.name +
426
+ // "'] -> " +
427
+ // obj.name +
428
+ // "." +
429
+ // object.property.name
430
+ // );
410
431
  }
411
432
  }
412
433
 
@@ -421,18 +442,16 @@ class Minify extends _transform.default {
421
442
  } // { "x": 1 } -> {x: 1}
422
443
 
423
444
 
424
- if (object.type == "Property") {
445
+ if (object.type === "Property" || object.type === "MethodDefinition") {
425
446
  if (object.key.type == "SequenceExpression" && object.key.expressions.length == 1) {
426
447
  object.key = object.key.expressions[0];
427
448
  object.computed = true;
428
449
  }
429
450
 
430
- if (object.key.type == "Literal" && (0, _compare.isValidIdentifier)(object.key.value)) {
451
+ if (object.key.type == "Literal" && typeof object.key.value === "string" && (0, _compare.isValidIdentifier)(object.key.value)) {
431
452
  object.key.type = "Identifier";
432
453
  object.key.name = object.key.value;
433
454
  object.computed = false;
434
- } else if (object.key.type == "Identifier" && !(0, _compare.isValidIdentifier)(object.key.name)) {
435
- object.key = (0, _gen.Literal)(object.key.name);
436
455
  }
437
456
  }
438
457
 
@@ -66,7 +66,7 @@ class OpaquePredicates extends _transform.default {
66
66
  _defineProperty(this, "made", void 0);
67
67
 
68
68
  this.predicates = Object.create(null);
69
- this.gen = this.getGenerator((0, _random.getRandomInteger)(0, 20));
69
+ this.gen = this.getGenerator();
70
70
  this.made = 0;
71
71
  }
72
72
 
@@ -103,9 +103,9 @@ class ExplicitIdentifiers extends _transform.default {
103
103
  if (parents[propIndex].type == "MethodDefinition" && parents[propIndex].kind == "constructor") {
104
104
  return;
105
105
  }
106
- }
106
+ } // this.log(object.name, "->", `'${object.name}'`);
107
+
107
108
 
108
- this.log(object.name, "->", "'".concat(object.name, "'"));
109
109
  this.replace(object, (0, _gen.Literal)(object.name));
110
110
  parents[0].computed = true;
111
111
  parents[0].shorthand = false;