js-confuser 1.5.9 → 1.7.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 (143) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +346 -165
  4. package/dist/constants.js +6 -2
  5. package/dist/index.js +9 -21
  6. package/dist/obfuscator.js +19 -31
  7. package/dist/options.js +5 -5
  8. package/dist/order.js +1 -3
  9. package/dist/presets.js +6 -7
  10. package/dist/probability.js +2 -4
  11. package/dist/templates/bufferToString.js +13 -0
  12. package/dist/templates/crash.js +3 -3
  13. package/dist/templates/es5.js +18 -0
  14. package/dist/templates/functionLength.js +16 -0
  15. package/dist/transforms/calculator.js +77 -21
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
  18. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  19. package/dist/transforms/deadCode.js +33 -25
  20. package/dist/transforms/dispatcher.js +8 -4
  21. package/dist/transforms/es5/antiDestructuring.js +2 -0
  22. package/dist/transforms/es5/es5.js +31 -34
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
  24. package/dist/transforms/finalizer.js +82 -0
  25. package/dist/transforms/flatten.js +229 -148
  26. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  27. package/dist/transforms/identifier/globalConcealing.js +10 -83
  28. package/dist/transforms/identifier/movedDeclarations.js +35 -88
  29. package/dist/transforms/identifier/renameVariables.js +124 -59
  30. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  31. package/dist/transforms/lock/lock.js +0 -37
  32. package/dist/transforms/minify.js +60 -57
  33. package/dist/transforms/opaquePredicates.js +1 -1
  34. package/dist/transforms/preparation/preparation.js +2 -2
  35. package/dist/transforms/preparation.js +231 -0
  36. package/dist/transforms/renameLabels.js +1 -1
  37. package/dist/transforms/rgf.js +139 -247
  38. package/dist/transforms/stack.js +128 -26
  39. package/dist/transforms/string/encoding.js +150 -179
  40. package/dist/transforms/string/stringCompression.js +14 -15
  41. package/dist/transforms/string/stringConcealing.js +25 -8
  42. package/dist/transforms/string/stringEncoding.js +13 -24
  43. package/dist/transforms/transform.js +12 -19
  44. package/dist/traverse.js +24 -10
  45. package/dist/util/gen.js +17 -1
  46. package/dist/util/identifiers.js +37 -3
  47. package/dist/util/insert.js +35 -4
  48. package/dist/util/random.js +15 -0
  49. package/docs/ControlFlowFlattening.md +595 -0
  50. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  51. package/{Integrity.md → docs/Integrity.md} +2 -2
  52. package/docs/RGF.md +419 -0
  53. package/package.json +5 -5
  54. package/src/constants.ts +3 -0
  55. package/src/index.ts +2 -2
  56. package/src/obfuscator.ts +19 -31
  57. package/src/options.ts +14 -103
  58. package/src/order.ts +1 -5
  59. package/src/presets.ts +6 -7
  60. package/src/probability.ts +2 -3
  61. package/src/templates/bufferToString.ts +68 -0
  62. package/src/templates/crash.ts +15 -19
  63. package/src/templates/es5.ts +131 -0
  64. package/src/templates/functionLength.ts +14 -0
  65. package/src/transforms/calculator.ts +122 -59
  66. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  67. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
  68. package/src/transforms/deadCode.ts +383 -26
  69. package/src/transforms/dispatcher.ts +9 -4
  70. package/src/transforms/es5/antiDestructuring.ts +2 -0
  71. package/src/transforms/es5/es5.ts +32 -77
  72. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
  73. package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
  74. package/src/transforms/flatten.ts +357 -300
  75. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  76. package/src/transforms/identifier/globalConcealing.ts +14 -103
  77. package/src/transforms/identifier/movedDeclarations.ts +49 -102
  78. package/src/transforms/identifier/renameVariables.ts +149 -78
  79. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  80. package/src/transforms/lock/lock.ts +1 -42
  81. package/src/transforms/minify.ts +91 -75
  82. package/src/transforms/opaquePredicates.ts +2 -2
  83. package/src/transforms/preparation.ts +238 -0
  84. package/src/transforms/renameLabels.ts +2 -2
  85. package/src/transforms/rgf.ts +213 -405
  86. package/src/transforms/stack.ts +156 -36
  87. package/src/transforms/string/encoding.ts +115 -212
  88. package/src/transforms/string/stringCompression.ts +27 -18
  89. package/src/transforms/string/stringConcealing.ts +39 -9
  90. package/src/transforms/string/stringEncoding.ts +18 -18
  91. package/src/transforms/transform.ts +21 -23
  92. package/src/traverse.ts +23 -4
  93. package/src/types.ts +2 -1
  94. package/src/util/gen.ts +28 -3
  95. package/src/util/identifiers.ts +43 -2
  96. package/src/util/insert.ts +38 -3
  97. package/src/util/random.ts +13 -0
  98. package/test/code/Cash.test.ts +1 -1
  99. package/test/code/Dynamic.test.ts +12 -10
  100. package/test/code/ES6.src.js +146 -0
  101. package/test/code/ES6.test.ts +28 -2
  102. package/test/index.test.ts +2 -1
  103. package/test/probability.test.ts +44 -0
  104. package/test/templates/template.test.ts +1 -1
  105. package/test/transforms/antiTooling.test.ts +22 -0
  106. package/test/transforms/calculator.test.ts +40 -0
  107. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  109. package/test/transforms/deadCode.test.ts +66 -15
  110. package/test/transforms/dispatcher.test.ts +20 -1
  111. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  112. package/test/transforms/flatten.test.ts +399 -86
  113. package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
  114. package/test/transforms/identifier/renameVariables.test.ts +119 -0
  115. package/test/transforms/lock/antiDebug.test.ts +2 -2
  116. package/test/transforms/lock/lock.test.ts +1 -48
  117. package/test/transforms/minify.test.ts +104 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +261 -381
  120. package/test/transforms/stack.test.ts +143 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +82 -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/identifiers.test.ts +113 -1
  127. package/test/util/insert.test.ts +57 -3
  128. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  129. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  130. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  131. package/src/transforms/eval.ts +0 -89
  132. package/src/transforms/hideInitializingCode.ts +0 -432
  133. package/src/transforms/identifier/nameRecycling.ts +0 -280
  134. package/src/transforms/label.ts +0 -64
  135. package/src/transforms/preparation/nameConflicts.ts +0 -102
  136. package/src/transforms/preparation/preparation.ts +0 -176
  137. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  138. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  139. package/test/transforms/eval.test.ts +0 -131
  140. package/test/transforms/hideInitializingCode.test.ts +0 -336
  141. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
  142. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  143. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -23,6 +23,8 @@ var _transform = _interopRequireDefault(require("../transform"));
23
23
 
24
24
  var _stringConcealing = require("./stringConcealing");
25
25
 
26
+ var _random = require("../../util/random");
27
+
26
28
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
29
 
28
30
  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; }
@@ -74,7 +76,7 @@ class StringCompression extends _transform.default {
74
76
 
75
77
  _defineProperty(this, "string", void 0);
76
78
 
77
- _defineProperty(this, "delimiter", "1");
79
+ _defineProperty(this, "delimiter", "|");
78
80
 
79
81
  _defineProperty(this, "fnName", void 0);
80
82
 
@@ -98,7 +100,7 @@ class StringCompression extends _transform.default {
98
100
  var encoded = LZ_encode(this.string);
99
101
 
100
102
  if (LZ_decode(encoded) !== this.string) {
101
- this.error(new Error("String failed to be decoded"));
103
+ this.error(new Error("String failed to be decoded. Try disabling the 'stringCompression' option."));
102
104
  }
103
105
 
104
106
  var getStringParamName = this.getPlaceholder();
@@ -130,33 +132,30 @@ class StringCompression extends _transform.default {
130
132
  return;
131
133
  }
132
134
 
133
- if (!(0, _probability.ComputeProbabilityMap)(object.value, x => x)) {
135
+ if (!(0, _probability.ComputeProbabilityMap)(this.options.stringCompression, x => x, object.value)) {
134
136
  return;
135
- }
137
+ } // HARD CODED LIMIT of 10,000 (after 1,000 elements)
136
138
 
137
- var index = this.map.get(object.value);
139
+
140
+ if (this.map.size > 1000 && !(0, _random.chance)(this.map.size / 100)) return;
141
+ var index = this.map.get(object.value); // New string, add it!
138
142
 
139
143
  if (typeof index !== "number") {
144
+ // Ensure the string gets properly decoded
140
145
  if (LZ_decode(LZ_encode(object.value)) !== object.value) {
141
146
  this.ignore.add(object.value);
142
147
  return;
143
148
  }
144
149
 
145
- var before = this.string;
146
150
  index = this.map.size;
147
151
  this.map.set(object.value, index);
148
- this.string += object.value + this.delimiter; // allow rollback if string becomes corrupted
149
-
150
- if (LZ_decode(LZ_encode(this.string)) !== this.string) {
151
- this.string = before;
152
- this.map.delete(object.value);
153
- this.ignore.add(object.value);
154
- return;
155
- }
152
+ this.string += object.value + this.delimiter;
156
153
  }
157
154
 
158
155
  (0, _assert.ok)(typeof index === "number");
159
- this.replaceIdentifierOrLiteral(object, (0, _gen.CallExpression)((0, _gen.Identifier)(this.fnName), [(0, _gen.Literal)(index)]), parents);
156
+ return () => {
157
+ this.replaceIdentifierOrLiteral(object, (0, _gen.CallExpression)((0, _gen.Identifier)(this.fnName), [(0, _gen.Literal)(index)]), parents);
158
+ };
160
159
  }
161
160
 
162
161
  }
@@ -26,6 +26,10 @@ var _transform = _interopRequireDefault(require("../transform"));
26
26
 
27
27
  var _encoding = _interopRequireDefault(require("./encoding"));
28
28
 
29
+ var _probability = require("../../probability");
30
+
31
+ var _bufferToString = require("../../templates/bufferToString");
32
+
29
33
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30
34
 
31
35
  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; }
@@ -95,6 +99,11 @@ class StringConcealing extends _transform.default {
95
99
  apply(tree) {
96
100
  super.apply(tree);
97
101
  var cacheName = this.getPlaceholder();
102
+ var bufferToStringName = this.getPlaceholder(); // This helper functions convert UInt8 Array to UTf-string
103
+
104
+ (0, _insert.prepend)(tree, ..._bufferToString.BufferToStringTemplate.compile({
105
+ name: bufferToStringName
106
+ }));
98
107
  Object.keys(this.encoding).forEach(type => {
99
108
  var {
100
109
  template
@@ -102,7 +111,8 @@ class StringConcealing extends _transform.default {
102
111
  var decodeFn = this.getPlaceholder();
103
112
  var getterFn = this.encoding[type];
104
113
  (0, _insert.append)(tree, template.single({
105
- name: decodeFn
114
+ name: decodeFn,
115
+ bufferToString: bufferToStringName
106
116
  }));
107
117
  (0, _insert.append)(tree, (0, _template.default)("\n \n function ".concat(getterFn, "(x, y, z, a = ").concat(decodeFn, ", b = ").concat(cacheName, "){\n if ( z ) {\n return y[").concat(cacheName, "[z]] = ").concat(getterFn, "(x, y);\n } else if ( y ) {\n [b, y] = [a(b), x || z]\n }\n \n return y ? x[b[y]] : ").concat(cacheName, "[x] || (z=(b[x], a), ").concat(cacheName, "[x] = z(").concat(this.arrayName, "[x]))\n }\n \n ")).single());
108
118
  });
@@ -122,12 +132,19 @@ class StringConcealing extends _transform.default {
122
132
  // Empty strings are discarded
123
133
  if (!object.value || this.ignore.has(object.value) || object.value.length == 0) {
124
134
  return;
125
- }
135
+ } // Allow user to choose which strings get changed
136
+
137
+
138
+ if (!(0, _probability.ComputeProbabilityMap)(this.options.stringConcealing, x => x, object.value)) {
139
+ return;
140
+ } // HARD CODED LIMIT of 10,000 (after 1,000 elements)
141
+
126
142
 
143
+ if (this.set.size > 1000 && !(0, _random.chance)(this.set.size / 100)) return;
127
144
  var types = Object.keys(this.encoding);
128
145
  var type = (0, _random.choice)(types);
129
146
 
130
- if (!type || !this.hasAllEncodings && Math.random() > 0.9) {
147
+ if (!type || !this.hasAllEncodings && (0, _random.chance)(10)) {
131
148
  var allowed = Object.keys(_encoding.default).filter(type => !this.encoding[type]);
132
149
 
133
150
  if (!allowed.length) {
@@ -165,16 +182,16 @@ class StringConcealing extends _transform.default {
165
182
  (0, _assert.ok)(index != -1, "index == -1");
166
183
  var callExpr = (0, _gen.CallExpression)((0, _gen.Identifier)(fnName), [(0, _gen.Literal)(index)]); // use `.apply` to fool automated de-obfuscators
167
184
 
168
- if (Math.random() > 0.5) {
169
- callExpr = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(fnName), (0, _gen.Identifier)("apply"), false), [(0, _gen.Identifier)("undefined"), (0, _gen.ArrayExpression)([(0, _gen.Literal)(index)])]);
185
+ if ((0, _random.chance)(10)) {
186
+ callExpr = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(fnName), (0, _gen.Literal)("apply"), true), [(0, _gen.Identifier)("undefined"), (0, _gen.ArrayExpression)([(0, _gen.Literal)(index)])]);
170
187
  } // use `.call`
171
- else if (Math.random() > 0.5) {
172
- callExpr = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(fnName), (0, _gen.Identifier)("call"), false), [(0, _gen.Identifier)("undefined"), (0, _gen.Literal)(index)]);
188
+ else if ((0, _random.chance)(10)) {
189
+ callExpr = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(fnName), (0, _gen.Literal)("call"), true), [(0, _gen.Identifier)("undefined"), (0, _gen.Literal)(index)]);
173
190
  }
174
191
 
175
192
  var referenceType = "call";
176
193
 
177
- if (parents.length && Math.random() < 0.5 / this.variablesMade) {
194
+ if (parents.length && (0, _random.chance)(50 - this.variablesMade)) {
178
195
  referenceType = "constantReference";
179
196
  }
180
197
 
@@ -9,15 +9,15 @@ var _transform = _interopRequireDefault(require("../transform"));
9
9
 
10
10
  var _random = require("../../util/random");
11
11
 
12
- var _order = require("../../order");
13
-
14
12
  var _compare = require("../../util/compare");
15
13
 
16
14
  var _stringConcealing = require("./stringConcealing");
17
15
 
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ var _probability = require("../../probability");
19
17
 
20
- 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; }
18
+ var _gen = require("../../util/gen");
19
+
20
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
21
 
22
22
  function pad(x, len) {
23
23
  while (x.length < len) {
@@ -73,34 +73,23 @@ function toUnicodeRepresentation(str) {
73
73
 
74
74
  class StringEncoding extends _transform.default {
75
75
  constructor(o) {
76
- super(o, _order.ObfuscateOrder.StringEncoding);
77
-
78
- _defineProperty(this, "seen", void 0);
79
- }
80
-
81
- apply(tree) {
82
- this.seen = new Set();
83
- super.apply(tree);
76
+ super(o);
84
77
  }
85
78
 
86
79
  match(object, parents) {
87
- return object.type == "Literal" && typeof object.value === "string" && !(0, _stringConcealing.isModuleSource)(object, parents) && !(0, _compare.isDirective)(object, parents);
80
+ return object.type == "Literal" && typeof object.value === "string" && object.value.length > 0 && !(0, _stringConcealing.isModuleSource)(object, parents) && !(0, _compare.isDirective)(object, parents);
88
81
  }
89
82
 
90
83
  transform(object, parents) {
91
- // Todo fix circular json problems
92
- if (this.seen.has(object)) {
93
- return;
94
- }
95
-
96
- this.seen.add(object);
84
+ // Allow percentages
85
+ if (!(0, _probability.ComputeProbabilityMap)(this.options.stringEncoding, x => x, object.value)) return;
97
86
  var type = (0, _random.choice)(["hexadecimal", "unicode"]);
98
- var escapedString = (type == "hexadecimal" ? toHexRepresentation : toUnicodeRepresentation)(object.value); // escodegen tries to escape backslashes, here is a work-around
87
+ var escapedString = (type == "hexadecimal" ? toHexRepresentation : toUnicodeRepresentation)(object.value);
88
+ return () => {
89
+ if (object.type !== "Literal") return; // ESCodeGen tries to escape backslashes, here is a work-around
99
90
 
100
- this.replace(object, {
101
- type: "Identifier",
102
- name: "'".concat(escapedString, "'")
103
- });
91
+ this.replace(object, (0, _gen.Identifier)("'".concat(escapedString, "'")));
92
+ };
104
93
  }
105
94
 
106
95
  }
@@ -81,10 +81,6 @@ class Transform {
81
81
  /**
82
82
  * Transforms to run after.
83
83
  */
84
-
85
- /**
86
- * Transformations to run at the same time (can cause conflicts so use sparingly)
87
- */
88
84
  constructor(obfuscator) {
89
85
  let priority = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
90
86
 
@@ -98,15 +94,12 @@ class Transform {
98
94
 
99
95
  _defineProperty(this, "after", void 0);
100
96
 
101
- _defineProperty(this, "concurrent", void 0);
102
-
103
97
  (0, _assert.ok)(obfuscator instanceof _obfuscator.default, "obfuscator should be an Obfuscator");
104
98
  this.obfuscator = obfuscator;
105
99
  this.options = this.obfuscator.options;
106
100
  this.priority = priority;
107
101
  this.before = [];
108
102
  this.after = [];
109
- this.concurrent = [];
110
103
  }
111
104
  /**
112
105
  * The transformation name.
@@ -136,12 +129,12 @@ class Transform {
136
129
 
137
130
 
138
131
  this.before.forEach(x => x.apply(tree));
139
- (0, _traverse.default)(tree, (object, parents) => {
140
- var fns = [];
141
- fns.push(this.input(object, parents)); // Fix 1. Increase performance with multiple transforms on one iteration.
132
+ /**
133
+ * Run this transformation
134
+ */
142
135
 
143
- this.concurrent.forEach(x => fns.push(x.input(object, parents)));
144
- return () => fns.forEach(x => x && x());
136
+ (0, _traverse.default)(tree, (object, parents) => {
137
+ return this.input(object, parents);
145
138
  });
146
139
  /**
147
140
  * Cleanup transformations
@@ -202,18 +195,17 @@ class Transform {
202
195
  getPlaceholder() {
203
196
  const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 10).toString(10)).join("");
204
197
 
205
- return "__p_" + genRanHex(10);
198
+ return _constants.placeholderVariablePrefix + genRanHex(10);
206
199
  }
207
200
  /**
208
201
  * Returns an independent name generator with it's own counter.
209
- * @param offset
202
+ * @param overrideMode - Override the user's `identifierGenerator` option
210
203
  * @returns
211
204
  */
212
205
 
213
206
 
214
- getGenerator() {
215
- let offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
216
- var count = offset;
207
+ getGenerator(overrideMode) {
208
+ var count = 0;
217
209
  var identifiers = new Set();
218
210
  return {
219
211
  generate: () => {
@@ -221,7 +213,7 @@ class Transform {
221
213
 
222
214
  do {
223
215
  count++;
224
- retValue = this.generateIdentifier(-1, count);
216
+ retValue = this.generateIdentifier(-1, count, overrideMode);
225
217
  } while (identifiers.has(retValue));
226
218
 
227
219
  identifiers.add(retValue);
@@ -239,6 +231,7 @@ class Transform {
239
231
  generateIdentifier() {
240
232
  let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : -1;
241
233
  let count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
234
+ let overrideMode = arguments.length > 2 ? arguments[2] : undefined;
242
235
 
243
236
  if (length == -1) {
244
237
  length = (0, _random.getRandomInteger)(6, 8);
@@ -255,7 +248,7 @@ class Transform {
255
248
  var identifier;
256
249
 
257
250
  do {
258
- identifier = (0, _probability.ComputeProbabilityMap)(this.options.identifierGenerator, function () {
251
+ identifier = (0, _probability.ComputeProbabilityMap)(overrideMode || this.options.identifierGenerator, function () {
259
252
  let mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "randomized";
260
253
 
261
254
  switch (mode) {
package/dist/traverse.js CHANGED
@@ -3,13 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.assertNoCircular = assertNoCircular;
6
7
  exports.default = traverse;
7
8
  exports.getBlock = getBlock;
8
9
  exports.isBlock = isBlock;
9
10
  exports.walk = walk;
10
11
 
11
- var _identifiers = require("./util/identifiers");
12
-
13
12
  /**
14
13
  * A block refers to any object that has a **`.body`** property where code is nested.
15
14
  *
@@ -41,12 +40,10 @@ function isBlock(object) {
41
40
 
42
41
  function walk(object, parents, onEnter) {
43
42
  if (typeof object === "object" && object) {
44
- var newParents = [object, ...parents];
45
-
46
- if (!Array.isArray(object)) {
47
- (0, _identifiers.validateChain)(object, parents);
48
- } // 1. Call `onEnter` function and remember any onExit callback returned
49
-
43
+ var newParents = [object, ...parents]; // if (!Array.isArray(object)) {
44
+ // validateChain(object, parents);
45
+ // }
46
+ // 1. Call `onEnter` function and remember any onExit callback returned
50
47
 
51
48
  var onExit = onEnter(object, parents); // 2. Traverse children
52
49
 
@@ -58,8 +55,6 @@ function walk(object, parents, onEnter) {
58
55
  return "EXIT";
59
56
  }
60
57
  }
61
-
62
- copy.forEach(x => {});
63
58
  } else {
64
59
  var keys = Object.keys(object);
65
60
 
@@ -100,4 +95,23 @@ function walk(object, parents, onEnter) {
100
95
 
101
96
  function traverse(tree, onEnter) {
102
97
  walk(tree, [], onEnter);
98
+ }
99
+ /**
100
+ * This is debugging function used to test for circular references.
101
+ */
102
+
103
+
104
+ function assertNoCircular(object) {
105
+ var seen = new Set();
106
+ traverse(object, (node, nodeParents) => {
107
+ if (node && typeof node === "object") {
108
+ if (seen.has(node)) {
109
+ console.log(nodeParents);
110
+ console.log(node);
111
+ throw new Error("FOUND CIRCULAR REFERENCE");
112
+ }
113
+
114
+ seen.add(node);
115
+ }
116
+ });
103
117
  }
package/dist/util/gen.js CHANGED
@@ -15,6 +15,7 @@ exports.BreakStatement = BreakStatement;
15
15
  exports.CallExpression = CallExpression;
16
16
  exports.CatchClause = CatchClause;
17
17
  exports.ClassDeclaration = ClassDeclaration;
18
+ exports.ClassExpression = ClassExpression;
18
19
  exports.ConditionalExpression = ConditionalExpression;
19
20
  exports.DebuggerStatement = DebuggerStatement;
20
21
  exports.ExpressionStatement = ExpressionStatement;
@@ -174,6 +175,7 @@ function BreakStatement(label) {
174
175
 
175
176
  function Property(key, value) {
176
177
  let computed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
178
+ let kind = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "init";
177
179
 
178
180
  if (!key) {
179
181
  throw new Error("key is undefined");
@@ -188,7 +190,7 @@ function Property(key, value) {
188
190
  key: key,
189
191
  computed: computed,
190
192
  value: value,
191
- kind: "init",
193
+ kind: kind,
192
194
  method: false,
193
195
  shorthand: false
194
196
  };
@@ -537,6 +539,20 @@ function ClassDeclaration(id) {
537
539
  };
538
540
  }
539
541
 
542
+ function ClassExpression(id) {
543
+ let superClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
544
+ let body = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
545
+ return {
546
+ type: "ClassExpression",
547
+ id: id,
548
+ superClass: superClass,
549
+ body: {
550
+ type: "ClassBody",
551
+ body: body
552
+ }
553
+ };
554
+ }
555
+
540
556
  function ThrowStatement(argument) {
541
557
  return {
542
558
  type: "ThrowStatement",
@@ -42,6 +42,22 @@ function validateChain(object, parents) {
42
42
  }
43
43
  }
44
44
  }
45
+
46
+ function objectPatternCheck(object, parents) {
47
+ var objectPatternIndex = parents.findIndex(x => x.type === "ObjectPattern");
48
+
49
+ if (objectPatternIndex == -1) {
50
+ return true;
51
+ }
52
+
53
+ var property = parents[objectPatternIndex].properties.find(property => parents[objectPatternIndex - 2] === property);
54
+
55
+ if (property.key === (parents[objectPatternIndex - 3] || object)) {
56
+ return false;
57
+ }
58
+
59
+ return true;
60
+ }
45
61
  /**
46
62
  * Returns detailed information about the given Identifier node.
47
63
  * @param object
@@ -70,11 +86,29 @@ function getIdentifierInfo(object, parents) {
70
86
  }
71
87
 
72
88
  var varIndex = parents.findIndex(x => x.type == "VariableDeclarator");
73
- var isVariableDeclaration = varIndex != -1 && parents[varIndex].id == (parents[varIndex - 1] || object) && parents.find(x => x.type == "VariableDeclaration");
89
+ var isVariableDeclaration = varIndex != -1 && parents[varIndex].id == (parents[varIndex - 1] || object) && parents.find(x => x.type == "VariableDeclaration") && objectPatternCheck(object, parents); // Assignment pattern check!
90
+
91
+ if (isVariableDeclaration) {
92
+ var slicedParents = parents.slice(0, varIndex - 1);
93
+ var i = 0;
94
+
95
+ for (var parent of slicedParents) {
96
+ var childNode = slicedParents[i - 1] || object;
97
+
98
+ if (parent.type === "AssignmentPattern" && parent.right === childNode) {
99
+ isVariableDeclaration = false;
100
+ break;
101
+ }
102
+
103
+ i++;
104
+ }
105
+ }
106
+
74
107
  var forIndex = parents.findIndex(x => x.type == "ForStatement");
75
108
  var isForInitializer = forIndex != -1 && parents[forIndex].init == (parents[forIndex - 1] || object);
76
109
  var functionIndex = parents.findIndex(x => (0, _insert.isFunction)(x));
77
110
  var isFunctionDeclaration = functionIndex != -1 && parents[functionIndex].type == "FunctionDeclaration" && parents[functionIndex].id == object;
111
+ var isNamedFunctionExpression = functionIndex != -1 && parents[functionIndex].type === "FunctionExpression" && parents[functionIndex].id === object;
78
112
  var isAFunctionParameter = isFunctionParameter(object, parents);
79
113
  var isClauseParameter = false; // Special case for Catch clauses
80
114
 
@@ -90,7 +124,7 @@ function getIdentifierInfo(object, parents) {
90
124
  var isFunctionCall = parent.callee == object; // NewExpression and CallExpression
91
125
 
92
126
  var assignmentIndex = parents.findIndex(p => p.type === "AssignmentExpression");
93
- var isAssignmentLeft = assignmentIndex !== -1 && parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
127
+ var isAssignmentLeft = assignmentIndex !== -1 && parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object) && objectPatternCheck(object, parents);
94
128
  var isAssignmentValue = assignmentIndex !== -1 && parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
95
129
  var isUpdateExpression = parent.type == "UpdateExpression";
96
130
  var isClassDeclaration = (parent.type == "ClassDeclaration" || parent.type == "ClassExpression") && parent.id == object;
@@ -227,7 +261,7 @@ function getIdentifierInfo(object, parents) {
227
261
  /**
228
262
  * Is the Identifier defined, i.e a variable declaration, function declaration, parameter, or class definition
229
263
  */
230
- isDefined: isVariableDeclaration || isFunctionDeclaration || isAFunctionParameter || isClassDeclaration || isClauseParameter || isMethodDefinition || isImportSpecifier,
264
+ isDefined: isVariableDeclaration || isFunctionDeclaration || isNamedFunctionExpression || isAFunctionParameter || isClassDeclaration || isClauseParameter || isMethodDefinition || isImportSpecifier,
231
265
 
232
266
  /**
233
267
  * Is the Identifier modified, either by an `AssignmentExpression` or `UpdateExpression`
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.append = append;
7
7
  exports.clone = clone;
8
+ exports.computeFunctionLength = computeFunctionLength;
8
9
  exports.deleteDeclaration = deleteDeclaration;
9
10
  exports.deleteDirect = deleteDirect;
10
11
  exports.getAllDefiningContexts = getAllDefiningContexts;
@@ -168,15 +169,14 @@ function getAllDefiningContexts(o, p) {
168
169
 
169
170
  if (info.isFunctionParameter) {
170
171
  // Get Function
171
- var fn = getFunction(o, p);
172
- contexts.push(fn.body);
172
+ var fn = getFunction(o, p); // contexts.push(fn.body);
173
173
  }
174
174
 
175
175
  if (info.isClauseParameter) {
176
176
  var catchClause = p.find(x => x.type === "CatchClause");
177
177
 
178
178
  if (catchClause) {
179
- contexts.push(catchClause.body);
179
+ return [catchClause];
180
180
  }
181
181
  }
182
182
 
@@ -306,8 +306,18 @@ function prepend(block) {
306
306
  }
307
307
  });
308
308
  block.body.splice(moveBy, 0, ...nodes);
309
+ } else if (block.type === "SwitchCase") {
310
+ block.consequent.unshift(...nodes);
309
311
  } else {
310
- getBlockBody(block).unshift(...nodes);
312
+ var bodyArray = getBlockBody(block); // Check for 'use strict'
313
+
314
+ if (bodyArray[0] && bodyArray[0].directive) {
315
+ // Insert under 'use strict' directive
316
+ bodyArray.splice(1, 0, ...nodes);
317
+ } else {
318
+ // Prepend at the top of the block
319
+ bodyArray.unshift(...nodes);
320
+ }
311
321
  }
312
322
  }
313
323
 
@@ -378,4 +388,25 @@ function isForInitialize(o, p) {
378
388
  }
379
389
 
380
390
  return false;
391
+ }
392
+ /**
393
+ * Computes the `function.length` property given the parameter nodes.
394
+ *
395
+ * @param params
396
+ * @returns
397
+ */
398
+
399
+
400
+ function computeFunctionLength(params) {
401
+ var count = 0;
402
+
403
+ for (var parameterNode of params) {
404
+ if (parameterNode.type === "Identifier" || parameterNode.type === "ObjectPattern" || parameterNode.type === "ArrayPattern") {
405
+ count++;
406
+ } else {
407
+ break;
408
+ }
409
+ }
410
+
411
+ return count;
381
412
  }
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.alphabeticalGenerator = alphabeticalGenerator;
7
+ exports.chance = chance;
7
8
  exports.choice = choice;
8
9
  exports.getRandom = getRandom;
9
10
  exports.getRandomFalseExpression = getRandomFalseExpression;
@@ -17,10 +18,24 @@ var _assert = require("assert");
17
18
 
18
19
  var _gen = require("./gen");
19
20
 
21
+ /**
22
+ * Returns a random element from the given array
23
+ * @param choices Array of items
24
+ * @returns One of the items in the array at random
25
+ */
20
26
  function choice(choices) {
21
27
  var index = Math.floor(Math.random() * choices.length);
22
28
  return choices[index];
23
29
  }
30
+ /**
31
+ * Returns a true/false based on the percent chance (0%-100%)
32
+ * @param percentChance AS A PERCENTAGE 0 - 100%
33
+ */
34
+
35
+
36
+ function chance(percentChance) {
37
+ return Math.random() < percentChance / 100;
38
+ }
24
39
  /**
25
40
  * **Mutates the given array**
26
41
  * @param array