js-confuser 2.0.0-alpha.5 → 2.0.1

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 (113) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +43 -43
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/workflows/node.js.yml +28 -28
  4. package/.prettierrc +4 -4
  5. package/CHANGELOG.md +1015 -989
  6. package/CODE_OF_CONDUCT.md +131 -131
  7. package/CONTRIBUTING.md +52 -52
  8. package/LICENSE +21 -21
  9. package/Migration.md +72 -71
  10. package/README.md +86 -78
  11. package/dist/constants.js +43 -43
  12. package/dist/index.js +14 -23
  13. package/dist/obfuscator.js +31 -25
  14. package/dist/order.js +4 -4
  15. package/dist/presets.js +31 -31
  16. package/dist/templates/integrityTemplate.js +4 -4
  17. package/dist/templates/template.js +1 -2
  18. package/dist/transforms/astScrambler.js +1 -2
  19. package/dist/transforms/calculator.js +1 -2
  20. package/dist/transforms/controlFlowFlattening.js +93 -63
  21. package/dist/transforms/deadCode.js +1 -2
  22. package/dist/transforms/dispatcher.js +4 -5
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +1 -2
  24. package/dist/transforms/extraction/objectExtraction.js +1 -2
  25. package/dist/transforms/finalizer.js +1 -2
  26. package/dist/transforms/flatten.js +1 -2
  27. package/dist/transforms/identifier/globalConcealing.js +15 -2
  28. package/dist/transforms/identifier/movedDeclarations.js +8 -7
  29. package/dist/transforms/identifier/renameVariables.js +7 -7
  30. package/dist/transforms/lock/integrity.js +11 -10
  31. package/dist/transforms/lock/lock.js +2 -3
  32. package/dist/transforms/minify.js +11 -29
  33. package/dist/transforms/opaquePredicates.js +1 -2
  34. package/dist/transforms/pack.js +5 -2
  35. package/dist/transforms/plugin.js +18 -19
  36. package/dist/transforms/preparation.js +16 -16
  37. package/dist/transforms/renameLabels.js +1 -2
  38. package/dist/transforms/rgf.js +8 -9
  39. package/dist/transforms/shuffle.js +1 -2
  40. package/dist/transforms/string/encoding.js +1 -2
  41. package/dist/transforms/string/stringCompression.js +3 -4
  42. package/dist/transforms/string/stringConcealing.js +8 -3
  43. package/dist/transforms/string/stringEncoding.js +1 -2
  44. package/dist/transforms/variableMasking.js +1 -2
  45. package/dist/utils/NameGen.js +2 -2
  46. package/dist/utils/PredicateGen.js +1 -2
  47. package/dist/utils/ast-utils.js +87 -88
  48. package/dist/utils/function-utils.js +8 -8
  49. package/dist/utils/node.js +5 -6
  50. package/dist/utils/object-utils.js +4 -4
  51. package/dist/utils/random-utils.js +20 -20
  52. package/dist/utils/static-utils.js +1 -2
  53. package/dist/validateOptions.js +4 -7
  54. package/index.d.ts +17 -17
  55. package/package.json +61 -59
  56. package/src/constants.ts +168 -168
  57. package/src/index.ts +118 -118
  58. package/src/obfuscationResult.ts +49 -49
  59. package/src/obfuscator.ts +501 -497
  60. package/src/options.ts +407 -407
  61. package/src/order.ts +54 -54
  62. package/src/presets.ts +125 -125
  63. package/src/templates/bufferToStringTemplate.ts +57 -57
  64. package/src/templates/deadCodeTemplates.ts +1185 -1185
  65. package/src/templates/getGlobalTemplate.ts +76 -76
  66. package/src/templates/integrityTemplate.ts +64 -64
  67. package/src/templates/setFunctionLengthTemplate.ts +11 -11
  68. package/src/templates/stringCompressionTemplate.ts +20 -20
  69. package/src/templates/tamperProtectionTemplates.ts +120 -120
  70. package/src/templates/template.ts +224 -224
  71. package/src/transforms/astScrambler.ts +99 -99
  72. package/src/transforms/calculator.ts +99 -99
  73. package/src/transforms/controlFlowFlattening.ts +1716 -1664
  74. package/src/transforms/deadCode.ts +82 -82
  75. package/src/transforms/dispatcher.ts +450 -450
  76. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +156 -158
  77. package/src/transforms/extraction/objectExtraction.ts +186 -186
  78. package/src/transforms/finalizer.ts +74 -74
  79. package/src/transforms/flatten.ts +421 -420
  80. package/src/transforms/identifier/globalConcealing.ts +315 -295
  81. package/src/transforms/identifier/movedDeclarations.ts +252 -251
  82. package/src/transforms/identifier/renameVariables.ts +328 -321
  83. package/src/transforms/lock/integrity.ts +117 -114
  84. package/src/transforms/lock/lock.ts +418 -425
  85. package/src/transforms/minify.ts +615 -629
  86. package/src/transforms/opaquePredicates.ts +100 -100
  87. package/src/transforms/pack.ts +239 -231
  88. package/src/transforms/plugin.ts +173 -173
  89. package/src/transforms/preparation.ts +349 -347
  90. package/src/transforms/renameLabels.ts +175 -175
  91. package/src/transforms/rgf.ts +322 -322
  92. package/src/transforms/shuffle.ts +82 -82
  93. package/src/transforms/string/encoding.ts +144 -144
  94. package/src/transforms/string/stringCompression.ts +128 -128
  95. package/src/transforms/string/stringConcealing.ts +312 -298
  96. package/src/transforms/string/stringEncoding.ts +80 -80
  97. package/src/transforms/string/stringSplitting.ts +77 -77
  98. package/src/transforms/variableMasking.ts +257 -257
  99. package/src/utils/IntGen.ts +33 -33
  100. package/src/utils/NameGen.ts +116 -116
  101. package/src/utils/PredicateGen.ts +61 -61
  102. package/src/utils/ast-utils.ts +663 -663
  103. package/src/utils/function-utils.ts +50 -50
  104. package/src/utils/gen-utils.ts +48 -48
  105. package/src/utils/node.ts +78 -78
  106. package/src/utils/object-utils.ts +21 -21
  107. package/src/utils/random-utils.ts +93 -93
  108. package/src/utils/static-utils.ts +66 -66
  109. package/src/validateOptions.ts +256 -259
  110. package/tsconfig.json +13 -14
  111. package/dist/probability.js +0 -1
  112. package/dist/transforms/functionOutlining.js +0 -230
  113. package/dist/utils/ControlObject.js +0 -125
@@ -1,257 +1,257 @@
1
- import { Binding, NodePath } from "@babel/traverse";
2
- import { PluginArg, PluginObject } from "./plugin";
3
- import * as t from "@babel/types";
4
- import Template from "../templates/template";
5
- import { Order } from "../order";
6
- import {
7
- NodeSymbol,
8
- PREDICTABLE,
9
- reservedIdentifiers,
10
- UNSAFE,
11
- variableFunctionName,
12
- } from "../constants";
13
- import {
14
- ensureComputedExpression,
15
- getFunctionName,
16
- isDefiningIdentifier,
17
- isStrictMode,
18
- isVariableIdentifier,
19
- prepend,
20
- replaceDefiningIdentifierToMemberExpression,
21
- } from "../utils/ast-utils";
22
- import {
23
- computeFunctionLength,
24
- isVariableFunctionIdentifier,
25
- } from "../utils/function-utils";
26
- import { ok } from "assert";
27
- import { NameGen } from "../utils/NameGen";
28
- import { choice, getRandomInteger } from "../utils/random-utils";
29
- import { createLiteral } from "../utils/node";
30
-
31
- export default ({ Plugin }: PluginArg): PluginObject => {
32
- const me = Plugin(Order.VariableMasking, {
33
- changeData: {
34
- functions: 0,
35
- },
36
- });
37
-
38
- const transformFunction = (fnPath: NodePath<t.Function>) => {
39
- // Do not apply to getter/setter methods
40
- if (fnPath.isObjectMethod() && fnPath.node.kind !== "method") {
41
- return;
42
- }
43
-
44
- // Do not apply to class getters/setters
45
- if (fnPath.isClassMethod() && fnPath.node.kind !== "method") {
46
- return;
47
- }
48
-
49
- // Do not apply to async or generator functions
50
- if (fnPath.node.generator || fnPath.node.async) {
51
- return;
52
- }
53
-
54
- // Do not apply to functions with rest parameters or destructuring
55
- if (fnPath.node.params.some((param) => !t.isIdentifier(param))) {
56
- return;
57
- }
58
-
59
- // Do not apply to 'use strict' functions
60
- if (isStrictMode(fnPath)) return;
61
-
62
- // Do not apply to functions marked unsafe
63
- if ((fnPath.node as NodeSymbol)[UNSAFE]) return;
64
-
65
- const functionName = getFunctionName(fnPath);
66
-
67
- if (!me.computeProbabilityMap(me.options.variableMasking, functionName)) {
68
- return;
69
- }
70
-
71
- const stackName = me.getPlaceholder() + "_varMask";
72
- const stackMap = new Map<Binding, number | string>();
73
- const propertyGen = new NameGen("mangled");
74
- const stackKeys = new Set<string>();
75
- let needsStack = false;
76
-
77
- const illegalBindings = new Set<Binding>();
78
-
79
- function checkBinding(binding: Binding) {
80
- // Custom illegal check
81
- // Variable Declarations with more than one declarator are not supported
82
- // They can be inserted from the user's code even though Preparation phase should prevent it
83
- // String Compression library includes such code
84
- // TODO: Support multiple declarators
85
- var variableDeclaration = binding.path.find((p) =>
86
- p.isVariableDeclaration()
87
- ) as NodePath<t.VariableDeclaration>;
88
- if (
89
- variableDeclaration &&
90
- variableDeclaration.node.declarations.length > 1
91
- ) {
92
- return false;
93
- }
94
-
95
- function checkForUnsafe(valuePath: NodePath) {
96
- var hasUnsafeNode = false;
97
-
98
- valuePath.traverse({
99
- ThisExpression(path) {
100
- hasUnsafeNode = true;
101
- path.stop();
102
- },
103
- Function(path) {
104
- if ((path.node as NodeSymbol)[UNSAFE]) {
105
- hasUnsafeNode = true;
106
- path.stop();
107
- }
108
- },
109
- });
110
-
111
- return hasUnsafeNode;
112
- }
113
-
114
- // Check function value for 'this'
115
- // Adding function expression to the stack (member expression)
116
- // would break the 'this' context
117
- if (binding.path.isVariableDeclarator()) {
118
- let init = binding.path.get("init");
119
- if (init.node) {
120
- if (checkForUnsafe(init)) return false;
121
- }
122
- }
123
-
124
- // x = function(){ return this }
125
- // Cannot be transformed to x = stack[0] as 'this' would change
126
- for (var assignment of binding.constantViolations) {
127
- if (checkForUnsafe(assignment)) return false;
128
- }
129
-
130
- // __JS_CONFUSER_VAR__(identifier) -> __JS_CONFUSER_VAR__(stack.identifier)
131
- // This cannot be transformed as it would break the user's code
132
- for (var referencePath of binding.referencePaths) {
133
- if (isVariableFunctionIdentifier(referencePath)) {
134
- return false;
135
- }
136
- }
137
-
138
- return true;
139
- }
140
-
141
- for (const param of fnPath.get("params")) {
142
- ok(param.isIdentifier());
143
-
144
- const paramName = param.node.name;
145
- const binding = param.scope.getBinding(paramName);
146
-
147
- if (!binding || !checkBinding(binding)) return;
148
-
149
- ok(!stackMap.has(binding));
150
- stackKeys.add(stackMap.size.toString());
151
- stackMap.set(binding, stackMap.size);
152
- }
153
-
154
- fnPath.traverse({
155
- Identifier(path) {
156
- if (!isVariableIdentifier(path)) return;
157
- if (fnPath.get("id") === path) return; // Skip this function's name (Test #21)
158
-
159
- if (reservedIdentifiers.has(path.node.name)) return;
160
- if (me.options.globalVariables.has(path.node.name)) return;
161
- if (path.node.name === stackName) return;
162
- if (path.node.name === variableFunctionName) return;
163
-
164
- const binding = path.scope.getBinding(path.node.name);
165
- if (!binding || binding.scope !== fnPath.scope) return;
166
- if (illegalBindings.has(binding)) return;
167
-
168
- needsStack = true;
169
-
170
- let index = stackMap.get(binding);
171
- if (typeof index === "undefined") {
172
- // Only transform var and let bindings
173
- // Function declarations could be hoisted and changing them to declarations is breaking
174
- if (!["var", "let"].includes(binding.kind)) {
175
- illegalBindings.add(binding);
176
- return;
177
- }
178
-
179
- if (!checkBinding(binding)) {
180
- illegalBindings.add(binding);
181
- return;
182
- }
183
-
184
- do {
185
- index = choice([
186
- stackMap.size,
187
- propertyGen.generate(),
188
- getRandomInteger(-250, 250),
189
- ]);
190
- } while (!index || stackKeys.has(index.toString()));
191
-
192
- stackMap.set(binding, index);
193
- stackKeys.add(index.toString());
194
- }
195
-
196
- const memberExpression = t.memberExpression(
197
- t.identifier(stackName),
198
- createLiteral(index),
199
- true
200
- );
201
-
202
- if (isDefiningIdentifier(path)) {
203
- replaceDefiningIdentifierToMemberExpression(path, memberExpression);
204
-
205
- return;
206
- }
207
-
208
- ensureComputedExpression(path);
209
- path.replaceWith(memberExpression);
210
- },
211
- });
212
-
213
- if (!needsStack) return;
214
-
215
- const originalParamCount = fnPath.node.params.length;
216
- const originalLength = computeFunctionLength(fnPath);
217
-
218
- fnPath.node.params = [t.restElement(t.identifier(stackName))];
219
-
220
- // Discard extraneous parameters
221
- // Predictable functions are guaranteed to not have extraneous parameters
222
- if (!(fnPath.node as NodeSymbol)[PREDICTABLE]) {
223
- prepend(
224
- fnPath,
225
- new Template(`${stackName}["length"] = {originalParamCount};`).single({
226
- originalParamCount: t.numericLiteral(originalParamCount),
227
- })
228
- );
229
- }
230
-
231
- // Function is no longer predictable
232
- (fnPath.node as NodeSymbol)[PREDICTABLE] = false;
233
-
234
- fnPath.scope.registerBinding("param", fnPath.get("params")[0], fnPath);
235
-
236
- me.setFunctionLength(fnPath, originalLength);
237
-
238
- me.changeData.functions++;
239
- };
240
-
241
- return {
242
- visitor: {
243
- Function: {
244
- exit(path: NodePath<t.Function>) {
245
- if (!path.get("body").isBlockStatement()) return;
246
-
247
- transformFunction(path);
248
- },
249
- },
250
- Program: {
251
- enter(path) {
252
- path.scope.crawl();
253
- },
254
- },
255
- },
256
- };
257
- };
1
+ import { Binding, NodePath } from "@babel/traverse";
2
+ import { PluginArg, PluginObject } from "./plugin";
3
+ import * as t from "@babel/types";
4
+ import Template from "../templates/template";
5
+ import { Order } from "../order";
6
+ import {
7
+ NodeSymbol,
8
+ PREDICTABLE,
9
+ reservedIdentifiers,
10
+ UNSAFE,
11
+ variableFunctionName,
12
+ } from "../constants";
13
+ import {
14
+ ensureComputedExpression,
15
+ getFunctionName,
16
+ isDefiningIdentifier,
17
+ isStrictMode,
18
+ isVariableIdentifier,
19
+ prepend,
20
+ replaceDefiningIdentifierToMemberExpression,
21
+ } from "../utils/ast-utils";
22
+ import {
23
+ computeFunctionLength,
24
+ isVariableFunctionIdentifier,
25
+ } from "../utils/function-utils";
26
+ import { ok } from "assert";
27
+ import { NameGen } from "../utils/NameGen";
28
+ import { choice, getRandomInteger } from "../utils/random-utils";
29
+ import { createLiteral } from "../utils/node";
30
+
31
+ export default ({ Plugin }: PluginArg): PluginObject => {
32
+ const me = Plugin(Order.VariableMasking, {
33
+ changeData: {
34
+ functions: 0,
35
+ },
36
+ });
37
+
38
+ const transformFunction = (fnPath: NodePath<t.Function>) => {
39
+ // Do not apply to getter/setter methods
40
+ if (fnPath.isObjectMethod() && fnPath.node.kind !== "method") {
41
+ return;
42
+ }
43
+
44
+ // Do not apply to class getters/setters
45
+ if (fnPath.isClassMethod() && fnPath.node.kind !== "method") {
46
+ return;
47
+ }
48
+
49
+ // Do not apply to async or generator functions
50
+ if (fnPath.node.generator || fnPath.node.async) {
51
+ return;
52
+ }
53
+
54
+ // Do not apply to functions with rest parameters or destructuring
55
+ if (fnPath.node.params.some((param) => !t.isIdentifier(param))) {
56
+ return;
57
+ }
58
+
59
+ // Do not apply to 'use strict' functions
60
+ if (isStrictMode(fnPath)) return;
61
+
62
+ // Do not apply to functions marked unsafe
63
+ if ((fnPath.node as NodeSymbol)[UNSAFE]) return;
64
+
65
+ const functionName = getFunctionName(fnPath);
66
+
67
+ if (!me.computeProbabilityMap(me.options.variableMasking, functionName)) {
68
+ return;
69
+ }
70
+
71
+ const stackName = me.getPlaceholder() + "_varMask";
72
+ const stackMap = new Map<Binding, number | string>();
73
+ const propertyGen = new NameGen("mangled");
74
+ const stackKeys = new Set<string>();
75
+ let needsStack = false;
76
+
77
+ const illegalBindings = new Set<Binding>();
78
+
79
+ function checkBinding(binding: Binding) {
80
+ // Custom illegal check
81
+ // Variable Declarations with more than one declarator are not supported
82
+ // They can be inserted from the user's code even though Preparation phase should prevent it
83
+ // String Compression library includes such code
84
+ // TODO: Support multiple declarators
85
+ var variableDeclaration = binding.path.find((p) =>
86
+ p.isVariableDeclaration()
87
+ ) as NodePath<t.VariableDeclaration>;
88
+ if (
89
+ variableDeclaration &&
90
+ variableDeclaration.node.declarations.length > 1
91
+ ) {
92
+ return false;
93
+ }
94
+
95
+ function checkForUnsafe(valuePath: NodePath) {
96
+ var hasUnsafeNode = false;
97
+
98
+ valuePath.traverse({
99
+ ThisExpression(path) {
100
+ hasUnsafeNode = true;
101
+ path.stop();
102
+ },
103
+ Function(path) {
104
+ if ((path.node as NodeSymbol)[UNSAFE]) {
105
+ hasUnsafeNode = true;
106
+ path.stop();
107
+ }
108
+ },
109
+ });
110
+
111
+ return hasUnsafeNode;
112
+ }
113
+
114
+ // Check function value for 'this'
115
+ // Adding function expression to the stack (member expression)
116
+ // would break the 'this' context
117
+ if (binding.path.isVariableDeclarator()) {
118
+ let init = binding.path.get("init");
119
+ if (init.node) {
120
+ if (checkForUnsafe(init)) return false;
121
+ }
122
+ }
123
+
124
+ // x = function(){ return this }
125
+ // Cannot be transformed to x = stack[0] as 'this' would change
126
+ for (var assignment of binding.constantViolations) {
127
+ if (checkForUnsafe(assignment)) return false;
128
+ }
129
+
130
+ // __JS_CONFUSER_VAR__(identifier) -> __JS_CONFUSER_VAR__(stack.identifier)
131
+ // This cannot be transformed as it would break the user's code
132
+ for (var referencePath of binding.referencePaths) {
133
+ if (isVariableFunctionIdentifier(referencePath)) {
134
+ return false;
135
+ }
136
+ }
137
+
138
+ return true;
139
+ }
140
+
141
+ for (const param of fnPath.get("params")) {
142
+ ok(param.isIdentifier());
143
+
144
+ const paramName = param.node.name;
145
+ const binding = param.scope.getBinding(paramName);
146
+
147
+ if (!binding || !checkBinding(binding)) return;
148
+
149
+ ok(!stackMap.has(binding));
150
+ stackKeys.add(stackMap.size.toString());
151
+ stackMap.set(binding, stackMap.size);
152
+ }
153
+
154
+ fnPath.traverse({
155
+ Identifier(path) {
156
+ if (!isVariableIdentifier(path)) return;
157
+ if (fnPath.get("id") === path) return; // Skip this function's name (Test #21)
158
+
159
+ if (reservedIdentifiers.has(path.node.name)) return;
160
+ if (me.options.globalVariables.has(path.node.name)) return;
161
+ if (path.node.name === stackName) return;
162
+ if (path.node.name === variableFunctionName) return;
163
+
164
+ const binding = path.scope.getBinding(path.node.name);
165
+ if (!binding || binding.scope !== fnPath.scope) return;
166
+ if (illegalBindings.has(binding)) return;
167
+
168
+ needsStack = true;
169
+
170
+ let index = stackMap.get(binding);
171
+ if (typeof index === "undefined") {
172
+ // Only transform var and let bindings
173
+ // Function declarations could be hoisted and changing them to declarations is breaking
174
+ if (!["var", "let"].includes(binding.kind)) {
175
+ illegalBindings.add(binding);
176
+ return;
177
+ }
178
+
179
+ if (!checkBinding(binding)) {
180
+ illegalBindings.add(binding);
181
+ return;
182
+ }
183
+
184
+ do {
185
+ index = choice([
186
+ stackMap.size,
187
+ propertyGen.generate(),
188
+ getRandomInteger(-250, 250),
189
+ ]);
190
+ } while (!index || stackKeys.has(index.toString()));
191
+
192
+ stackMap.set(binding, index);
193
+ stackKeys.add(index.toString());
194
+ }
195
+
196
+ const memberExpression = t.memberExpression(
197
+ t.identifier(stackName),
198
+ createLiteral(index),
199
+ true
200
+ );
201
+
202
+ if (isDefiningIdentifier(path)) {
203
+ replaceDefiningIdentifierToMemberExpression(path, memberExpression);
204
+
205
+ return;
206
+ }
207
+
208
+ ensureComputedExpression(path);
209
+ path.replaceWith(memberExpression);
210
+ },
211
+ });
212
+
213
+ if (!needsStack) return;
214
+
215
+ const originalParamCount = fnPath.node.params.length;
216
+ const originalLength = computeFunctionLength(fnPath);
217
+
218
+ fnPath.node.params = [t.restElement(t.identifier(stackName))];
219
+
220
+ // Discard extraneous parameters
221
+ // Predictable functions are guaranteed to not have extraneous parameters
222
+ if (!(fnPath.node as NodeSymbol)[PREDICTABLE]) {
223
+ prepend(
224
+ fnPath,
225
+ new Template(`${stackName}["length"] = {originalParamCount};`).single({
226
+ originalParamCount: t.numericLiteral(originalParamCount),
227
+ })
228
+ );
229
+ }
230
+
231
+ // Function is no longer predictable
232
+ (fnPath.node as NodeSymbol)[PREDICTABLE] = false;
233
+
234
+ fnPath.scope.registerBinding("param", fnPath.get("params")[0], fnPath);
235
+
236
+ me.setFunctionLength(fnPath, originalLength);
237
+
238
+ me.changeData.functions++;
239
+ };
240
+
241
+ return {
242
+ visitor: {
243
+ Function: {
244
+ exit(path: NodePath<t.Function>) {
245
+ if (!path.get("body").isBlockStatement()) return;
246
+
247
+ transformFunction(path);
248
+ },
249
+ },
250
+ Program: {
251
+ enter(path) {
252
+ path.scope.crawl();
253
+ },
254
+ },
255
+ },
256
+ };
257
+ };
@@ -1,33 +1,33 @@
1
- export class IntGen {
2
- private min: number;
3
- private max: number;
4
- private generatedInts: Set<number>;
5
-
6
- constructor(min: number = -250, max: number = 250) {
7
- this.min = min;
8
- this.max = max;
9
- this.generatedInts = new Set<number>();
10
- }
11
-
12
- private getRandomInt(min: number, max: number): number {
13
- return Math.floor(Math.random() * (max - min + 1)) + min;
14
- }
15
-
16
- generate(): number {
17
- let randomInt: number;
18
-
19
- // Keep generating until we find a unique integer
20
- do {
21
- randomInt = this.getRandomInt(this.min, this.max);
22
-
23
- // Expand the range if most integers in the current range are exhausted
24
- if (this.generatedInts.size >= 0.8 * (this.max - this.min)) {
25
- this.min -= 100;
26
- this.max += 100;
27
- }
28
- } while (this.generatedInts.has(randomInt));
29
-
30
- this.generatedInts.add(randomInt);
31
- return randomInt;
32
- }
33
- }
1
+ export class IntGen {
2
+ private min: number;
3
+ private max: number;
4
+ private generatedInts: Set<number>;
5
+
6
+ constructor(min: number = -250, max: number = 250) {
7
+ this.min = min;
8
+ this.max = max;
9
+ this.generatedInts = new Set<number>();
10
+ }
11
+
12
+ private getRandomInt(min: number, max: number): number {
13
+ return Math.floor(Math.random() * (max - min + 1)) + min;
14
+ }
15
+
16
+ generate(): number {
17
+ let randomInt: number;
18
+
19
+ // Keep generating until we find a unique integer
20
+ do {
21
+ randomInt = this.getRandomInt(this.min, this.max);
22
+
23
+ // Expand the range if most integers in the current range are exhausted
24
+ if (this.generatedInts.size >= 0.8 * (this.max - this.min)) {
25
+ this.min -= 100;
26
+ this.max += 100;
27
+ }
28
+ } while (this.generatedInts.has(randomInt));
29
+
30
+ this.generatedInts.add(randomInt);
31
+ return randomInt;
32
+ }
33
+ }