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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.prettierrc +4 -0
  2. package/CHANGELOG.md +42 -8
  3. package/Migration.md +23 -8
  4. package/README.md +2 -2
  5. package/dist/constants.js +11 -2
  6. package/dist/index.js +49 -6
  7. package/dist/obfuscator.js +121 -10
  8. package/dist/order.js +0 -1
  9. package/dist/probability.js +1 -96
  10. package/dist/templates/getGlobalTemplate.js +4 -1
  11. package/dist/templates/integrityTemplate.js +1 -1
  12. package/dist/templates/stringCompressionTemplate.js +3 -3
  13. package/dist/templates/tamperProtectionTemplates.js +1 -1
  14. package/dist/templates/template.js +17 -12
  15. package/dist/transforms/controlFlowFlattening.js +112 -83
  16. package/dist/transforms/deadCode.js +21 -22
  17. package/dist/transforms/dispatcher.js +62 -37
  18. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -0
  19. package/dist/transforms/extraction/objectExtraction.js +1 -2
  20. package/dist/transforms/finalizer.js +1 -1
  21. package/dist/transforms/flatten.js +2 -19
  22. package/dist/transforms/identifier/globalConcealing.js +3 -4
  23. package/dist/transforms/identifier/movedDeclarations.js +12 -5
  24. package/dist/transforms/identifier/renameVariables.js +40 -6
  25. package/dist/transforms/lock/integrity.js +9 -1
  26. package/dist/transforms/lock/lock.js +16 -9
  27. package/dist/transforms/minify.js +64 -27
  28. package/dist/transforms/opaquePredicates.js +6 -7
  29. package/dist/transforms/pack.js +32 -5
  30. package/dist/transforms/plugin.js +20 -39
  31. package/dist/transforms/preparation.js +25 -36
  32. package/dist/transforms/renameLabels.js +1 -2
  33. package/dist/transforms/rgf.js +36 -16
  34. package/dist/transforms/shuffle.js +10 -11
  35. package/dist/transforms/string/stringCompression.js +14 -10
  36. package/dist/transforms/string/stringConcealing.js +7 -5
  37. package/dist/transforms/string/stringEncoding.js +4 -2
  38. package/dist/transforms/string/stringSplitting.js +4 -2
  39. package/dist/transforms/variableMasking.js +3 -2
  40. package/dist/utils/NameGen.js +5 -2
  41. package/dist/utils/PredicateGen.js +62 -0
  42. package/dist/utils/ast-utils.js +24 -9
  43. package/dist/utils/random-utils.js +10 -0
  44. package/dist/validateOptions.js +2 -2
  45. package/index.d.ts +16 -2
  46. package/package.json +2 -2
  47. package/src/constants.ts +15 -5
  48. package/src/index.ts +15 -5
  49. package/src/obfuscationResult.ts +7 -1
  50. package/src/obfuscator.ts +152 -12
  51. package/src/options.ts +26 -8
  52. package/src/order.ts +0 -2
  53. package/src/templates/getGlobalTemplate.ts +5 -1
  54. package/src/templates/integrityTemplate.ts +14 -19
  55. package/src/templates/stringCompressionTemplate.ts +4 -28
  56. package/src/templates/tamperProtectionTemplates.ts +7 -3
  57. package/src/templates/template.ts +5 -3
  58. package/src/transforms/controlFlowFlattening.ts +139 -83
  59. package/src/transforms/deadCode.ts +27 -30
  60. package/src/transforms/dispatcher.ts +24 -5
  61. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +10 -1
  62. package/src/transforms/extraction/objectExtraction.ts +1 -2
  63. package/src/transforms/finalizer.ts +1 -1
  64. package/src/transforms/flatten.ts +3 -22
  65. package/src/transforms/identifier/globalConcealing.ts +26 -17
  66. package/src/transforms/identifier/movedDeclarations.ts +18 -6
  67. package/src/transforms/identifier/renameVariables.ts +48 -6
  68. package/src/transforms/lock/integrity.ts +11 -1
  69. package/src/transforms/lock/lock.ts +26 -10
  70. package/src/transforms/minify.ts +85 -38
  71. package/src/transforms/opaquePredicates.ts +6 -9
  72. package/src/transforms/pack.ts +41 -5
  73. package/src/transforms/plugin.ts +47 -69
  74. package/src/transforms/preparation.ts +33 -46
  75. package/src/transforms/renameLabels.ts +1 -2
  76. package/src/transforms/rgf.ts +52 -23
  77. package/src/transforms/shuffle.ts +28 -26
  78. package/src/transforms/string/encoding.ts +1 -1
  79. package/src/transforms/string/stringCompression.ts +22 -13
  80. package/src/transforms/string/stringConcealing.ts +13 -7
  81. package/src/transforms/string/stringEncoding.ts +6 -2
  82. package/src/transforms/string/stringSplitting.ts +9 -4
  83. package/src/transforms/variableMasking.ts +2 -2
  84. package/src/utils/NameGen.ts +13 -3
  85. package/src/utils/PredicateGen.ts +61 -0
  86. package/src/utils/ast-utils.ts +16 -9
  87. package/src/utils/random-utils.ts +14 -0
  88. package/src/validateOptions.ts +7 -4
  89. package/src/probability.ts +0 -110
  90. package/src/transforms/functionOutlining.ts +0 -225
  91. package/src/utils/ControlObject.ts +0 -141
@@ -1,7 +1,6 @@
1
1
  import traverse, { NodePath, Scope, Visitor } from "@babel/traverse";
2
2
  import { PluginArg, PluginObject } from "./plugin";
3
3
  import { Order } from "../order";
4
- import { computeProbabilityMap } from "../probability";
5
4
  import {
6
5
  ensureComputedExpression,
7
6
  getParentFunctionOrProgram,
@@ -30,9 +29,11 @@ import {
30
29
  PREDICTABLE,
31
30
  variableFunctionName,
32
31
  WITH_STATEMENT,
33
- CONTROL_OBJECTS,
34
32
  } from "../constants";
35
33
 
34
+ // Function deemed unsafe for CFF
35
+ const CFF_UNSAFE = Symbol("CFF_UNSAFE");
36
+
36
37
  /**
37
38
  * Breaks functions into DAGs (Directed Acyclic Graphs)
38
39
  *
@@ -77,13 +78,44 @@ export default ({ Plugin }: PluginArg): PluginObject => {
77
78
 
78
79
  const functionsModified = new Set<t.Node>();
79
80
 
81
+ function flagFunctionToAvoid(path: NodePath, reason: string) {
82
+ var fnOrProgram = getParentFunctionOrProgram(path);
83
+
84
+ fnOrProgram.node[CFF_UNSAFE] = reason;
85
+ }
86
+
80
87
  return {
81
88
  post: () => {
82
89
  functionsModified.forEach((node) => {
83
90
  (node as NodeSymbol)[UNSAFE] = true;
84
91
  });
85
92
  },
93
+
86
94
  visitor: {
95
+ // Unsafe detection
96
+ ThisExpression(path) {
97
+ flagFunctionToAvoid(path, "this");
98
+ },
99
+ VariableDeclaration(path) {
100
+ if (path.node.declarations.length !== 1) {
101
+ path.getAncestry().forEach((p) => {
102
+ p.node[CFF_UNSAFE] = "multipleDeclarations";
103
+ });
104
+ }
105
+ },
106
+ Identifier(path) {
107
+ if (
108
+ path.node.name === variableFunctionName ||
109
+ path.node.name === "arguments"
110
+ ) {
111
+ flagFunctionToAvoid(path, "arguments");
112
+ }
113
+ },
114
+ "Super|MetaProperty|AwaitExpression|YieldExpression"(path) {
115
+ flagFunctionToAvoid(path, "functionSpecific");
116
+ },
117
+
118
+ // Main CFF transformation
87
119
  "Program|Function": {
88
120
  exit(_path) {
89
121
  let programOrFunctionPath = _path as NodePath<t.Program | t.Function>;
@@ -94,6 +126,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
94
126
  )
95
127
  return;
96
128
 
129
+ // Exclude 'CFF_UNSAFE' functions
130
+ if (programOrFunctionPath.node[CFF_UNSAFE]) return;
131
+
97
132
  let programPath = _path.isProgram() ? _path : null;
98
133
  let functionPath = _path.isFunction() ? _path : null;
99
134
 
@@ -116,13 +151,16 @@ export default ({ Plugin }: PluginArg): PluginObject => {
116
151
  if (blockPath.node.body.length < 3) return;
117
152
 
118
153
  // Check user's threshold setting
119
- if (!computeProbabilityMap(me.options.controlFlowFlattening)) {
154
+ if (!me.computeProbabilityMap(me.options.controlFlowFlattening)) {
120
155
  return;
121
156
  }
122
157
 
123
- // Avoid unsafe functions
124
- if (functionPath && (functionPath.node as NodeSymbol)[UNSAFE]) return;
158
+ if (functionPath) {
159
+ // Avoid unsafe functions
160
+ if ((functionPath.node as NodeSymbol)[UNSAFE]) return;
125
161
 
162
+ if (functionPath.node.async || functionPath.node.generator) return;
163
+ }
126
164
  programOrFunctionPath.scope.crawl();
127
165
 
128
166
  const blockFnParent = getParentFunctionOrProgram(blockPath);
@@ -130,30 +168,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
130
168
  let hasIllegalNode = false;
131
169
  const bindingNames = new Set<string>();
132
170
  blockPath.traverse({
133
- "Super|MetaProperty|AwaitExpression|YieldExpression"(path) {
134
- if (
135
- getParentFunctionOrProgram(path).node === blockFnParent.node
136
- ) {
137
- hasIllegalNode = true;
138
- path.stop();
139
- }
140
- },
141
- VariableDeclaration(path) {
142
- if (path.node.declarations.length !== 1) {
143
- hasIllegalNode = true;
144
- path.stop();
145
- }
146
- },
147
171
  Identifier(path) {
148
- if (
149
- path.node.name === variableFunctionName ||
150
- path.node.name === "arguments"
151
- ) {
152
- hasIllegalNode = true;
153
- path.stop();
154
- return;
155
- }
156
-
157
172
  if (!path.isBindingIdentifier()) return;
158
173
  const binding = path.scope.getBinding(path.node.name);
159
174
  if (!binding) return;
@@ -319,7 +334,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
319
334
  identity: "${this.propertyName}"
320
335
  })
321
336
  `).expression()
322
- : new Template(`Object["create"](null)`).expression();
337
+ : new Template(`({})`).expression();
323
338
  }
324
339
 
325
340
  getMemberExpression(name: string) {
@@ -375,6 +390,25 @@ export default ({ Plugin }: PluginArg): PluginObject => {
375
390
  );
376
391
  }
377
392
 
393
+ if (this === mainScope) {
394
+ // Reset With logic
395
+ properties.push(
396
+ t.objectProperty(
397
+ t.stringLiteral(resetWithProperty),
398
+ new Template(`
399
+ (function(newStateValues, alwaysUndefined){
400
+ {withMemberExpression} = alwaysUndefined;
401
+ {arrayPattern} = newStateValues
402
+ })
403
+ `).expression({
404
+ withMemberExpression: deepClone(withMemberExpression),
405
+ arrayPattern: t.arrayPattern(deepClone(stateVars)),
406
+ }),
407
+ true
408
+ )
409
+ );
410
+ }
411
+
378
412
  return t.objectExpression(properties);
379
413
  }
380
414
 
@@ -660,7 +694,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
660
694
  !flattenFunctionDeclarations ||
661
695
  statement.node.async ||
662
696
  statement.node.generator ||
663
- (statement.node as NodeSymbol)[UNSAFE]
697
+ (statement.node as NodeSymbol)[UNSAFE] ||
698
+ (statement.node as NodeSymbol)[CFF_UNSAFE] ||
699
+ isStrictMode(statement)
664
700
  ) {
665
701
  isIllegal = true;
666
702
  }
@@ -872,20 +908,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
872
908
 
873
909
  basicBlocks.get(endLabel).allowWithDiscriminant = false;
874
910
 
875
- // Add with / reset with logic
876
- basicBlocks.get(startLabel).body.unshift(
877
- new Template(`
878
- {resetWithMemberExpression} = function(newStateValues){
879
- {withMemberExpression} = undefined;
880
- {arrayPattern} = newStateValues
881
- }
882
- `).single({
883
- arrayPattern: t.arrayPattern(deepClone(stateVars)),
884
- resetWithMemberExpression: deepClone(resetWithMemberExpression),
885
- withMemberExpression: deepClone(withMemberExpression),
886
- })
887
- );
888
-
889
911
  if (!isDebug && addDeadCode) {
890
912
  // DEAD CODE 1/3: Add fake chunks that are never reached
891
913
  const fakeChunkCount = getRandomInteger(1, 5);
@@ -1081,7 +1103,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1081
1103
  const identifierName = path.node.name;
1082
1104
  if (identifierName === gotoFunctionName) return;
1083
1105
 
1084
- var binding = basicBlock.scope.getBinding(identifierName);
1106
+ var binding = path.scope.getBinding(identifierName);
1085
1107
  if (!binding) {
1086
1108
  return;
1087
1109
  }
@@ -1139,6 +1161,17 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1139
1161
 
1140
1162
  path.replaceWith(memberExpression);
1141
1163
  path.skip();
1164
+
1165
+ // Preserve proper 'this' context when directly calling functions
1166
+ // X.Y.Z() -> (1, X.Y.Z)()
1167
+ if (
1168
+ path.parentPath.isCallExpression() &&
1169
+ path.key === "callee"
1170
+ ) {
1171
+ path.replaceWith(
1172
+ t.sequenceExpression([t.numericLiteral(1), path.node])
1173
+ );
1174
+ }
1142
1175
  },
1143
1176
  },
1144
1177
 
@@ -1212,15 +1245,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1212
1245
  // console.log(oldValue, newValue);
1213
1246
  if (oldValue === newValue) continue; // No diff needed if the value doesn't change
1214
1247
 
1215
- const leftValue = jumpBlock.withDiscriminant
1216
- ? jumpBlock.withDiscriminant.getMemberExpression(
1217
- stateVars[i].name
1218
- )
1219
- : deepClone(stateVars[i]);
1220
-
1221
1248
  let assignment = t.assignmentExpression(
1222
1249
  "=",
1223
- leftValue,
1250
+ deepClone(stateVars[i]),
1224
1251
  numericLiteral(newValue)
1225
1252
  );
1226
1253
 
@@ -1271,7 +1298,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1271
1298
  const mainScope = basicBlocks.get(startLabel).scopeManager;
1272
1299
  const predicateNumbers = new Map<string, number>();
1273
1300
  const predicateNumberCount =
1274
- isDebug || !addPredicateTests ? 0 : getRandomInteger(2, 5);
1301
+ isDebug || !addPredicateTests ? 0 : getRandomInteger(1, 4);
1302
+
1275
1303
  for (let i = 0; i < predicateNumberCount; i++) {
1276
1304
  const name = mainScope.getNewName(
1277
1305
  me.getPlaceholder("predicate_" + i)
@@ -1279,27 +1307,47 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1279
1307
 
1280
1308
  const number = getRandomInteger(-250, 250);
1281
1309
  predicateNumbers.set(name, number);
1310
+ }
1282
1311
 
1283
- const createAssignment = (value: number) => {
1284
- return new Template(`
1285
- {memberExpression} = {number}
1286
- `).single({
1287
- memberExpression: mainScope.getMemberExpression(name),
1288
- number: numericLiteral(number),
1289
- });
1290
- };
1312
+ const predicateSymbol = Symbol("predicate");
1313
+
1314
+ const createAssignment = (values: number[]) => {
1315
+ var exprStmt = new Template(`
1316
+ ({predicateVariables} = {values})
1317
+ `).single({
1318
+ predicateVariables: t.arrayPattern(
1319
+ Array.from(predicateNumbers.keys()).map((name) =>
1320
+ mainScope.getMemberExpression(name)
1321
+ )
1322
+ ),
1323
+ values: t.arrayExpression(
1324
+ values.map((value) => numericLiteral(value))
1325
+ ),
1326
+ });
1291
1327
 
1292
- basicBlocks.get(startLabel).body.unshift(createAssignment(number));
1328
+ exprStmt[predicateSymbol] = true;
1293
1329
 
1294
- // Add random assignments to impossible blocks
1295
- var fakeAssignmentCount = getRandomInteger(0, 3);
1296
- for (let i = 0; i < fakeAssignmentCount; i++) {
1297
- var impossibleBlock = choice(getImpossibleBasicBlocks());
1298
- if (impossibleBlock) {
1299
- impossibleBlock.body.unshift(
1300
- createAssignment(getRandomInteger(-250, 250))
1301
- );
1302
- }
1330
+ return exprStmt;
1331
+ };
1332
+
1333
+ basicBlocks
1334
+ .get(startLabel)
1335
+ .body.unshift(
1336
+ createAssignment(Array.from(predicateNumbers.values()))
1337
+ );
1338
+
1339
+ // Add random assignments to impossible blocks
1340
+ var fakeAssignmentCount = getRandomInteger(1, 3);
1341
+
1342
+ for (let i = 0; i < fakeAssignmentCount; i++) {
1343
+ var impossibleBlock = choice(getImpossibleBasicBlocks());
1344
+ if (impossibleBlock) {
1345
+ if (impossibleBlock.body[0]?.[predicateSymbol]) continue;
1346
+
1347
+ var fakeValues = new Array(predicateNumberCount)
1348
+ .fill(0)
1349
+ .map(() => getRandomInteger(-250, 250));
1350
+ impossibleBlock.body.unshift(createAssignment(fakeValues));
1303
1351
  }
1304
1352
  }
1305
1353
 
@@ -1467,9 +1515,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1467
1515
  ),
1468
1516
  t.blockStatement([
1469
1517
  t.withStatement(
1470
- new Template(
1471
- `{withDiscriminant} || Object["create"](null)`
1472
- ).expression({
1518
+ new Template(`{withDiscriminant} || {}`).expression({
1473
1519
  withDiscriminant: deepClone(withMemberExpression),
1474
1520
  }),
1475
1521
  t.blockStatement([switchStatement])
@@ -1533,6 +1579,17 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1533
1579
  );
1534
1580
  }
1535
1581
 
1582
+ const startProgramObjectExpression = basicBlocks
1583
+ .get(startLabel)
1584
+ .scopeManager.getObjectExpression(startLabel);
1585
+
1586
+ const mainParameters: t.FunctionDeclaration["params"] = parameters;
1587
+ const scopeParameter = mainParameters.pop() as t.Identifier;
1588
+
1589
+ mainParameters.push(
1590
+ t.assignmentPattern(scopeParameter, startProgramObjectExpression)
1591
+ );
1592
+
1536
1593
  const mainFnDeclaration = t.functionDeclaration(
1537
1594
  deepClone(mainFnName),
1538
1595
  parameters,
@@ -1544,17 +1601,19 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1544
1601
  var startProgramExpression = t.callExpression(deepClone(mainFnName), [
1545
1602
  ...startStateValues.map((stateValue) => numericLiteral(stateValue)),
1546
1603
  t.identifier("undefined"),
1547
- basicBlocks
1548
- .get(startLabel)
1549
- .scopeManager.getObjectExpression(startLabel),
1550
1604
  ]);
1551
1605
 
1552
- var resultVar = withIdentifier("result");
1553
- var allowReturns = blockPath.find((p) => p.isFunction());
1606
+ const resultVar = withIdentifier("result");
1607
+
1608
+ const isTopLevel = blockPath.isProgram();
1609
+ const allowReturns =
1610
+ !isTopLevel && blockPath.find((p) => p.isFunction());
1611
+
1612
+ const startPrefix = allowReturns ? `var {resultVar} = ` : "";
1554
1613
 
1555
1614
  const startProgramStatements = new Template(`
1556
1615
  ${allowReturns ? `var {didReturnVar};` : ""}
1557
- var {resultVar} = {startProgramExpression};
1616
+ ${startPrefix}{startProgramExpression};
1558
1617
  ${
1559
1618
  allowReturns
1560
1619
  ? `
@@ -1580,9 +1639,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
1580
1639
  // Reset all bindings here
1581
1640
  blockPath.scope.bindings = Object.create(null);
1582
1641
 
1583
- // Bindings changed - breaking control objects
1584
- delete (blockPath.node as NodeSymbol)[CONTROL_OBJECTS];
1585
-
1586
1642
  // Register new declarations
1587
1643
  for (var node of blockPath.get("body")) {
1588
1644
  blockPath.scope.registerDeclaration(node);
@@ -1,12 +1,11 @@
1
1
  import { PluginArg, PluginObject } from "./plugin";
2
- import { chance, choice } from "../utils/random-utils";
2
+ import { choice } from "../utils/random-utils";
3
3
  import { deadCodeTemplates } from "../templates/deadCodeTemplates";
4
- import { computeProbabilityMap } from "../probability";
5
4
  import { Order } from "../order";
6
5
  import * as t from "@babel/types";
7
6
  import Template from "../templates/template";
8
- import { NameGen } from "../utils/NameGen";
9
7
  import { prepend } from "../utils/ast-utils";
8
+ import PredicateGen from "../utils/PredicateGen";
10
9
 
11
10
  export default ({ Plugin }: PluginArg): PluginObject => {
12
11
  const me = Plugin(Order.DeadCode, {
@@ -14,7 +13,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
14
13
  deadCode: 0,
15
14
  },
16
15
  });
17
- let created = 0;
16
+ let predicateGen = new PredicateGen(me);
18
17
 
19
18
  return {
20
19
  visitor: {
@@ -22,29 +21,41 @@ export default ({ Plugin }: PluginArg): PluginObject => {
22
21
  exit(blockPath) {
23
22
  if (blockPath.find((p) => me.isSkipped(p))) return;
24
23
 
25
- if (!computeProbabilityMap(me.options.deadCode)) {
24
+ if (!me.computeProbabilityMap(me.options.deadCode)) {
26
25
  return;
27
26
  }
28
27
 
29
- if (typeof me.options.deadCode !== "function") {
30
- let suggestedMax = 25;
28
+ // Default limit on dead code
29
+ // May be overridden by user
30
+ if (
31
+ typeof me.options.deadCode !== "function" &&
32
+ typeof me.options.deadCode !== "object"
33
+ ) {
34
+ let suggestedMax = 20;
31
35
  if (me.obfuscator.parentObfuscator) {
32
36
  // RGF should contain less dead code
33
37
  suggestedMax = 5;
34
38
  }
35
39
 
36
- if (created > suggestedMax && chance(created - suggestedMax))
40
+ if (me.changeData.deadCode >= suggestedMax) {
37
41
  return;
38
- created++;
42
+ }
39
43
  }
40
44
 
45
+ // Increment dead code counter
46
+ me.changeData.deadCode++;
47
+
41
48
  var template = choice(deadCodeTemplates);
42
49
  var nodes = template.compile();
43
50
 
44
- var containingFnName = me.getPlaceholder("dead_" + created);
51
+ var containingFnName = me.getPlaceholder(
52
+ "dead_" + me.changeData.deadCode
53
+ );
54
+
55
+ // Insert dummy function
56
+ prepend(
57
+ blockPath,
45
58
 
46
- var newPath = blockPath.unshiftContainer(
47
- "body",
48
59
  t.functionDeclaration(
49
60
  t.identifier(containingFnName),
50
61
  [],
@@ -52,29 +63,15 @@ export default ({ Plugin }: PluginArg): PluginObject => {
52
63
  )
53
64
  );
54
65
 
55
- // Overcomplicated way to get a random property name that doesn't exist on the Function
56
- var randomProperty: string;
57
- var nameGen = new NameGen("randomized");
58
-
59
- function PrototypeCollision() {}
60
- PrototypeCollision(); // Call it for code coverage :D
61
-
62
- do {
63
- randomProperty = nameGen.generate();
64
- } while (
65
- !randomProperty ||
66
- PrototypeCollision[randomProperty] !== undefined
67
- );
68
-
69
- me.changeData.deadCode++;
70
-
71
66
  prepend(
72
67
  blockPath,
73
68
  new Template(`
74
- if("${randomProperty}" in ${containingFnName}) {
69
+ if({falsePredicate}) {
75
70
  ${containingFnName}()
76
71
  }
77
- `).single()
72
+ `).single({
73
+ falsePredicate: predicateGen.generateFalseExpression(blockPath),
74
+ })
78
75
  );
79
76
 
80
77
  me.skip(blockPath);
@@ -4,7 +4,6 @@ import * as t from "@babel/types";
4
4
  import Template from "../templates/template";
5
5
  import { ok } from "assert";
6
6
  import { chance, getRandomString } from "../utils/random-utils";
7
- import { computeProbabilityMap } from "../probability";
8
7
  import { Order } from "../order";
9
8
  import { NodeSymbol, PREDICTABLE, UNSAFE } from "../constants";
10
9
  import {
@@ -127,11 +126,31 @@ export default ({ Plugin }: PluginArg): PluginObject => {
127
126
  return;
128
127
  }
129
128
 
129
+ var hasAssignmentPattern = false;
130
+
131
+ for (var param of path.get("params")) {
132
+ if (param.isAssignmentPattern()) {
133
+ hasAssignmentPattern = true;
134
+ break;
135
+ }
136
+ param.traverse({
137
+ AssignmentPattern(innerPath) {
138
+ var fn = innerPath.getFunctionParent();
139
+ if (fn === path) {
140
+ hasAssignmentPattern = true;
141
+ innerPath.stop();
142
+ } else {
143
+ innerPath.skip();
144
+ }
145
+ },
146
+ });
147
+
148
+ if (hasAssignmentPattern) break;
149
+ }
150
+
130
151
  // Functions with default parameters are not fully supported
131
152
  // (Could be a Function Expression referencing outer scope)
132
- if (
133
- path.node.params.find((x) => x.type === "AssignmentPattern")
134
- ) {
153
+ if (hasAssignmentPattern) {
135
154
  illegalNames.add(name);
136
155
  return;
137
156
  }
@@ -146,7 +165,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
146
165
  }
147
166
 
148
167
  for (var name of functionPaths.keys()) {
149
- if (!computeProbabilityMap(me.options.dispatcher, name)) {
168
+ if (!me.computeProbabilityMap(me.options.dispatcher, name)) {
150
169
  functionPaths.delete(name);
151
170
  }
152
171
  }
@@ -2,7 +2,11 @@ import * as t from "@babel/types";
2
2
  import { ok } from "assert";
3
3
  import { PluginArg, PluginObject } from "../plugin";
4
4
  import { Order } from "../../order";
5
- import { ensureComputedExpression, prepend } from "../../utils/ast-utils";
5
+ import {
6
+ ensureComputedExpression,
7
+ isModuleImport,
8
+ prepend,
9
+ } from "../../utils/ast-utils";
6
10
  import { createLiteral, LiteralValue, numericLiteral } from "../../utils/node";
7
11
  import { NodePath } from "@babel/traverse";
8
12
 
@@ -49,6 +53,11 @@ export default ({ Plugin }: PluginArg): PluginObject => {
49
53
  t.Literal | t.Identifier
50
54
  >;
51
55
 
56
+ // Don't change module imports
57
+ if (literalPath.isStringLiteral()) {
58
+ if (isModuleImport(literalPath)) return;
59
+ }
60
+
52
61
  let node = literalPath.node;
53
62
  var isUndefined = false;
54
63
  if (literalPath.isIdentifier()) {
@@ -7,7 +7,6 @@ import {
7
7
  getObjectPropertyAsString,
8
8
  getParentFunctionOrProgram,
9
9
  } from "../../utils/ast-utils";
10
- import { computeProbabilityMap } from "../../probability";
11
10
 
12
11
  export default ({ Plugin }: PluginArg): PluginObject => {
13
12
  const me = Plugin(Order.ObjectExtraction, {
@@ -152,7 +151,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
152
151
  if (!isObjectSafe) return;
153
152
 
154
153
  if (
155
- !computeProbabilityMap(
154
+ !me.computeProbabilityMap(
156
155
  me.options.objectExtraction,
157
156
  identifier.node.name
158
157
  )
@@ -41,7 +41,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
41
41
  }),
42
42
 
43
43
  // Hexadecimal numbers
44
- NumberLiteral: {
44
+ NumericLiteral: {
45
45
  exit(path) {
46
46
  if (me.options.hexadecimalNumbers) {
47
47
  const { value } = path.node;
@@ -11,7 +11,6 @@ import {
11
11
  prependProgram,
12
12
  } from "../utils/ast-utils";
13
13
  import { PluginArg, PluginObject } from "./plugin";
14
- import { computeProbabilityMap } from "../probability";
15
14
  import { Order } from "../order";
16
15
  import { NodeSymbol, PREDICTABLE, UNSAFE } from "../constants";
17
16
  import {
@@ -58,7 +57,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
58
57
  functionName = "anonymous";
59
58
  }
60
59
 
61
- if (!computeProbabilityMap(me.options.flatten, functionName)) {
60
+ if (!me.computeProbabilityMap(me.options.flatten, functionName)) {
62
61
  return;
63
62
  }
64
63
 
@@ -117,26 +116,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
117
116
  return;
118
117
  }
119
118
 
120
- var definedLocal = identifierPath.scope;
121
- do {
122
- if (definedLocal.hasOwnBinding(identifierName)) return;
123
- if (definedLocal === fnPath.scope) break;
124
-
125
- definedLocal = definedLocal.parent;
126
- if (definedLocal === program.scope)
127
- ok(functionName + ":" + identifierName);
128
- } while (definedLocal);
129
-
130
- var cursor: Scope = fnPath.scope.parent;
131
- var isOutsideVariable = false;
132
-
133
- do {
134
- if (cursor.hasBinding(identifierName)) {
135
- isOutsideVariable = true;
136
- break;
137
- }
138
- cursor = cursor.parent;
139
- } while (cursor);
119
+ var isOutsideVariable =
120
+ fnPath.scope.parent.getBinding(identifierName) === binding;
140
121
 
141
122
  if (!isOutsideVariable) {
142
123
  return;