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
@@ -330,3 +330,27 @@ it("should apply to every level of the code", async () => {
330
330
 
331
331
  expect(value).toStrictEqual(100);
332
332
  });
333
+
334
+ // https://github.com/MichaelXF/js-confuser/issues/77
335
+ it("should work with code that uses toString() function", async () => {
336
+ var output = await JsConfuser(
337
+ `
338
+ function myFunction(){
339
+
340
+ }
341
+
342
+ TEST_OUTPUT = toString();
343
+ `,
344
+ {
345
+ target: "node",
346
+ dispatcher: true,
347
+ }
348
+ );
349
+
350
+ var toString = () => "Correct Value";
351
+ var TEST_OUTPUT;
352
+
353
+ eval(output);
354
+
355
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
356
+ });
@@ -392,3 +392,36 @@ it("should work with stringConcealing and hide method names", async () => {
392
392
 
393
393
  expect(TEST_VALUE).toStrictEqual(100);
394
394
  });
395
+
396
+ // https://github.com/MichaelXF/js-confuser/issues/72
397
+ it("should support class fields", async () => {
398
+ var output = await JsConfuser(
399
+ `
400
+ class MyClass {
401
+ myField = 1;
402
+ ["myComputedField"] = 2;
403
+
404
+ static myStaticField = 3;
405
+ static ["myComputedStaticField"] = 4;
406
+ }
407
+
408
+ var myObject = new MyClass();
409
+ TEST_OUTPUT_1 = myObject.myField;
410
+ TEST_OUTPUT_2 = myObject.myComputedField;
411
+ TEST_OUTPUT_3 = MyClass.myStaticField;
412
+ TEST_OUTPUT_4 = MyClass.myComputedStaticField;
413
+ `,
414
+ {
415
+ target: "node",
416
+ es5: true,
417
+ }
418
+ );
419
+
420
+ var TEST_OUTPUT_1, TEST_OUTPUT_2, TEST_OUTPUT_3, TEST_OUTPUT_4;
421
+
422
+ eval(output);
423
+ expect(TEST_OUTPUT_1).toStrictEqual(1);
424
+ expect(TEST_OUTPUT_2).toStrictEqual(2);
425
+ expect(TEST_OUTPUT_3).toStrictEqual(3);
426
+ expect(TEST_OUTPUT_4).toStrictEqual(4);
427
+ });
@@ -76,3 +76,56 @@ it("should work with Integrity also enabled", async () => {
76
76
 
77
77
  expect(value).toStrictEqual("Hello World");
78
78
  });
79
+
80
+ it("should work on async functions", async () => {
81
+ var output = await JsConfuser(
82
+ `
83
+ async function myFunction(){
84
+ return "Correct Value";
85
+ }
86
+
87
+ (async ()=>{
88
+ TEST_FUNCTION( await myFunction() );
89
+ })();
90
+ `,
91
+ { target: "node", eval: true }
92
+ );
93
+
94
+ expect(output).toContain("eval");
95
+
96
+ var wasCalled = false;
97
+
98
+ function TEST_FUNCTION(value) {
99
+ wasCalled = true;
100
+ expect(value).toStrictEqual("Correct Value");
101
+ }
102
+
103
+ eval(output);
104
+
105
+ setTimeout(() => {
106
+ expect(wasCalled).toStrictEqual(true);
107
+ }, 1000);
108
+ });
109
+
110
+ it("should work on generator functions", async () => {
111
+ var output = await JsConfuser(
112
+ `
113
+ function* myFunction(){
114
+ yield "Correct Value";
115
+ }
116
+
117
+ const gen = myFunction();
118
+
119
+ TEST_OUTPUT = gen.next().value;
120
+ `,
121
+ { target: "node", eval: true }
122
+ );
123
+
124
+ expect(output).toContain("eval");
125
+
126
+ var TEST_OUTPUT;
127
+
128
+ eval(output);
129
+
130
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
131
+ });
@@ -446,3 +446,24 @@ it("should not apply to objects with non-init properties (method, set, get)", as
446
446
  expect(output).toContain("TEST_OBJECT");
447
447
  expect(output).toContain("set ");
448
448
  });
449
+
450
+ // https://github.com/MichaelXF/js-confuser/issues/78
451
+ it("should handle objects with spread elements", async () => {
452
+ var output = await JsConfuser(
453
+ `
454
+ var x = { firstName: "John", lastName: "Doe" }
455
+ var y = { ...x };
456
+
457
+ TEST_OUTPUT = y;
458
+ `,
459
+ {
460
+ target: "node",
461
+ objectExtraction: true,
462
+ }
463
+ );
464
+
465
+ var TEST_OUTPUT;
466
+ eval(output);
467
+
468
+ expect(TEST_OUTPUT).toStrictEqual({ firstName: "John", lastName: "Doe" });
469
+ });
@@ -4,7 +4,7 @@ it("should bring independent to the global level", async () => {
4
4
  var output = await JsConfuser.obfuscate(
5
5
  `
6
6
  function container(){
7
- function nested(){
7
+ function nested(param){
8
8
 
9
9
  }
10
10
 
@@ -17,7 +17,8 @@ it("should bring independent to the global level", async () => {
17
17
  }
18
18
  );
19
19
 
20
- expect(output).toContain("set");
20
+ // Ensure flatten was applied
21
+ expect(output).toContain("[param]");
21
22
  });
22
23
 
23
24
  it("should have correct return values", async () => {
@@ -255,7 +256,8 @@ it("should work when pattern-based assignment expressions are involved", async (
255
256
  }
256
257
  );
257
258
 
258
- expect(output).toContain("set");
259
+ // Ensure flatten was applied
260
+ expect(output).toContain("[i],[]");
259
261
 
260
262
  var value = "never_called",
261
263
  input = (x) => (value = x);
@@ -263,3 +265,144 @@ it("should work when pattern-based assignment expressions are involved", async (
263
265
  eval(output);
264
266
  expect(value).toStrictEqual(1);
265
267
  });
268
+
269
+ it("should work on async functions", async () => {
270
+ var output = await JsConfuser.obfuscate(
271
+ `
272
+ async function timeout(ms){
273
+ return await new Promise((resolve, reject)=>{
274
+ setTimeout(()=>{
275
+ resolve();
276
+ }, ms);
277
+ });
278
+ }
279
+
280
+ (async ()=>{
281
+ var startTime = Date.now();
282
+
283
+ await timeout(1000);
284
+
285
+ var endTime = Date.now();
286
+
287
+ var duration = endTime - startTime;
288
+
289
+ TEST_CALLBACK(duration);
290
+ })();
291
+ `,
292
+ {
293
+ target: "node",
294
+ flatten: true,
295
+ }
296
+ );
297
+
298
+ expect(output).toContain("_flat_timeout");
299
+
300
+ var wasCalled = false;
301
+ var TEST_CALLBACK = (time) => {
302
+ expect(time).toBeGreaterThan(500);
303
+ wasCalled = true;
304
+ };
305
+
306
+ eval(output);
307
+
308
+ setTimeout(() => {
309
+ expect(wasCalled).toStrictEqual(true);
310
+ }, 2000);
311
+ });
312
+
313
+ it("should work on Function Expressions", async () => {
314
+ var output = await JsConfuser.obfuscate(
315
+ `
316
+ var outsideVar = "Correct Value";
317
+
318
+ var myFunctionExpression = function(){
319
+ return outsideVar;
320
+ }
321
+
322
+ TEST_OUTPUT = myFunctionExpression();
323
+ `,
324
+ {
325
+ target: "node",
326
+ flatten: true,
327
+ }
328
+ );
329
+
330
+ // Ensure flatten applied
331
+ expect(output).toContain("_flat_myFunctionExpression");
332
+
333
+ var TEST_OUTPUT;
334
+ eval(output);
335
+
336
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
337
+ });
338
+
339
+ it("should work on Properties", async () => {
340
+ var output = await JsConfuser.obfuscate(
341
+ `
342
+ var outsideVar = "Incorrect Value";
343
+
344
+ var myObject = {
345
+ myInitProperty: function(){
346
+ return outsideVar;
347
+ },
348
+
349
+ myMethodProperty(){
350
+ return;
351
+ },
352
+
353
+ get myGetProperty(){
354
+ return;
355
+ },
356
+
357
+ set mySetProperty(val){
358
+ outsideVar = val;
359
+ }
360
+ }
361
+
362
+ myObject.mySetProperty = "Correct Value";
363
+ TEST_OUTPUT = myObject.myInitProperty();
364
+ `,
365
+ {
366
+ target: "node",
367
+ flatten: true,
368
+ }
369
+ );
370
+
371
+ // Ensure flatten applied
372
+ expect(output).toContain("_flat_myInitProperty");
373
+
374
+ var TEST_OUTPUT;
375
+ eval(output);
376
+
377
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
378
+ });
379
+
380
+ it("should work with RGF enabled", async () => {
381
+ var output = await JsConfuser.obfuscate(
382
+ `
383
+ var outsideVar = "Correct Value";
384
+
385
+ function myFunction(){
386
+ return outsideVar;
387
+ }
388
+
389
+ TEST_OUTPUT = myFunction();
390
+ `,
391
+ {
392
+ target: "node",
393
+ flatten: true,
394
+ rgf: true,
395
+ }
396
+ );
397
+
398
+ // Ensure flatten applied
399
+ expect(output).toContain("_flat_myFunction");
400
+
401
+ // Ensure RGF applied
402
+ expect(output).toContain("new Function");
403
+
404
+ var TEST_OUTPUT;
405
+ eval(output);
406
+
407
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
408
+ });
@@ -164,3 +164,42 @@ it("should convert variable declarations in for loop initializers properly", asy
164
164
  expect(TEST_VAR_1).toStrictEqual("Hello World");
165
165
  expect(TEST_VAR_2).toStrictEqual("Number: 0");
166
166
  });
167
+
168
+ // https://github.com/MichaelXF/js-confuser/issues/68
169
+ it("should work on Function Declarations that are defined later in the code", async () => {
170
+ var output = await JsConfuser(
171
+ `
172
+ var result = MyFunction();
173
+ TEST_VAR = result;
174
+
175
+ function MyFunction(b) {
176
+ return "Hello World";
177
+ }
178
+ `,
179
+ { target: "node", nameRecycling: true }
180
+ );
181
+
182
+ var TEST_VAR;
183
+ eval(output);
184
+
185
+ expect(TEST_VAR).toStrictEqual("Hello World");
186
+ });
187
+
188
+ // https://github.com/MichaelXF/js-confuser/issues/71
189
+ it("should work on Import Declarations", async () => {
190
+ var output = await JsConfuser(
191
+ `
192
+ import crypto from 'node:crypto'
193
+
194
+ var x = 1;
195
+
196
+ console.log(x);
197
+ `,
198
+ {
199
+ target: "node",
200
+ nameRecycling: true,
201
+ }
202
+ );
203
+
204
+ expect(output).not.toContain("crypto=");
205
+ });
@@ -436,3 +436,67 @@ test("Variant #18: Catch parameter and lexical variable clash", async () => {
436
436
 
437
437
  eval(output);
438
438
  });
439
+
440
+ // https://github.com/MichaelXF/js-confuser/issues/69
441
+ test("Variant #19: Don't break Import Declarations", async () => {
442
+ var output = await JsConfuser(
443
+ `
444
+ import { createHash } from 'node:crypto'
445
+
446
+ function sha256(content) {
447
+ return createHash('sha256').update(content).digest('hex')
448
+ }
449
+
450
+ TEST_OUTPUT = sha256("Hash this string");
451
+ `,
452
+ {
453
+ target: "node",
454
+ renameVariables: true,
455
+ }
456
+ );
457
+
458
+ // Ensure the createHash got renamed
459
+ expect(output).toContain("createHash as ");
460
+
461
+ // Convert to runnable code
462
+ // This smartly changes the `import` statement to a require call, keeping the new variable name intact
463
+ var newVarName = output.split("createHash as ")[1].split("}")[0];
464
+ output = output
465
+ .split(";")
466
+ .filter((s) => !s.startsWith("import"))
467
+ .join(";");
468
+ output = `var {createHash: ${newVarName}}=require('crypto');` + output;
469
+
470
+ var TEST_OUTPUT;
471
+ eval(output);
472
+
473
+ expect(TEST_OUTPUT).toStrictEqual(
474
+ "1cac63f39fd68d8c531f27b807610fb3d50f0fc3f186995767fb6316e7200a3e"
475
+ );
476
+ });
477
+
478
+ // https://github.com/MichaelXF/js-confuser/issues/80
479
+ test("Variant #20: Don't break code with var and let variables in same scope", async () => {
480
+ var output = await JsConfuser(
481
+ `
482
+ function log(param) {
483
+ let message = param;
484
+ var isWarning = false;
485
+ var isError = false;
486
+
487
+ TEST_OUTPUT = message;
488
+ };
489
+
490
+ log("Correct Value");
491
+ `,
492
+ {
493
+ target: "node",
494
+ renameVariables: true,
495
+ }
496
+ );
497
+
498
+ var TEST_OUTPUT;
499
+ eval(output);
500
+
501
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
502
+ });
@@ -269,6 +269,7 @@ test("Variant #15: Removing implied 'return'", async () => {
269
269
  function MyFunction(){
270
270
  var output = "Hello World";
271
271
  console.log(output);
272
+ this; // Stop arrow function conversion
272
273
  return;
273
274
  }
274
275
 
@@ -366,3 +367,68 @@ test("Variant #19: Remove unreachable code following a throw statement", async (
366
367
 
367
368
  expect(output).not.toContain("unreachableStmt");
368
369
  });
370
+
371
+ // https://github.com/MichaelXF/js-confuser/issues/76
372
+ test("Variant #20: Properly handle objects with `, ^, [, ] as keys", async () => {
373
+ var output = await JsConfuser(
374
+ `
375
+ TEST_OBJECT = {
376
+ "\`": true,
377
+ "^": true,
378
+ "]": true,
379
+ "[": true
380
+ };
381
+ `,
382
+ {
383
+ target: "node",
384
+ minify: true,
385
+ }
386
+ );
387
+
388
+ var TEST_OBJECT;
389
+ eval(output);
390
+
391
+ expect(TEST_OBJECT).toStrictEqual({
392
+ "`": true,
393
+ "^": true,
394
+ "]": true,
395
+ "[": true,
396
+ });
397
+ });
398
+
399
+ // https://github.com/MichaelXF/js-confuser/issues/75
400
+ test("Variant #21: Properly handle Object constructor (Function Declaration)", async () => {
401
+ var output = await JsConfuser(
402
+ `
403
+ function MyClass() {};
404
+
405
+ var myObject = new MyClass();
406
+
407
+ TEST_OUTPUT = myObject instanceof MyClass;
408
+ `,
409
+ { target: "node", minify: true }
410
+ );
411
+
412
+ var TEST_OUTPUT = false;
413
+ eval(output);
414
+
415
+ expect(TEST_OUTPUT).toStrictEqual(true);
416
+ });
417
+
418
+ test("Variant #22: Properly handle Object constructor (Function Expression)", async () => {
419
+ var output = await JsConfuser(
420
+ `
421
+ var MyClass = function() {};
422
+
423
+ var myObject = new MyClass();
424
+
425
+ TEST_OUTPUT = myObject instanceof MyClass;
426
+ `,
427
+ { target: "node", minify: true }
428
+ );
429
+
430
+ var TEST_OUTPUT = false;
431
+ eval(output);
432
+
433
+ expect(TEST_OUTPUT).toStrictEqual(true);
434
+ });
@@ -288,6 +288,62 @@ input(console.log, result)
288
288
 
289
289
  expect(output).not.toContain("new Function");
290
290
  });
291
+
292
+ it("should work with Control Flow Flattening and Duplicate Literals Removal enabled", async () => {
293
+ var output = await JsConfuser.obfuscate(
294
+ `
295
+ var x = [1,1,1,1,1,1,1,1,1,1];
296
+
297
+ function myFunction(){
298
+ return 1;
299
+ };
300
+
301
+ input( myFunction() ); // 1
302
+ `,
303
+ {
304
+ target: "node",
305
+ controlFlowFlattening: true,
306
+ duplicateLiteralsRemoval: true,
307
+ rgf: true,
308
+ }
309
+ );
310
+
311
+ var value = "never_called";
312
+ function input(valueIn) {
313
+ value = valueIn;
314
+ }
315
+
316
+ eval(output);
317
+
318
+ expect(value).toStrictEqual(1);
319
+ });
320
+
321
+ it("should work with String Encoding enabled", async () => {
322
+ var output = await JsConfuser.obfuscate(
323
+ `
324
+ function myFunction(){
325
+ var val1 = "\\x43\\x6F\\x72\\x72\\x65\\x63\\x74\\x20\\x56\\x61\\x6C\\x75\\x65"; // "Correct Value"
326
+ var val2 = "Correct Value";
327
+ return val1 === val2;
328
+ }
329
+
330
+ TEST_OUTPUT = myFunction(); // true
331
+ `,
332
+ {
333
+ target: "node",
334
+ rgf: true,
335
+ stringEncoding: true,
336
+ }
337
+ );
338
+
339
+ // Ensure RGF applied
340
+ expect(output).toContain("new Function");
341
+
342
+ var TEST_OUTPUT;
343
+ eval(output);
344
+
345
+ expect(TEST_OUTPUT).toStrictEqual(true);
346
+ });
291
347
  });
292
348
 
293
349
  describe("RGF with the 'all' mode", () => {
@@ -182,3 +182,36 @@ it("should not encode constructor key", async () => {
182
182
 
183
183
  expect(TEST_VAR).toStrictEqual(100);
184
184
  });
185
+
186
+ // https://github.com/MichaelXF/js-confuser/issues/82
187
+ it("should work inside the Class Constructor function", async () => {
188
+ var code = `
189
+ class MyClass1 {}
190
+ class MyClass2 extends MyClass1 {
191
+ constructor(){
192
+ super();
193
+ this["myString1"] = true;
194
+ this["myString2"] = true;
195
+ this["myString3"] = true;
196
+ }
197
+ }
198
+
199
+ var instance = new MyClass2();
200
+
201
+ TEST_OUTPUT = instance.myString1 === true; // true
202
+ `;
203
+
204
+ var output = await JsConfuser(code, {
205
+ target: "node",
206
+ stringConcealing: true,
207
+ });
208
+
209
+ // Ensure the strings got encrypted properly
210
+ expect(output).not.toContain("myString");
211
+
212
+ // Ensure the code works
213
+ var TEST_OUTPUT = false;
214
+ eval(output);
215
+
216
+ expect(TEST_OUTPUT).toStrictEqual(true);
217
+ });
@@ -1,4 +1,4 @@
1
- import { isEquivalent } from "../../src/util/compare";
1
+ import { isEquivalent, isValidIdentifier } from "../../src/util/compare";
2
2
  import { Identifier } from "../../src/util/gen";
3
3
 
4
4
  it("should compare nodes correctly", () => {
@@ -10,3 +10,25 @@ it("should compare nodes correctly", () => {
10
10
  isEquivalent(Identifier("name"), Identifier("different_name"))
11
11
  ).toStrictEqual(false);
12
12
  });
13
+
14
+ describe("isValidIdentifier", () => {
15
+ test("Variant #1: Basic examples", () => {
16
+ // true examples
17
+ expect(isValidIdentifier("myClass")).toStrictEqual(true);
18
+ expect(isValidIdentifier("MyClass")).toStrictEqual(true);
19
+ expect(isValidIdentifier("$myObject")).toStrictEqual(true);
20
+ expect(isValidIdentifier("_myObject")).toStrictEqual(true);
21
+ expect(isValidIdentifier("myObject2")).toStrictEqual(true);
22
+ expect(isValidIdentifier("_0")).toStrictEqual(true);
23
+
24
+ // false examples
25
+ expect(isValidIdentifier("0")).toStrictEqual(false);
26
+ expect(isValidIdentifier("0myInvalidVar")).toStrictEqual(false);
27
+ expect(isValidIdentifier("^")).toStrictEqual(false);
28
+ expect(isValidIdentifier("%")).toStrictEqual(false);
29
+ expect(isValidIdentifier("invalid*Var")).toStrictEqual(false);
30
+ expect(isValidIdentifier("invalid!")).toStrictEqual(false);
31
+ expect(isValidIdentifier("my invalid var")).toStrictEqual(false);
32
+ expect(isValidIdentifier("my-invalid-var")).toStrictEqual(false);
33
+ });
34
+ });