js-confuser 1.5.7 → 1.5.9

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 (73) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/index.js +45 -4
  3. package/dist/obfuscator.js +10 -5
  4. package/dist/options.js +6 -7
  5. package/dist/order.js +3 -3
  6. package/dist/transforms/antiTooling.js +1 -1
  7. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +16 -2
  8. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -2
  9. package/dist/transforms/dispatcher.js +3 -3
  10. package/dist/transforms/es5/antiClass.js +6 -2
  11. package/dist/transforms/es5/antiDestructuring.js +1 -1
  12. package/dist/transforms/eval.js +11 -0
  13. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -4
  14. package/dist/transforms/extraction/objectExtraction.js +6 -1
  15. package/dist/transforms/flatten.js +73 -50
  16. package/dist/transforms/hexadecimalNumbers.js +34 -9
  17. package/dist/transforms/identifier/movedDeclarations.js +1 -1
  18. package/dist/transforms/identifier/nameRecycling.js +8 -2
  19. package/dist/transforms/identifier/renameVariables.js +9 -0
  20. package/dist/transforms/lock/antiDebug.js +1 -1
  21. package/dist/transforms/minify.js +22 -6
  22. package/dist/transforms/rgf.js +4 -4
  23. package/dist/transforms/stack.js +1 -1
  24. package/dist/transforms/string/stringConcealing.js +77 -40
  25. package/dist/transforms/transform.js +1 -1
  26. package/dist/traverse.js +0 -8
  27. package/dist/util/compare.js +2 -2
  28. package/dist/util/insert.js +20 -6
  29. package/package.json +2 -2
  30. package/src/index.ts +57 -19
  31. package/src/obfuscator.ts +6 -1
  32. package/src/options.ts +20 -6
  33. package/src/order.ts +3 -3
  34. package/src/transforms/antiTooling.ts +1 -1
  35. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +16 -1
  36. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +14 -2
  37. package/src/transforms/dispatcher.ts +4 -3
  38. package/src/transforms/es5/antiClass.ts +10 -1
  39. package/src/transforms/es5/antiDestructuring.ts +1 -1
  40. package/src/transforms/eval.ts +18 -0
  41. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +5 -5
  42. package/src/transforms/extraction/objectExtraction.ts +12 -5
  43. package/src/transforms/flatten.ts +181 -128
  44. package/src/transforms/hexadecimalNumbers.ts +37 -9
  45. package/src/transforms/identifier/movedDeclarations.ts +1 -1
  46. package/src/transforms/identifier/nameRecycling.ts +14 -3
  47. package/src/transforms/identifier/renameVariables.ts +19 -0
  48. package/src/transforms/lock/antiDebug.ts +1 -1
  49. package/src/transforms/minify.ts +37 -5
  50. package/src/transforms/rgf.ts +4 -3
  51. package/src/transforms/stack.ts +3 -1
  52. package/src/transforms/string/stringConcealing.ts +120 -56
  53. package/src/transforms/transform.ts +1 -1
  54. package/src/traverse.ts +1 -8
  55. package/src/types.ts +9 -1
  56. package/src/util/compare.ts +2 -2
  57. package/src/util/insert.ts +37 -8
  58. package/test/code/ES6.src.js +14 -0
  59. package/test/code/NewFeatures.test.ts +19 -0
  60. package/test/index.test.ts +13 -1
  61. package/test/transforms/antiTooling.test.ts +30 -0
  62. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +58 -0
  63. package/test/transforms/dispatcher.test.ts +24 -0
  64. package/test/transforms/es5/antiClass.test.ts +33 -0
  65. package/test/transforms/eval.test.ts +53 -0
  66. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  67. package/test/transforms/flatten.test.ts +146 -3
  68. package/test/transforms/identifier/nameRecycling.test.ts +39 -0
  69. package/test/transforms/identifier/renameVariables.test.ts +64 -0
  70. package/test/transforms/minify.test.ts +66 -0
  71. package/test/transforms/rgf.test.ts +56 -0
  72. package/test/transforms/string/stringConcealing.test.ts +33 -0
  73. package/test/util/compare.test.ts +23 -1
@@ -59,8 +59,8 @@ function isValidIdentifier(name) {
59
59
  return false;
60
60
  }
61
61
 
62
- var x = name.match(/^[A-z$_][A-z0-9$_]*/);
63
- return x && x[0] == name;
62
+ var x = name.match(/^[A-Za-z$_][A-Za-z0-9$_]*/);
63
+ return !!(x && x[0] == name);
64
64
  }
65
65
 
66
66
  function isInsideType(type, object, parents) {
@@ -139,8 +139,12 @@ function getDefiningContext(o, p) {
139
139
  var variableDeclaration = p.find(x => x.type == "VariableDeclaration");
140
140
  (0, _assert.ok)(variableDeclaration);
141
141
 
142
- if (variableDeclaration.kind === "let") {
143
- return getLexContext(o, p);
142
+ if (variableDeclaration.kind === "let" || variableDeclaration.kind === "const") {
143
+ var context = getVarContext(o, p);
144
+
145
+ if (context && context.type === "Program") {
146
+ return getLexContext(o, p);
147
+ }
144
148
  }
145
149
  }
146
150
 
@@ -287,15 +291,21 @@ function prepend(block) {
287
291
  }
288
292
 
289
293
  if (block.type == "Program") {
290
- var decs = 0;
294
+ var moveBy = 0;
291
295
  block.body.forEach((stmt, i) => {
292
296
  if (stmt.type == "ImportDeclaration") {
293
- if (decs == i) {
294
- decs++;
297
+ if (moveBy == i) {
298
+ moveBy++;
299
+ }
300
+ }
301
+
302
+ if (stmt.type === "ExpressionStatement" && typeof stmt.directive === "string") {
303
+ if (moveBy == i) {
304
+ moveBy++;
295
305
  }
296
306
  }
297
307
  });
298
- block.body.splice(decs, 0, ...nodes);
308
+ block.body.splice(moveBy, 0, ...nodes);
299
309
  } else {
300
310
  getBlockBody(block).unshift(...nodes);
301
311
  }
@@ -351,6 +361,10 @@ function isForInitialize(o, p) {
351
361
  (0, _identifiers.validateChain)(o, p);
352
362
  var forIndex = p.findIndex(x => x.type == "ForStatement" || x.type == "ForInStatement" || x.type == "ForOfStatement");
353
363
 
364
+ if (p.slice(0, forIndex).find(x => ["ArrowFunctionExpression", "BlockStatement"].includes(x.type))) {
365
+ return false;
366
+ }
367
+
354
368
  if (forIndex !== -1) {
355
369
  if (p[forIndex].type == "ForStatement") {
356
370
  if (p[forIndex].init == (p[forIndex - 1] || o)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-confuser",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "JavaScript Obfuscation Tool.",
5
5
  "main": "dist/index.js",
6
6
  "types": "index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "author": "MichaelXF",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "acorn": "^8.7.0",
25
+ "acorn": "^8.8.2",
26
26
  "escodegen": "^2.0.0"
27
27
  },
28
28
  "devDependencies": {
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import Obfuscator from "./obfuscator";
4
4
  import Transform from "./transforms/transform";
5
5
  import { remove$Properties } from "./util/object";
6
6
  import presets from "./presets";
7
+ import { performance } from "perf_hooks";
7
8
 
8
9
  import * as assert from "assert";
9
10
  import { correctOptions, ObfuscateOptions, validateOptions } from "./options";
@@ -85,8 +86,8 @@ var JsConfuser: IJsConfuser = async function (
85
86
  return result;
86
87
  } as any;
87
88
 
88
- export var debugTransformations: IJsConfuserDebugTransformations =
89
- async function debugTransformations(
89
+ export const debugTransformations: IJsConfuserDebugTransformations =
90
+ async function (
90
91
  code: string,
91
92
  options: ObfuscateOptions
92
93
  ): Promise<{ name: string; code: string; ms: number }[]> {
@@ -115,28 +116,65 @@ export var debugTransformations: IJsConfuserDebugTransformations =
115
116
  return frames;
116
117
  };
117
118
 
118
- export var debugObfuscation: IJsConfuserDebugObfuscation =
119
- async function debugTransformations(
120
- code: string,
121
- options: ObfuscateOptions,
122
- callback: (name: string, complete: number, totalTransforms: number) => void
123
- ): Promise<string> {
124
- validateOptions(options);
125
- options = await correctOptions(options);
119
+ /**
120
+ * This method is used by the obfuscator website to display a progress bar and additional information
121
+ * about the obfuscation.
122
+ *
123
+ * @param code - Source code to obfuscate
124
+ * @param options - Options
125
+ * @param callback - Progress callback, called after each transformation
126
+ * @returns
127
+ */
128
+ export const debugObfuscation: IJsConfuserDebugObfuscation = async function (
129
+ code: string,
130
+ options: ObfuscateOptions,
131
+ callback: (name: string, complete: number, totalTransforms: number) => void
132
+ ) {
133
+ const startTime = performance.now();
126
134
 
127
- var tree = parseSync(code);
128
- var obfuscator = new Obfuscator(options);
129
- var totalTransforms = obfuscator.array.length;
135
+ validateOptions(options);
136
+ options = await correctOptions(options);
130
137
 
131
- obfuscator.on("debug", (name: string, tree: Node, i: number) => {
132
- callback(name, i, totalTransforms);
133
- });
138
+ const beforeParseTime = performance.now();
134
139
 
135
- await obfuscator.apply(tree, true);
140
+ var tree = parseSync(code);
141
+
142
+ const parseTime = performance.now() - beforeParseTime;
143
+
144
+ var obfuscator = new Obfuscator(options);
145
+ var totalTransforms = obfuscator.array.length;
146
+
147
+ var transformationTimes = Object.create(null);
148
+ var currentTransformTime = performance.now();
149
+
150
+ obfuscator.on("debug", (name: string, tree: Node, i: number) => {
151
+ var nowTime = performance.now();
152
+ transformationTimes[name] = nowTime - currentTransformTime;
153
+ currentTransformTime = nowTime;
154
+
155
+ callback(name, i, totalTransforms);
156
+ });
157
+
158
+ await obfuscator.apply(tree, true);
159
+
160
+ const beforeCompileTime = performance.now();
161
+
162
+ var output = await compileJs(tree, options);
163
+
164
+ const compileTime = performance.now() - beforeCompileTime;
165
+
166
+ const endTime = performance.now();
136
167
 
137
- var output = compileJs(tree, options);
138
- return output;
168
+ return {
169
+ obfuscated: output,
170
+ transformationTimes: transformationTimes,
171
+ obfuscationTime: endTime - startTime,
172
+ parseTime: parseTime,
173
+ compileTime: compileTime,
174
+ totalTransforms: totalTransforms,
175
+ totalPossibleTransforms: obfuscator.totalPossibleTransforms,
139
176
  };
177
+ };
140
178
 
141
179
  JsConfuser.obfuscate = obfuscate;
142
180
  JsConfuser.obfuscateAST = obfuscateAST;
package/src/obfuscator.ts CHANGED
@@ -47,17 +47,22 @@ export default class Obfuscator extends EventEmitter {
47
47
  state: "transform" | "eval" = "transform";
48
48
  generated: Set<string>;
49
49
 
50
+ totalPossibleTransforms: number;
51
+
50
52
  constructor(public options: ObfuscateOptions) {
51
53
  super();
52
54
 
53
55
  this.varCount = 0;
54
56
  this.transforms = Object.create(null);
55
57
  this.generated = new Set();
58
+ this.totalPossibleTransforms = 0;
56
59
 
57
60
  this.push(new Preparation(this));
58
61
  this.push(new RenameLabels(this));
59
62
 
60
63
  const test = <T>(map: ProbabilityMap<T>, ...transformers: any[]) => {
64
+ this.totalPossibleTransforms += transformers.length;
65
+
61
66
  if (isProbabilityMapProbable(map)) {
62
67
  // options.verbose && console.log("+ Added " + transformer.name);
63
68
 
@@ -97,7 +102,7 @@ export default class Obfuscator extends EventEmitter {
97
102
  test(options.stack, Stack);
98
103
  test(true, AntiTooling);
99
104
  test(options.hideInitializingCode, HideInitializingCode);
100
- test(options.hexadecimalNumbers, HexadecimalNumbers);
105
+ test(true, HexadecimalNumbers); // BigInt support is included
101
106
 
102
107
  if (
103
108
  options.lock &&
package/src/options.ts CHANGED
@@ -770,7 +770,10 @@ export function validateOptions(options: ObfuscateOptions) {
770
770
 
771
771
  if (options.lock) {
772
772
  // Validate browser-lock option
773
- if (typeof options.lock.browserLock !== "undefined") {
773
+ if (
774
+ options.lock.browserLock &&
775
+ typeof options.lock.browserLock !== "undefined"
776
+ ) {
774
777
  ok(
775
778
  Array.isArray(options.lock.browserLock),
776
779
  "browserLock must be an array"
@@ -783,7 +786,7 @@ export function validateOptions(options: ObfuscateOptions) {
783
786
  );
784
787
  }
785
788
  // Validate os-lock option
786
- if (typeof options.lock.osLock !== "undefined") {
789
+ if (options.lock.osLock && typeof options.lock.osLock !== "undefined") {
787
790
  ok(Array.isArray(options.lock.osLock), "osLock must be an array");
788
791
  ok(
789
792
  !options.lock.osLock.find((osName) => !validOses.has(osName)),
@@ -791,12 +794,15 @@ export function validateOptions(options: ObfuscateOptions) {
791
794
  );
792
795
  }
793
796
  // Validate domain-lock option
794
- if (typeof options.lock.domainLock !== "undefined") {
797
+ if (
798
+ options.lock.domainLock &&
799
+ typeof options.lock.domainLock !== "undefined"
800
+ ) {
795
801
  ok(Array.isArray(options.lock.domainLock), "domainLock must be an array");
796
802
  }
797
803
 
798
804
  // Validate context option
799
- if (typeof options.lock.context !== "undefined") {
805
+ if (options.lock.context && typeof options.lock.context !== "undefined") {
800
806
  ok(Array.isArray(options.lock.context), "context must be an array");
801
807
  }
802
808
 
@@ -861,8 +867,7 @@ export async function correctOptions(
861
867
  options.compact = true; // self defending forcibly enables this
862
868
  }
863
869
 
864
- // options.globalVariables was never used.
865
- // GlobalConcealing implicitly determines a global to be a variable referenced but never defined or modified.
870
+ // options.globalVariables outlines generic globals that should be present in the execution context
866
871
  if (!options.hasOwnProperty("globalVariables")) {
867
872
  options.globalVariables = new Set([]);
868
873
 
@@ -902,6 +907,10 @@ export async function correctOptions(
902
907
  "Array",
903
908
  "Proxy",
904
909
  "Error",
910
+ "TypeError",
911
+ "ReferenceError",
912
+ "RangeError",
913
+ "EvalError",
905
914
  "setTimeout",
906
915
  "clearTimeout",
907
916
  "setInterval",
@@ -913,6 +922,11 @@ export async function correctOptions(
913
922
  "module",
914
923
  "isNaN",
915
924
  "isFinite",
925
+ "Set",
926
+ "Map",
927
+ "WeakSet",
928
+ "WeakMap",
929
+ "Symbol",
916
930
  ].forEach((x) => options.globalVariables.add(x));
917
931
  }
918
932
 
package/src/order.ts CHANGED
@@ -44,11 +44,11 @@ export enum ObfuscateOrder {
44
44
 
45
45
  MovedDeclarations = 26,
46
46
 
47
- RenameVariables = 27,
47
+ RenameLabels = 27,
48
48
 
49
- RenameLabels = 28,
49
+ Minify = 28,
50
50
 
51
- Minify = 30,
51
+ RenameVariables = 30,
52
52
 
53
53
  ES5 = 31,
54
54
 
@@ -45,7 +45,7 @@ export default class AntiTooling extends Transform {
45
45
  exprs[0],
46
46
  ExpressionStatement(
47
47
  UnaryExpression(
48
- choice(["typeof", "void", "~", "!", "+"]),
48
+ choice(["typeof", "void", "!"]),
49
49
  SequenceExpression(flattened)
50
50
  )
51
51
  )
@@ -47,6 +47,7 @@ import ChoiceFlowObfuscation from "./choiceFlowObfuscation";
47
47
  import ControlFlowObfuscation from "./controlFlowObfuscation";
48
48
  import ExpressionObfuscation from "./expressionObfuscation";
49
49
  import SwitchCaseObfuscation from "./switchCaseObfuscation";
50
+ import { isModuleSource } from "../string/stringConcealing";
50
51
 
51
52
  var flattenStructures = new Set([
52
53
  "IfStatement",
@@ -226,6 +227,13 @@ export default class ControlFlowFlattening extends Transform {
226
227
  fnNames.delete(illegal);
227
228
  });
228
229
 
230
+ var importDeclarations = [];
231
+ for (var stmt of body) {
232
+ if (stmt.type === "ImportDeclaration") {
233
+ importDeclarations.push(stmt);
234
+ }
235
+ }
236
+
229
237
  var fraction = 0.9;
230
238
  if (body.length > 20) {
231
239
  fraction /= Math.max(1.2, body.length - 18);
@@ -285,6 +293,7 @@ export default class ControlFlowFlattening extends Transform {
285
293
  if (
286
294
  o.type == "Literal" &&
287
295
  typeof o.value == "string" &&
296
+ !isModuleSource(o, p) &&
288
297
  !o.regex &&
289
298
  Math.random() / (Object.keys(stringBank).length / 2 + 1) > 0.5
290
299
  ) {
@@ -318,7 +327,10 @@ export default class ControlFlowFlattening extends Transform {
318
327
  };
319
328
 
320
329
  body.forEach((stmt, i) => {
321
- if (functionDeclarations.has(stmt)) {
330
+ if (
331
+ functionDeclarations.has(stmt) ||
332
+ stmt.type === "ImportDeclaration"
333
+ ) {
322
334
  return;
323
335
  }
324
336
 
@@ -1045,6 +1057,9 @@ export default class ControlFlowFlattening extends Transform {
1045
1057
  var discriminant = Template(`${stateVars.join("+")}`).single().expression;
1046
1058
 
1047
1059
  body.length = 0;
1060
+ for (var importDeclaration of importDeclarations) {
1061
+ body.push(importDeclaration);
1062
+ }
1048
1063
 
1049
1064
  if (functionDeclarations.size) {
1050
1065
  functionDeclarations.forEach((x) => {
@@ -20,7 +20,13 @@ export default class ExpressionObfuscation extends Transform {
20
20
  if (stmt.type == "ExpressionStatement") {
21
21
  var expr = stmt.expression;
22
22
 
23
- if (expr.type == "UnaryExpression" && exprs.length) {
23
+ if (
24
+ expr.type == "UnaryExpression" &&
25
+ !(
26
+ expr.operator === "typeof" && expr.argument.type === "Identifier"
27
+ ) &&
28
+ exprs.length // typeof is special
29
+ ) {
24
30
  expr.argument = SequenceExpression([
25
31
  ...exprs,
26
32
  { ...expr.argument },
@@ -38,7 +44,13 @@ export default class ExpressionObfuscation extends Transform {
38
44
  stmt.test.type == "BinaryExpression" &&
39
45
  stmt.test.operator !== "**"
40
46
  ) {
41
- if (stmt.test.left.type == "UnaryExpression") {
47
+ if (
48
+ stmt.test.left.type == "UnaryExpression" &&
49
+ !(
50
+ stmt.test.left.operator === "typeof" &&
51
+ stmt.test.left.argument.type === "Identifier"
52
+ ) // typeof is special
53
+ ) {
42
54
  stmt.test.left.argument = SequenceExpression([
43
55
  ...exprs,
44
56
  { ...stmt.test.left.argument },
@@ -97,14 +97,15 @@ export default class Dispatcher extends Transform {
97
97
  }
98
98
 
99
99
  // Map of FunctionDeclarations
100
- var functionDeclarations: { [name: string]: Location } = {};
100
+ var functionDeclarations: { [name: string]: Location } =
101
+ Object.create(null);
101
102
 
102
103
  // Array of Identifier nodes
103
104
  var identifiers: Location[] = [];
104
105
  var illegalFnNames: Set<string> = new Set();
105
106
 
106
107
  // New Names for Functions
107
- var newFnNames: { [name: string]: string } = {}; // [old name]: randomized name
108
+ var newFnNames: { [name: string]: string } = Object.create(null); // [old name]: randomized name
108
109
 
109
110
  var context = isVarContext(object)
110
111
  ? object
@@ -469,7 +470,7 @@ export default class Dispatcher extends Transform {
469
470
  }
470
471
 
471
472
  var newName = newFnNames[o.name];
472
- if (!newName) {
473
+ if (!newName || typeof newName !== "string") {
473
474
  return;
474
475
  }
475
476
 
@@ -110,7 +110,16 @@ export default class AntiClass extends Transform {
110
110
  );
111
111
  }
112
112
 
113
- if (
113
+ // Support class fields
114
+ if (methodDefinition.type === "PropertyDefinition") {
115
+ var assignmentExpression = AssignmentExpression(
116
+ "=",
117
+ key,
118
+ value || Identifier("undefined")
119
+ );
120
+
121
+ pushingTo.push(ExpressionStatement(assignmentExpression));
122
+ } else if (
114
123
  methodDefinition.kind == "constructor" ||
115
124
  methodDefinition.kind == "method"
116
125
  ) {
@@ -266,7 +266,7 @@ export default class AntiDestructuring extends Transform {
266
266
  ]);
267
267
 
268
268
  if (object.type == "VariableDeclarator") {
269
- var i = getIndexDirect(object, parents);
269
+ var i = getIndexDirect(object, parents[0]);
270
270
 
271
271
  var extra = Array.from(names).map((x) => {
272
272
  return {
@@ -28,6 +28,24 @@ export default class Eval extends Transform {
28
28
  }
29
29
 
30
30
  transform(object, parents) {
31
+ // Don't apply to getter/setters or class methods
32
+ if (parents[0]) {
33
+ if (
34
+ parents[0].type === "MethodDefinition" &&
35
+ parents[0].value === object
36
+ ) {
37
+ return;
38
+ }
39
+
40
+ if (
41
+ parents[0].type === "Property" &&
42
+ parents[0].value === object &&
43
+ (parents[0].kind !== "init" || parents[0].method)
44
+ ) {
45
+ return;
46
+ }
47
+ }
48
+
31
49
  if (
32
50
  !ComputeProbabilityMap(
33
51
  this.options.eval,
@@ -159,7 +159,7 @@ export default class DuplicateLiteralsRemoval extends Transform {
159
159
  var body = [];
160
160
  var thisShift = getRandomInteger(-250, 250);
161
161
  // the name of the getter
162
- getterName = this.getPlaceholder();
162
+ getterName = this.getPlaceholder() + "_dLR_" + this.fnGetters.size;
163
163
 
164
164
  if (basedOn) {
165
165
  var shift = this.fnShifts.get(basedOn);
@@ -268,20 +268,20 @@ export default class DuplicateLiteralsRemoval extends Transform {
268
268
  this.arrayExpression = ArrayExpression([]);
269
269
  }
270
270
 
271
- var first = this.first.get(value);
272
- if (first) {
271
+ var firstLocation = this.first.get(value);
272
+ if (firstLocation) {
273
273
  this.first.set(value, null);
274
274
  var index = this.map.size;
275
275
 
276
276
  ok(!this.map.has(value));
277
277
  this.map.set(value, index);
278
278
 
279
- this.toCaller(first[0], first[1], index);
280
-
281
279
  var pushing = clone(object);
282
280
  this.arrayExpression.elements.push(pushing);
283
281
 
284
282
  ok(this.arrayExpression.elements[index] === pushing);
283
+
284
+ this.toCaller(firstLocation[0], firstLocation[1], index);
285
285
  }
286
286
 
287
287
  var index = this.map.get(value);
@@ -100,11 +100,18 @@ export default class ObjectExtraction extends Transform {
100
100
  );
101
101
 
102
102
  if (nonInitOrComputed) {
103
- this.log(
104
- name +
105
- " has non-init/computed property: " +
106
- nonInitOrComputed.key.name || nonInitOrComputed.key.value
107
- );
103
+ if (nonInitOrComputed.key) {
104
+ this.log(
105
+ name +
106
+ " has non-init/computed property: " +
107
+ nonInitOrComputed.key.name || nonInitOrComputed.key.value
108
+ );
109
+ } else {
110
+ this.log(
111
+ name + " has spread-element or other type of property"
112
+ );
113
+ }
114
+
108
115
  illegal.add(name);
109
116
  return;
110
117
  } else {