expose-kit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -7
- package/dist/index.js +431 -33
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ With this alone:
|
|
|
105
105
|
### 3. Apply transforms step by step
|
|
106
106
|
|
|
107
107
|
After `safe-scope`, combine common techniques like:
|
|
108
|
-
- `expand-array` and more
|
|
108
|
+
- `expand-array`, `expand-object` and more
|
|
109
109
|
- legacy obfuscator-specific commands
|
|
110
110
|
|
|
111
111
|
After **each step**, run `parsable` again.
|
|
@@ -175,7 +175,7 @@ Args:
|
|
|
175
175
|
|
|
176
176
|
---
|
|
177
177
|
|
|
178
|
-
### `expose expand-array`
|
|
178
|
+
### `expose expand-array`
|
|
179
179
|
|
|
180
180
|
Expand array index access for primitive values.
|
|
181
181
|
```js
|
|
@@ -196,13 +196,60 @@ Args:
|
|
|
196
196
|
Target array variable name
|
|
197
197
|
- `--o, --output <file>`
|
|
198
198
|
Output file path
|
|
199
|
-
- No extension → `file.expand-array.js`
|
|
200
|
-
- With extension → `file.expand-array.<ext>`
|
|
201
199
|
|
|
202
|
-
Notes:
|
|
203
|
-
- Each replacement is validated by reparsing; invalid replacements (e.g. `++a[0]` or `a[0]++`) are skipped.-
|
|
200
|
+
Notes:
|
|
201
|
+
- Each replacement is validated by reparsing; invalid replacements (e.g. `++a[0]` or `a[0]++`) are skipped.-
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### `expose expand-object`
|
|
206
|
+
|
|
207
|
+
Expand object property access for primitive values.
|
|
208
|
+
```js
|
|
209
|
+
const obj = { a: 1, b: 2 };
|
|
210
|
+
// before
|
|
211
|
+
console.log(obj.a, obj["b"]);
|
|
212
|
+
// after
|
|
213
|
+
console.log(1, 2);
|
|
214
|
+
```
|
|
215
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/expand-object/mocks).
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
expose expand-object path/to/file.js --target objectName --output path/to/file.expand-object.js
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
- `--target <name>`
|
|
223
|
+
Target object variable name
|
|
224
|
+
- `--o, --output <file>`
|
|
225
|
+
Output file path
|
|
226
|
+
|
|
227
|
+
Notes:
|
|
228
|
+
- Each replacement is validated by reparsing; invalid replacements are skipped.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### `expose remove-unused`
|
|
233
|
+
|
|
234
|
+
Remove unused variabless.
|
|
235
|
+
```js
|
|
236
|
+
// before
|
|
237
|
+
var a = 0, b = 1;
|
|
238
|
+
console.log(a);
|
|
239
|
+
// after
|
|
240
|
+
var a = 0;
|
|
241
|
+
console.log(a);
|
|
242
|
+
```
|
|
243
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/remove-unused/mocks).
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
expose remove-unused path/to/file.js --output path/to/file.remove-unused.js
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
- `--o, --output <file>`
|
|
251
|
+
Output file path
|
|
204
252
|
|
|
205
|
-
---
|
|
206
253
|
|
|
207
254
|
## Community & Support
|
|
208
255
|
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { dirname as
|
|
5
|
+
import { dirname as dirname6, join as join6 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import chalk4 from "chalk";
|
|
8
8
|
|
|
@@ -364,15 +364,27 @@ var findTargetArray = (ast, targetName) => {
|
|
|
364
364
|
if (!found) return null;
|
|
365
365
|
let hasRiskOfSideEffects = false;
|
|
366
366
|
patchDefault(traverse2)(ast, {
|
|
367
|
-
|
|
367
|
+
MemberExpression(path) {
|
|
368
368
|
if (hasRiskOfSideEffects) return;
|
|
369
|
-
if (!t.isIdentifier(path.node, { name: targetName })) return;
|
|
369
|
+
if (!t.isIdentifier(path.node.object, { name: targetName })) return;
|
|
370
370
|
const parent = path.parentPath;
|
|
371
371
|
if (!parent) return;
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
372
|
+
if (isAssignmentTarget(path)) {
|
|
373
|
+
hasRiskOfSideEffects = true;
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
AssignmentExpression(path) {
|
|
377
|
+
if (hasRiskOfSideEffects) return;
|
|
378
|
+
const left = path.get("left");
|
|
379
|
+
if (left.isIdentifier({ name: targetName })) {
|
|
380
|
+
hasRiskOfSideEffects = true;
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
UpdateExpression(path) {
|
|
384
|
+
if (hasRiskOfSideEffects) return;
|
|
385
|
+
if (t.isIdentifier(path.node.argument, { name: targetName })) {
|
|
386
|
+
hasRiskOfSideEffects = true;
|
|
387
|
+
}
|
|
376
388
|
}
|
|
377
389
|
});
|
|
378
390
|
const result = found;
|
|
@@ -386,7 +398,9 @@ var expandArrayAccess = async (code, filename, targetName) => {
|
|
|
386
398
|
throw new Error(`Target array '${targetName}' is not a primitive array`);
|
|
387
399
|
}
|
|
388
400
|
if (targetArray.hasRiskOfSideEffects) {
|
|
389
|
-
const continueAnswer = await createPrompt(
|
|
401
|
+
const continueAnswer = await createPrompt(
|
|
402
|
+
"The target array has risk of side effects, do you want to continue? (y/n)"
|
|
403
|
+
);
|
|
390
404
|
if (continueAnswer !== "y") {
|
|
391
405
|
throw new Error("User cancelled");
|
|
392
406
|
}
|
|
@@ -491,7 +505,7 @@ var expand_array_default = createCommand((program2) => {
|
|
|
491
505
|
);
|
|
492
506
|
});
|
|
493
507
|
|
|
494
|
-
// commands/
|
|
508
|
+
// commands/expand-object/index.ts
|
|
495
509
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
496
510
|
import { basename as basename3, dirname as dirname3, extname as extname3, join as join3 } from "path";
|
|
497
511
|
import { parse as parse4 } from "@babel/parser";
|
|
@@ -502,10 +516,281 @@ import loading4 from "loading-cli";
|
|
|
502
516
|
var createDefaultOutputPath3 = (inputPath) => {
|
|
503
517
|
const ext = extname3(inputPath);
|
|
504
518
|
if (!ext) {
|
|
505
|
-
return `${inputPath}.
|
|
519
|
+
return `${inputPath}.expand-object.js`;
|
|
506
520
|
}
|
|
507
521
|
const base = basename3(inputPath, ext);
|
|
508
|
-
return join3(dirname3(inputPath), `${base}.
|
|
522
|
+
return join3(dirname3(inputPath), `${base}.expand-object${ext}`);
|
|
523
|
+
};
|
|
524
|
+
var getPropertyKeyFromObjectProperty = (property) => {
|
|
525
|
+
if (t2.isIdentifier(property.key)) {
|
|
526
|
+
return property.key.name;
|
|
527
|
+
}
|
|
528
|
+
if (t2.isStringLiteral(property.key)) {
|
|
529
|
+
return property.key.value;
|
|
530
|
+
}
|
|
531
|
+
if (t2.isNumericLiteral(property.key)) {
|
|
532
|
+
return String(property.key.value);
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
};
|
|
536
|
+
var getPropertyKeyFromMemberExpression = (node) => {
|
|
537
|
+
if (!node.computed && t2.isIdentifier(node.property)) {
|
|
538
|
+
return node.property.name;
|
|
539
|
+
}
|
|
540
|
+
if (!node.computed || !t2.isExpression(node.property)) {
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
if (t2.isStringLiteral(node.property)) {
|
|
544
|
+
return node.property.value;
|
|
545
|
+
}
|
|
546
|
+
if (t2.isNumericLiteral(node.property)) {
|
|
547
|
+
return String(node.property.value);
|
|
548
|
+
}
|
|
549
|
+
if (t2.isTemplateLiteral(node.property) && node.property.expressions.length === 0) {
|
|
550
|
+
return node.property.quasis[0]?.value.cooked ?? null;
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
};
|
|
554
|
+
var isAssignmentTarget2 = (path) => {
|
|
555
|
+
const parent = path.parentPath;
|
|
556
|
+
if (!parent) return false;
|
|
557
|
+
if (parent.isUpdateExpression()) return true;
|
|
558
|
+
if (parent.isAssignmentExpression() && parent.get("left") === path) {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
if (parent.isForInStatement() && parent.get("left") === path) {
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
if (parent.isForOfStatement() && parent.get("left") === path) {
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
return false;
|
|
568
|
+
};
|
|
569
|
+
var collectMutatedProperties = (ast, targetName) => {
|
|
570
|
+
const mutatedProperties = /* @__PURE__ */ new Set();
|
|
571
|
+
let hasUnknownMutations = false;
|
|
572
|
+
patchDefault(traverse3)(ast, {
|
|
573
|
+
MemberExpression(path) {
|
|
574
|
+
if (!t2.isIdentifier(path.node.object, { name: targetName })) return;
|
|
575
|
+
const parent = path.parentPath;
|
|
576
|
+
if (!parent) return;
|
|
577
|
+
const isMutationTarget = parent.isUpdateExpression() || parent.isAssignmentExpression() && parent.get("left") === path || parent.isForInStatement() && parent.get("left") === path || parent.isForOfStatement() && parent.get("left") === path;
|
|
578
|
+
if (!isMutationTarget) return;
|
|
579
|
+
const propertyKey = getPropertyKeyFromMemberExpression(path.node);
|
|
580
|
+
if (!propertyKey) {
|
|
581
|
+
hasUnknownMutations = true;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
mutatedProperties.add(propertyKey);
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
return { mutatedProperties, hasUnknownMutations };
|
|
588
|
+
};
|
|
589
|
+
var getPropertyMap = (objectNode) => {
|
|
590
|
+
const map = /* @__PURE__ */ new Map();
|
|
591
|
+
for (const property of objectNode.properties) {
|
|
592
|
+
if (!t2.isObjectProperty(property)) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
if (property.computed) {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
if (!t2.isExpression(property.value)) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
const key = getPropertyKeyFromObjectProperty(property);
|
|
602
|
+
if (!key) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
map.set(key, property.value);
|
|
606
|
+
}
|
|
607
|
+
return map;
|
|
608
|
+
};
|
|
609
|
+
var findTargetObject = (ast, targetName) => {
|
|
610
|
+
let found = null;
|
|
611
|
+
patchDefault(traverse3)(ast, {
|
|
612
|
+
VariableDeclarator(path) {
|
|
613
|
+
if (found) return;
|
|
614
|
+
if (!t2.isIdentifier(path.node.id, { name: targetName })) return;
|
|
615
|
+
if (!t2.isObjectExpression(path.node.init)) return;
|
|
616
|
+
const propertyMap = getPropertyMap(path.node.init);
|
|
617
|
+
if (!propertyMap) return;
|
|
618
|
+
found = {
|
|
619
|
+
binding: path.scope.getBinding(targetName) ?? null,
|
|
620
|
+
objectNode: path.node.init,
|
|
621
|
+
propertyMap
|
|
622
|
+
};
|
|
623
|
+
},
|
|
624
|
+
AssignmentExpression(path) {
|
|
625
|
+
if (found) return;
|
|
626
|
+
if (!t2.isIdentifier(path.node.left, { name: targetName })) return;
|
|
627
|
+
if (!t2.isObjectExpression(path.node.right)) return;
|
|
628
|
+
const propertyMap = getPropertyMap(path.node.right);
|
|
629
|
+
if (!propertyMap) return;
|
|
630
|
+
found = {
|
|
631
|
+
binding: path.scope.getBinding(targetName) ?? null,
|
|
632
|
+
objectNode: path.node.right,
|
|
633
|
+
propertyMap
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
if (!found) return null;
|
|
638
|
+
let hasRiskOfSideEffects = false;
|
|
639
|
+
patchDefault(traverse3)(ast, {
|
|
640
|
+
MemberExpression(path) {
|
|
641
|
+
if (hasRiskOfSideEffects) return;
|
|
642
|
+
if (!t2.isIdentifier(path.node.object, { name: targetName })) return;
|
|
643
|
+
const parent = path.parentPath;
|
|
644
|
+
if (!parent) return;
|
|
645
|
+
if (isAssignmentTarget2(path)) {
|
|
646
|
+
hasRiskOfSideEffects = true;
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
AssignmentExpression(path) {
|
|
650
|
+
if (hasRiskOfSideEffects) return;
|
|
651
|
+
const left = path.get("left");
|
|
652
|
+
if (left.isIdentifier({ name: targetName })) {
|
|
653
|
+
hasRiskOfSideEffects = true;
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
UpdateExpression(path) {
|
|
657
|
+
if (hasRiskOfSideEffects) return;
|
|
658
|
+
if (t2.isIdentifier(path.node.argument, { name: targetName })) {
|
|
659
|
+
hasRiskOfSideEffects = true;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
const result = found;
|
|
664
|
+
result.hasRiskOfSideEffects = hasRiskOfSideEffects;
|
|
665
|
+
return result;
|
|
666
|
+
};
|
|
667
|
+
var expandObjectAccess = async (code, filename, targetName) => {
|
|
668
|
+
const ast = parse4(code, createParseOptions(filename));
|
|
669
|
+
const targetObject = findTargetObject(ast, targetName);
|
|
670
|
+
if (!targetObject) {
|
|
671
|
+
throw new Error(`Target object '${targetName}' is not a primitive object`);
|
|
672
|
+
}
|
|
673
|
+
if (targetObject.hasRiskOfSideEffects) {
|
|
674
|
+
const continueAnswer = await createPrompt(
|
|
675
|
+
"The target object has risk of side effects, do you want to continue? (y/n)"
|
|
676
|
+
);
|
|
677
|
+
if (continueAnswer !== "y") {
|
|
678
|
+
throw new Error("User cancelled");
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const candidates = [];
|
|
682
|
+
const mutatedInfo = collectMutatedProperties(ast, targetName);
|
|
683
|
+
if (mutatedInfo.hasUnknownMutations) {
|
|
684
|
+
return {
|
|
685
|
+
code: patchDefault(generate3)(ast).code,
|
|
686
|
+
replacedCount: 0
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
patchDefault(traverse3)(ast, {
|
|
690
|
+
MemberExpression(path) {
|
|
691
|
+
if (isAssignmentTarget2(path)) return;
|
|
692
|
+
if (!t2.isIdentifier(path.node.object, { name: targetName })) return;
|
|
693
|
+
if (targetObject.binding && path.scope.getBinding(targetName) !== targetObject.binding) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const propertyKey = getPropertyKeyFromMemberExpression(path.node);
|
|
697
|
+
if (!propertyKey) return;
|
|
698
|
+
if (mutatedInfo.mutatedProperties.has(propertyKey)) return;
|
|
699
|
+
const replacement = targetObject.propertyMap.get(propertyKey);
|
|
700
|
+
if (!replacement) return;
|
|
701
|
+
candidates.push({
|
|
702
|
+
path,
|
|
703
|
+
replacement: t2.cloneNode(replacement, true)
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
let replacedCount = 0;
|
|
708
|
+
for (const candidate of candidates) {
|
|
709
|
+
const original = t2.cloneNode(candidate.path.node, true);
|
|
710
|
+
candidate.path.replaceWith(t2.cloneNode(candidate.replacement, true));
|
|
711
|
+
const nextCode = patchDefault(generate3)(ast).code;
|
|
712
|
+
try {
|
|
713
|
+
parse4(nextCode, createParseOptions(filename));
|
|
714
|
+
replacedCount += 1;
|
|
715
|
+
} catch {
|
|
716
|
+
candidate.path.replaceWith(original);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return {
|
|
720
|
+
code: patchDefault(generate3)(ast).code,
|
|
721
|
+
replacedCount
|
|
722
|
+
};
|
|
723
|
+
};
|
|
724
|
+
var expand_object_default = createCommand((program2) => {
|
|
725
|
+
program2.command("expand-object").description("Expand object property access for primitive values").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--target <name>", "Target object variable name").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
726
|
+
async (fileArgument, options) => {
|
|
727
|
+
await timeout(
|
|
728
|
+
async ({ finish }) => {
|
|
729
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
730
|
+
if (!filename) {
|
|
731
|
+
showError("No file provided");
|
|
732
|
+
return finish();
|
|
733
|
+
}
|
|
734
|
+
const targetName = options.target ?? await createPrompt("Enter the target variable name:");
|
|
735
|
+
if (!targetName) {
|
|
736
|
+
showError("No target variable provided");
|
|
737
|
+
return finish();
|
|
738
|
+
}
|
|
739
|
+
try {
|
|
740
|
+
const fileContent = readFileSync4(filename, "utf8");
|
|
741
|
+
const defaultOutputPath = createDefaultOutputPath3(filename);
|
|
742
|
+
let outputPath = options.output;
|
|
743
|
+
if (!outputPath) {
|
|
744
|
+
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
745
|
+
outputPath = promptPath || defaultOutputPath;
|
|
746
|
+
}
|
|
747
|
+
const loader = loading4("Expanding object access...").start();
|
|
748
|
+
try {
|
|
749
|
+
const { code: output, replacedCount } = await expandObjectAccess(
|
|
750
|
+
fileContent,
|
|
751
|
+
filename,
|
|
752
|
+
targetName
|
|
753
|
+
);
|
|
754
|
+
writeFileSync3(outputPath, output, "utf8");
|
|
755
|
+
loader.succeed(
|
|
756
|
+
`Saved expand-object file to: ${outputPath} (${diff(fileContent, output).length} lines changed, ${replacedCount} replacements)`
|
|
757
|
+
);
|
|
758
|
+
return finish();
|
|
759
|
+
} catch (error) {
|
|
760
|
+
loader.fail("Failed to apply expand-object transform");
|
|
761
|
+
showError(
|
|
762
|
+
`Error transforming file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
763
|
+
);
|
|
764
|
+
return finish();
|
|
765
|
+
}
|
|
766
|
+
} catch (error) {
|
|
767
|
+
showError(
|
|
768
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
769
|
+
);
|
|
770
|
+
return finish();
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
options.unlimited ? null : 120 * 1e3
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
);
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
// commands/pre-evaluate/index.ts
|
|
780
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
781
|
+
import { basename as basename4, dirname as dirname4, extname as extname4, join as join4 } from "path";
|
|
782
|
+
import { parse as parse5 } from "@babel/parser";
|
|
783
|
+
import traverse4 from "@babel/traverse";
|
|
784
|
+
import generate4 from "@babel/generator";
|
|
785
|
+
import * as t3 from "@babel/types";
|
|
786
|
+
import loading5 from "loading-cli";
|
|
787
|
+
var createDefaultOutputPath4 = (inputPath) => {
|
|
788
|
+
const ext = extname4(inputPath);
|
|
789
|
+
if (!ext) {
|
|
790
|
+
return `${inputPath}.pre-evaluate.js`;
|
|
791
|
+
}
|
|
792
|
+
const base = basename4(inputPath, ext);
|
|
793
|
+
return join4(dirname4(inputPath), `${base}.pre-evaluate${ext}`);
|
|
509
794
|
};
|
|
510
795
|
var isSupportedNumberOperator = (operator) => {
|
|
511
796
|
return operator === "-" || operator === "*" || operator === "/" || operator === "%" || operator === "**" || operator === "<<" || operator === ">>" || operator === ">>>" || operator === "|" || operator === "&" || operator === "^";
|
|
@@ -639,13 +924,13 @@ var shouldSkipReferencedIdentifier = (path) => {
|
|
|
639
924
|
return false;
|
|
640
925
|
};
|
|
641
926
|
var preEvaluate = (code, filename) => {
|
|
642
|
-
const ast =
|
|
927
|
+
const ast = parse5(code, createParseOptions(filename));
|
|
643
928
|
const state = {
|
|
644
929
|
bindingValues: /* @__PURE__ */ new Map(),
|
|
645
930
|
bindingStack: /* @__PURE__ */ new Set()
|
|
646
931
|
};
|
|
647
932
|
let replacedCount = 0;
|
|
648
|
-
patchDefault(
|
|
933
|
+
patchDefault(traverse4)(ast, {
|
|
649
934
|
ReferencedIdentifier(path) {
|
|
650
935
|
if (shouldSkipReferencedIdentifier(path)) {
|
|
651
936
|
return;
|
|
@@ -653,9 +938,9 @@ var preEvaluate = (code, filename) => {
|
|
|
653
938
|
const value = evaluateExpression(path, state);
|
|
654
939
|
if (value === null) return;
|
|
655
940
|
if (typeof value === "number") {
|
|
656
|
-
path.replaceWith(
|
|
941
|
+
path.replaceWith(t3.numericLiteral(value));
|
|
657
942
|
} else {
|
|
658
|
-
path.replaceWith(
|
|
943
|
+
path.replaceWith(t3.stringLiteral(value));
|
|
659
944
|
}
|
|
660
945
|
replacedCount += 1;
|
|
661
946
|
},
|
|
@@ -664,9 +949,9 @@ var preEvaluate = (code, filename) => {
|
|
|
664
949
|
const value = evaluateExpression(path, state);
|
|
665
950
|
if (value === null) return;
|
|
666
951
|
if (typeof value === "number") {
|
|
667
|
-
path.replaceWith(
|
|
952
|
+
path.replaceWith(t3.numericLiteral(value));
|
|
668
953
|
} else {
|
|
669
|
-
path.replaceWith(
|
|
954
|
+
path.replaceWith(t3.stringLiteral(value));
|
|
670
955
|
}
|
|
671
956
|
replacedCount += 1;
|
|
672
957
|
}
|
|
@@ -676,9 +961,9 @@ var preEvaluate = (code, filename) => {
|
|
|
676
961
|
const value = evaluateExpression(path, state);
|
|
677
962
|
if (value === null) return;
|
|
678
963
|
if (typeof value === "number") {
|
|
679
|
-
path.replaceWith(
|
|
964
|
+
path.replaceWith(t3.numericLiteral(value));
|
|
680
965
|
} else {
|
|
681
|
-
path.replaceWith(
|
|
966
|
+
path.replaceWith(t3.stringLiteral(value));
|
|
682
967
|
}
|
|
683
968
|
replacedCount += 1;
|
|
684
969
|
}
|
|
@@ -688,16 +973,16 @@ var preEvaluate = (code, filename) => {
|
|
|
688
973
|
const value = evaluateExpression(path, state);
|
|
689
974
|
if (value === null) return;
|
|
690
975
|
if (typeof value === "number") {
|
|
691
|
-
path.replaceWith(
|
|
976
|
+
path.replaceWith(t3.numericLiteral(value));
|
|
692
977
|
} else {
|
|
693
|
-
path.replaceWith(
|
|
978
|
+
path.replaceWith(t3.stringLiteral(value));
|
|
694
979
|
}
|
|
695
980
|
replacedCount += 1;
|
|
696
981
|
}
|
|
697
982
|
}
|
|
698
983
|
});
|
|
699
984
|
return {
|
|
700
|
-
code: patchDefault(
|
|
985
|
+
code: patchDefault(generate4)(ast).code,
|
|
701
986
|
replacedCount
|
|
702
987
|
};
|
|
703
988
|
};
|
|
@@ -712,20 +997,20 @@ var pre_evaluate_default = createCommand((program2) => {
|
|
|
712
997
|
return finish();
|
|
713
998
|
}
|
|
714
999
|
try {
|
|
715
|
-
const fileContent =
|
|
716
|
-
const defaultOutputPath =
|
|
1000
|
+
const fileContent = readFileSync5(filename, "utf8");
|
|
1001
|
+
const defaultOutputPath = createDefaultOutputPath4(filename);
|
|
717
1002
|
let outputPath = options.output;
|
|
718
1003
|
if (!outputPath) {
|
|
719
1004
|
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
720
1005
|
outputPath = promptPath || defaultOutputPath;
|
|
721
1006
|
}
|
|
722
|
-
const loader =
|
|
1007
|
+
const loader = loading5("Pre-evaluating constants...").start();
|
|
723
1008
|
try {
|
|
724
1009
|
const { code: output, replacedCount } = preEvaluate(
|
|
725
1010
|
fileContent,
|
|
726
1011
|
filename
|
|
727
1012
|
);
|
|
728
|
-
|
|
1013
|
+
writeFileSync4(outputPath, output, "utf8");
|
|
729
1014
|
loader.succeed(
|
|
730
1015
|
`Saved pre-evaluate file to: ${outputPath} (${diff(fileContent, output).length} lines changed, ${replacedCount} replacements)`
|
|
731
1016
|
);
|
|
@@ -750,6 +1035,112 @@ var pre_evaluate_default = createCommand((program2) => {
|
|
|
750
1035
|
);
|
|
751
1036
|
});
|
|
752
1037
|
|
|
1038
|
+
// commands/remove-unused/index.ts
|
|
1039
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1040
|
+
import { basename as basename5, dirname as dirname5, extname as extname5, join as join5 } from "path";
|
|
1041
|
+
import { parse as parse6 } from "@babel/parser";
|
|
1042
|
+
import traverse5 from "@babel/traverse";
|
|
1043
|
+
import generate5 from "@babel/generator";
|
|
1044
|
+
import * as t4 from "@babel/types";
|
|
1045
|
+
import loading6 from "loading-cli";
|
|
1046
|
+
var createDefaultOutputPath5 = (inputPath) => {
|
|
1047
|
+
const ext = extname5(inputPath);
|
|
1048
|
+
if (!ext) {
|
|
1049
|
+
return `${inputPath}.remove-unused.js`;
|
|
1050
|
+
}
|
|
1051
|
+
const base = basename5(inputPath, ext);
|
|
1052
|
+
return join5(dirname5(inputPath), `${base}.remove-unused${ext}`);
|
|
1053
|
+
};
|
|
1054
|
+
var removeUnusedVariables = (code, filename) => {
|
|
1055
|
+
const ast = parse6(code, createParseOptions(filename));
|
|
1056
|
+
let changed = false;
|
|
1057
|
+
patchDefault(traverse5)(ast, {
|
|
1058
|
+
Scope(path) {
|
|
1059
|
+
for (const binding of Object.values(path.scope.bindings)) {
|
|
1060
|
+
if (!binding.referenced && binding.constantViolations.length === 0 && binding.path.key !== "handler" && !binding.path.isFunctionExpression()) {
|
|
1061
|
+
if (t4.isProgram(binding.scope.block) && (binding.kind === "var" || binding.kind === "hoisted")) {
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
const targets = binding.path.parentKey === "params" ? [...binding.referencePaths, ...binding.constantViolations] : [
|
|
1065
|
+
binding.path,
|
|
1066
|
+
...binding.referencePaths,
|
|
1067
|
+
...binding.constantViolations
|
|
1068
|
+
];
|
|
1069
|
+
for (const targetPath of targets) {
|
|
1070
|
+
if (targetPath.isVariableDeclarator() && (t4.isArrayPattern(targetPath.node.id) && targetPath.node.id.elements.length > 1 || t4.isObjectPattern(targetPath.node.id) && targetPath.node.id.properties.length > 1)) {
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
if (targetPath.key === "consequent" || targetPath.key === "alternate" || targetPath.key === "body") {
|
|
1074
|
+
targetPath.replaceWith(t4.blockStatement([]));
|
|
1075
|
+
} else {
|
|
1076
|
+
const parentPath = targetPath.parentPath;
|
|
1077
|
+
if (parentPath?.isVariableDeclaration() && parentPath.node.declarations.length === 1) {
|
|
1078
|
+
parentPath.remove();
|
|
1079
|
+
} else {
|
|
1080
|
+
targetPath.remove();
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
changed = true;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
return {
|
|
1090
|
+
code: patchDefault(generate5)(ast).code,
|
|
1091
|
+
changed
|
|
1092
|
+
};
|
|
1093
|
+
};
|
|
1094
|
+
var remove_unused_default = createCommand((program2) => {
|
|
1095
|
+
program2.command("remove-unused").description("Remove unused variables and declarations").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1096
|
+
async (fileArgument, options) => {
|
|
1097
|
+
await timeout(
|
|
1098
|
+
async ({ finish }) => {
|
|
1099
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
1100
|
+
if (!filename) {
|
|
1101
|
+
showError("No file provided");
|
|
1102
|
+
return finish();
|
|
1103
|
+
}
|
|
1104
|
+
try {
|
|
1105
|
+
const fileContent = readFileSync6(filename, "utf8");
|
|
1106
|
+
const defaultOutputPath = createDefaultOutputPath5(filename);
|
|
1107
|
+
let outputPath = options.output;
|
|
1108
|
+
if (!outputPath) {
|
|
1109
|
+
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
1110
|
+
outputPath = promptPath || defaultOutputPath;
|
|
1111
|
+
}
|
|
1112
|
+
const loader = loading6("Removing unused variables...").start();
|
|
1113
|
+
try {
|
|
1114
|
+
const { code: output, changed } = removeUnusedVariables(
|
|
1115
|
+
fileContent,
|
|
1116
|
+
filename
|
|
1117
|
+
);
|
|
1118
|
+
writeFileSync5(outputPath, output, "utf8");
|
|
1119
|
+
const diffLines = diff(fileContent, output).length;
|
|
1120
|
+
loader.succeed(
|
|
1121
|
+
`Saved remove-unused file to: ${outputPath} (${diffLines} lines changed${changed ? ", removed unused declarations" : ", no changes"})`
|
|
1122
|
+
);
|
|
1123
|
+
return finish();
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
loader.fail("Failed to apply remove-unused transform");
|
|
1126
|
+
showError(
|
|
1127
|
+
`Error transforming file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1128
|
+
);
|
|
1129
|
+
return finish();
|
|
1130
|
+
}
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
showError(
|
|
1133
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1134
|
+
);
|
|
1135
|
+
return finish();
|
|
1136
|
+
}
|
|
1137
|
+
},
|
|
1138
|
+
options.unlimited ? null : 120 * 1e3
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
});
|
|
1143
|
+
|
|
753
1144
|
// utils/cli/showCredit.ts
|
|
754
1145
|
import chalk3 from "chalk";
|
|
755
1146
|
var beautify = (strings, ...values) => {
|
|
@@ -774,10 +1165,10 @@ var calmGradienrain = (text) => {
|
|
|
774
1165
|
const endHue = 300;
|
|
775
1166
|
const saturation = 0.45;
|
|
776
1167
|
const value = 0.8;
|
|
777
|
-
const ease = (
|
|
1168
|
+
const ease = (t5) => t5 * t5 * (3 - 2 * t5);
|
|
778
1169
|
return text.split("").map((char, i) => {
|
|
779
|
-
const
|
|
780
|
-
const hue = startHue + (endHue - startHue) *
|
|
1170
|
+
const t5 = ease(i / Math.max(text.length - 1, 1));
|
|
1171
|
+
const hue = startHue + (endHue - startHue) * t5;
|
|
781
1172
|
const c = value * saturation;
|
|
782
1173
|
const h = hue / 60;
|
|
783
1174
|
const x = c * (1 - Math.abs(h % 2 - 1));
|
|
@@ -801,10 +1192,10 @@ ${calmGradienrain(`Expose Kit v${VERSION}`)}
|
|
|
801
1192
|
`;
|
|
802
1193
|
|
|
803
1194
|
// index.ts
|
|
804
|
-
import { readFileSync as
|
|
1195
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
805
1196
|
var __filename = fileURLToPath(import.meta.url);
|
|
806
|
-
var __dirname =
|
|
807
|
-
var pkg = JSON.parse(
|
|
1197
|
+
var __dirname = dirname6(__filename);
|
|
1198
|
+
var pkg = JSON.parse(readFileSync7(join6(__dirname, "package.json"), "utf8"));
|
|
808
1199
|
console.log(showCredit(pkg.version));
|
|
809
1200
|
console.log();
|
|
810
1201
|
var program = new Command();
|
|
@@ -813,7 +1204,14 @@ program.name("expose").description("CLI for Deobfuscating").version(
|
|
|
813
1204
|
"-v, --version",
|
|
814
1205
|
"display version number"
|
|
815
1206
|
);
|
|
816
|
-
var commands = [
|
|
1207
|
+
var commands = [
|
|
1208
|
+
parsable_default,
|
|
1209
|
+
safe_scope_default,
|
|
1210
|
+
expand_array_default,
|
|
1211
|
+
expand_object_default,
|
|
1212
|
+
pre_evaluate_default,
|
|
1213
|
+
remove_unused_default
|
|
1214
|
+
];
|
|
817
1215
|
for (const command of commands) {
|
|
818
1216
|
command(program);
|
|
819
1217
|
}
|
package/dist/package.json
CHANGED