expose-kit 0.5.0 → 0.7.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 +69 -13
- package/dist/index.js +324 -46
- 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`, `expand-object` 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
|
|
@@ -197,35 +197,91 @@ Args:
|
|
|
197
197
|
- `--o, --output <file>`
|
|
198
198
|
Output file path
|
|
199
199
|
|
|
200
|
+
Notes:
|
|
201
|
+
- Each replacement is validated by reparsing; unsafe replacements are skipped.
|
|
202
|
+
(This array is intended to be immutable, so caution is required)
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### `expose expand-object`
|
|
207
|
+
|
|
208
|
+
Expand object property access for primitive values.
|
|
209
|
+
```js
|
|
210
|
+
const obj = { a: 1, b: 2 };
|
|
211
|
+
// before
|
|
212
|
+
console.log(obj.a, obj["b"]);
|
|
213
|
+
// after
|
|
214
|
+
console.log(1, 2);
|
|
215
|
+
```
|
|
216
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/expand-object/mocks).
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
expose expand-object path/to/file.js --target objectName --output path/to/file.expand-object.js
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
- `--target <name>`
|
|
224
|
+
Target object variable name
|
|
225
|
+
- `--o, --output <file>`
|
|
226
|
+
Output file path
|
|
227
|
+
|
|
200
228
|
Notes:
|
|
201
|
-
- Each replacement is validated by reparsing;
|
|
229
|
+
- Each replacement is validated by reparsing; unsafe replacements are skipped.
|
|
230
|
+
(This object is intended to be immutable, so caution is required)
|
|
202
231
|
|
|
203
232
|
---
|
|
204
233
|
|
|
205
|
-
### `expose
|
|
234
|
+
### `expose object-packer`
|
|
235
|
+
|
|
236
|
+
Pack consecutive object property assignments into literals.
|
|
237
|
+
```js
|
|
238
|
+
const obj = {};
|
|
239
|
+
// before
|
|
240
|
+
obj.a = 0;
|
|
241
|
+
obj["b"] = 1;
|
|
242
|
+
// after
|
|
243
|
+
const obj = { a: 0, b: 1 };
|
|
244
|
+
```
|
|
245
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/object-packer/mocks).
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
expose object-packer path/to/file.js --output path/to/file.object-packer.js
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
- `--o, --output <file>`
|
|
253
|
+
Output file path
|
|
254
|
+
|
|
255
|
+
Notes:
|
|
256
|
+
- Packs only consecutive assignments following an empty object literal.
|
|
257
|
+
- Stops when a property value references the object itself.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### `expose remove-updater`
|
|
206
262
|
|
|
207
|
-
|
|
263
|
+
Replace safe update expressions with += or -=.
|
|
208
264
|
```js
|
|
209
|
-
const obj = { a: 1, b: 2 };
|
|
210
265
|
// before
|
|
211
|
-
|
|
266
|
+
a++;
|
|
267
|
+
--b;
|
|
212
268
|
// after
|
|
213
|
-
|
|
269
|
+
a += 1;
|
|
270
|
+
b -= 1;
|
|
214
271
|
```
|
|
215
|
-
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/
|
|
272
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/remove-updater/mocks).
|
|
216
273
|
|
|
217
274
|
```bash
|
|
218
|
-
expose
|
|
275
|
+
expose remove-updater path/to/file.js --output path/to/file.remove-updater.js
|
|
219
276
|
```
|
|
220
277
|
|
|
221
278
|
Args:
|
|
222
|
-
- `--target <name>`
|
|
223
|
-
Target object variable name
|
|
224
279
|
- `--o, --output <file>`
|
|
225
280
|
Output file path
|
|
226
281
|
|
|
227
282
|
Notes:
|
|
228
|
-
-
|
|
283
|
+
- Only replaces update expressions whose value is not used.
|
|
284
|
+
- Safe for expression statements and for-loop update clauses.
|
|
229
285
|
|
|
230
286
|
---
|
|
231
287
|
|
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 dirname8, join as join8 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import chalk4 from "chalk";
|
|
8
8
|
|
|
@@ -776,7 +776,7 @@ var expand_object_default = createCommand((program2) => {
|
|
|
776
776
|
);
|
|
777
777
|
});
|
|
778
778
|
|
|
779
|
-
// commands/
|
|
779
|
+
// commands/object-packer/index.ts
|
|
780
780
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
781
781
|
import { basename as basename4, dirname as dirname4, extname as extname4, join as join4 } from "path";
|
|
782
782
|
import { parse as parse5 } from "@babel/parser";
|
|
@@ -787,10 +787,192 @@ import loading5 from "loading-cli";
|
|
|
787
787
|
var createDefaultOutputPath4 = (inputPath) => {
|
|
788
788
|
const ext = extname4(inputPath);
|
|
789
789
|
if (!ext) {
|
|
790
|
-
return `${inputPath}.
|
|
790
|
+
return `${inputPath}.object-packer.js`;
|
|
791
791
|
}
|
|
792
792
|
const base = basename4(inputPath, ext);
|
|
793
|
-
return join4(dirname4(inputPath), `${base}.
|
|
793
|
+
return join4(dirname4(inputPath), `${base}.object-packer${ext}`);
|
|
794
|
+
};
|
|
795
|
+
var isEmptyObjectExpression = (node) => {
|
|
796
|
+
return t3.isObjectExpression(node) && node.properties.length === 0;
|
|
797
|
+
};
|
|
798
|
+
var isPropertyAssignment = (node, objectName) => {
|
|
799
|
+
return t3.isAssignmentExpression(node) && t3.isMemberExpression(node.left) && t3.isIdentifier(node.left.object, { name: objectName });
|
|
800
|
+
};
|
|
801
|
+
var hasSelfReference = (value, statementPath, arrayIndex, binding, log) => {
|
|
802
|
+
try {
|
|
803
|
+
const statementContainerPath = statementPath.parentPath?.get(
|
|
804
|
+
`${statementPath.parentKey}.${arrayIndex}`
|
|
805
|
+
);
|
|
806
|
+
let detected = false;
|
|
807
|
+
patchDefault(traverse4)(
|
|
808
|
+
value,
|
|
809
|
+
{
|
|
810
|
+
Identifier(path) {
|
|
811
|
+
if (detected) return;
|
|
812
|
+
if (path.node.name !== binding.identifier.name) return;
|
|
813
|
+
if (path.scope.getBinding(binding.identifier.name) === binding) {
|
|
814
|
+
detected = true;
|
|
815
|
+
path.stop();
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
statementContainerPath.scope,
|
|
820
|
+
void 0,
|
|
821
|
+
statementContainerPath
|
|
822
|
+
);
|
|
823
|
+
return detected;
|
|
824
|
+
} catch (error) {
|
|
825
|
+
log(
|
|
826
|
+
`Error looking for self reference when object packing: ${error instanceof Error ? error.message : String(error)}`
|
|
827
|
+
);
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
var packObjectProperties = (code, filename) => {
|
|
832
|
+
const ast = parse5(code, createParseOptions(filename));
|
|
833
|
+
let packedCount = 0;
|
|
834
|
+
let removedStatements = 0;
|
|
835
|
+
const log = (message) => console.warn(message);
|
|
836
|
+
patchDefault(traverse4)(ast, {
|
|
837
|
+
VariableDeclarator(path) {
|
|
838
|
+
if (!t3.isIdentifier(path.node.id)) return;
|
|
839
|
+
if (!path.node.init || !isEmptyObjectExpression(path.node.init)) return;
|
|
840
|
+
const binding = path.scope.getBinding(path.node.id.name);
|
|
841
|
+
if (!binding || !binding.constant) return;
|
|
842
|
+
const objectExpression = path.node.init;
|
|
843
|
+
const statementPath = path.getStatementParent();
|
|
844
|
+
if (!statementPath || !statementPath.parentPath || typeof statementPath.key !== "number") {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
const statements = statementPath.parentPath.node[statementPath.parentKey];
|
|
848
|
+
let localRemoved = 0;
|
|
849
|
+
let localPacked = 0;
|
|
850
|
+
for (let i = statementPath.key + 1; i < statements.length; i++) {
|
|
851
|
+
const node = statements[i];
|
|
852
|
+
if (t3.isExpressionStatement(node) && isPropertyAssignment(node.expression, path.node.id.name)) {
|
|
853
|
+
const assignment = node.expression;
|
|
854
|
+
if (isPropertyAssignment(assignment.right, path.node.id.name)) {
|
|
855
|
+
const properties = [assignment.left];
|
|
856
|
+
let right = assignment.right;
|
|
857
|
+
while (isPropertyAssignment(right, path.node.id.name)) {
|
|
858
|
+
properties.push(right.left);
|
|
859
|
+
right = right.right;
|
|
860
|
+
}
|
|
861
|
+
if (!t3.isLiteral(right)) {
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
for (const { property } of properties) {
|
|
865
|
+
if (t3.isPrivateName(property)) {
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
const isComputed = !t3.isStringLiteral(property) && !t3.isNumericLiteral(property) && !t3.isIdentifier(property);
|
|
869
|
+
objectExpression.properties.push(
|
|
870
|
+
t3.objectProperty(
|
|
871
|
+
t3.cloneNode(property),
|
|
872
|
+
t3.cloneNode(right, true),
|
|
873
|
+
isComputed
|
|
874
|
+
)
|
|
875
|
+
);
|
|
876
|
+
localPacked += 1;
|
|
877
|
+
}
|
|
878
|
+
localRemoved += 1;
|
|
879
|
+
} else {
|
|
880
|
+
const key = assignment.left.property;
|
|
881
|
+
if (t3.isPrivateName(key)) {
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
const isComputed = !t3.isStringLiteral(key) && !t3.isNumericLiteral(key) && !t3.isIdentifier(key);
|
|
885
|
+
if (hasSelfReference(assignment.right, statementPath, i, binding, log)) {
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
objectExpression.properties.push(
|
|
889
|
+
t3.objectProperty(
|
|
890
|
+
t3.cloneNode(key),
|
|
891
|
+
t3.cloneNode(assignment.right, true),
|
|
892
|
+
isComputed
|
|
893
|
+
)
|
|
894
|
+
);
|
|
895
|
+
localPacked += 1;
|
|
896
|
+
localRemoved += 1;
|
|
897
|
+
}
|
|
898
|
+
} else {
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
if (localRemoved > 0) {
|
|
903
|
+
statements.splice(statementPath.key + 1, localRemoved);
|
|
904
|
+
packedCount += localPacked;
|
|
905
|
+
removedStatements += localRemoved;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
return {
|
|
910
|
+
code: patchDefault(generate4)(ast).code,
|
|
911
|
+
packedCount,
|
|
912
|
+
removedStatements
|
|
913
|
+
};
|
|
914
|
+
};
|
|
915
|
+
var object_packer_default = createCommand((program2) => {
|
|
916
|
+
program2.command("object-packer").description("Pack consecutive object property assignments into literals").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(
|
|
917
|
+
async (fileArgument, options) => {
|
|
918
|
+
await timeout(
|
|
919
|
+
async ({ finish }) => {
|
|
920
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
921
|
+
if (!filename) {
|
|
922
|
+
showError("No file provided");
|
|
923
|
+
return finish();
|
|
924
|
+
}
|
|
925
|
+
try {
|
|
926
|
+
const fileContent = readFileSync5(filename, "utf8");
|
|
927
|
+
const defaultOutputPath = createDefaultOutputPath4(filename);
|
|
928
|
+
let outputPath = options.output;
|
|
929
|
+
if (!outputPath) {
|
|
930
|
+
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
931
|
+
outputPath = promptPath || defaultOutputPath;
|
|
932
|
+
}
|
|
933
|
+
const loader = loading5("Packing object properties...").start();
|
|
934
|
+
try {
|
|
935
|
+
const { code: output, packedCount, removedStatements } = packObjectProperties(fileContent, filename);
|
|
936
|
+
writeFileSync4(outputPath, output, "utf8");
|
|
937
|
+
loader.succeed(
|
|
938
|
+
`Saved object-packer file to: ${outputPath} (${diff(fileContent, output).length} lines changed, ${packedCount} properties packed, ${removedStatements} statements removed)`
|
|
939
|
+
);
|
|
940
|
+
return finish();
|
|
941
|
+
} catch (error) {
|
|
942
|
+
loader.fail("Failed to apply object-packer transform");
|
|
943
|
+
showError(
|
|
944
|
+
`Error transforming file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
945
|
+
);
|
|
946
|
+
return finish();
|
|
947
|
+
}
|
|
948
|
+
} catch (error) {
|
|
949
|
+
showError(
|
|
950
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
951
|
+
);
|
|
952
|
+
return finish();
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
options.unlimited ? null : 120 * 1e3
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
);
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
// commands/pre-evaluate/index.ts
|
|
962
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
963
|
+
import { basename as basename5, dirname as dirname5, extname as extname5, join as join5 } from "path";
|
|
964
|
+
import { parse as parse6 } from "@babel/parser";
|
|
965
|
+
import traverse5 from "@babel/traverse";
|
|
966
|
+
import generate5 from "@babel/generator";
|
|
967
|
+
import * as t4 from "@babel/types";
|
|
968
|
+
import loading6 from "loading-cli";
|
|
969
|
+
var createDefaultOutputPath5 = (inputPath) => {
|
|
970
|
+
const ext = extname5(inputPath);
|
|
971
|
+
if (!ext) {
|
|
972
|
+
return `${inputPath}.pre-evaluate.js`;
|
|
973
|
+
}
|
|
974
|
+
const base = basename5(inputPath, ext);
|
|
975
|
+
return join5(dirname5(inputPath), `${base}.pre-evaluate${ext}`);
|
|
794
976
|
};
|
|
795
977
|
var isSupportedNumberOperator = (operator) => {
|
|
796
978
|
return operator === "-" || operator === "*" || operator === "/" || operator === "%" || operator === "**" || operator === "<<" || operator === ">>" || operator === ">>>" || operator === "|" || operator === "&" || operator === "^";
|
|
@@ -924,13 +1106,13 @@ var shouldSkipReferencedIdentifier = (path) => {
|
|
|
924
1106
|
return false;
|
|
925
1107
|
};
|
|
926
1108
|
var preEvaluate = (code, filename) => {
|
|
927
|
-
const ast =
|
|
1109
|
+
const ast = parse6(code, createParseOptions(filename));
|
|
928
1110
|
const state = {
|
|
929
1111
|
bindingValues: /* @__PURE__ */ new Map(),
|
|
930
1112
|
bindingStack: /* @__PURE__ */ new Set()
|
|
931
1113
|
};
|
|
932
1114
|
let replacedCount = 0;
|
|
933
|
-
patchDefault(
|
|
1115
|
+
patchDefault(traverse5)(ast, {
|
|
934
1116
|
ReferencedIdentifier(path) {
|
|
935
1117
|
if (shouldSkipReferencedIdentifier(path)) {
|
|
936
1118
|
return;
|
|
@@ -938,9 +1120,9 @@ var preEvaluate = (code, filename) => {
|
|
|
938
1120
|
const value = evaluateExpression(path, state);
|
|
939
1121
|
if (value === null) return;
|
|
940
1122
|
if (typeof value === "number") {
|
|
941
|
-
path.replaceWith(
|
|
1123
|
+
path.replaceWith(t4.numericLiteral(value));
|
|
942
1124
|
} else {
|
|
943
|
-
path.replaceWith(
|
|
1125
|
+
path.replaceWith(t4.stringLiteral(value));
|
|
944
1126
|
}
|
|
945
1127
|
replacedCount += 1;
|
|
946
1128
|
},
|
|
@@ -949,9 +1131,9 @@ var preEvaluate = (code, filename) => {
|
|
|
949
1131
|
const value = evaluateExpression(path, state);
|
|
950
1132
|
if (value === null) return;
|
|
951
1133
|
if (typeof value === "number") {
|
|
952
|
-
path.replaceWith(
|
|
1134
|
+
path.replaceWith(t4.numericLiteral(value));
|
|
953
1135
|
} else {
|
|
954
|
-
path.replaceWith(
|
|
1136
|
+
path.replaceWith(t4.stringLiteral(value));
|
|
955
1137
|
}
|
|
956
1138
|
replacedCount += 1;
|
|
957
1139
|
}
|
|
@@ -961,9 +1143,9 @@ var preEvaluate = (code, filename) => {
|
|
|
961
1143
|
const value = evaluateExpression(path, state);
|
|
962
1144
|
if (value === null) return;
|
|
963
1145
|
if (typeof value === "number") {
|
|
964
|
-
path.replaceWith(
|
|
1146
|
+
path.replaceWith(t4.numericLiteral(value));
|
|
965
1147
|
} else {
|
|
966
|
-
path.replaceWith(
|
|
1148
|
+
path.replaceWith(t4.stringLiteral(value));
|
|
967
1149
|
}
|
|
968
1150
|
replacedCount += 1;
|
|
969
1151
|
}
|
|
@@ -973,16 +1155,16 @@ var preEvaluate = (code, filename) => {
|
|
|
973
1155
|
const value = evaluateExpression(path, state);
|
|
974
1156
|
if (value === null) return;
|
|
975
1157
|
if (typeof value === "number") {
|
|
976
|
-
path.replaceWith(
|
|
1158
|
+
path.replaceWith(t4.numericLiteral(value));
|
|
977
1159
|
} else {
|
|
978
|
-
path.replaceWith(
|
|
1160
|
+
path.replaceWith(t4.stringLiteral(value));
|
|
979
1161
|
}
|
|
980
1162
|
replacedCount += 1;
|
|
981
1163
|
}
|
|
982
1164
|
}
|
|
983
1165
|
});
|
|
984
1166
|
return {
|
|
985
|
-
code: patchDefault(
|
|
1167
|
+
code: patchDefault(generate5)(ast).code,
|
|
986
1168
|
replacedCount
|
|
987
1169
|
};
|
|
988
1170
|
};
|
|
@@ -997,20 +1179,20 @@ var pre_evaluate_default = createCommand((program2) => {
|
|
|
997
1179
|
return finish();
|
|
998
1180
|
}
|
|
999
1181
|
try {
|
|
1000
|
-
const fileContent =
|
|
1001
|
-
const defaultOutputPath =
|
|
1182
|
+
const fileContent = readFileSync6(filename, "utf8");
|
|
1183
|
+
const defaultOutputPath = createDefaultOutputPath5(filename);
|
|
1002
1184
|
let outputPath = options.output;
|
|
1003
1185
|
if (!outputPath) {
|
|
1004
1186
|
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
1005
1187
|
outputPath = promptPath || defaultOutputPath;
|
|
1006
1188
|
}
|
|
1007
|
-
const loader =
|
|
1189
|
+
const loader = loading6("Pre-evaluating constants...").start();
|
|
1008
1190
|
try {
|
|
1009
1191
|
const { code: output, replacedCount } = preEvaluate(
|
|
1010
1192
|
fileContent,
|
|
1011
1193
|
filename
|
|
1012
1194
|
);
|
|
1013
|
-
|
|
1195
|
+
writeFileSync5(outputPath, output, "utf8");
|
|
1014
1196
|
loader.succeed(
|
|
1015
1197
|
`Saved pre-evaluate file to: ${outputPath} (${diff(fileContent, output).length} lines changed, ${replacedCount} replacements)`
|
|
1016
1198
|
);
|
|
@@ -1035,30 +1217,124 @@ var pre_evaluate_default = createCommand((program2) => {
|
|
|
1035
1217
|
);
|
|
1036
1218
|
});
|
|
1037
1219
|
|
|
1220
|
+
// commands/remove-updater/index.ts
|
|
1221
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
1222
|
+
import { basename as basename6, dirname as dirname6, extname as extname6, join as join6 } from "path";
|
|
1223
|
+
import { parse as parse7 } from "@babel/parser";
|
|
1224
|
+
import traverse6 from "@babel/traverse";
|
|
1225
|
+
import generate6 from "@babel/generator";
|
|
1226
|
+
import * as t5 from "@babel/types";
|
|
1227
|
+
import loading7 from "loading-cli";
|
|
1228
|
+
var createDefaultOutputPath6 = (inputPath) => {
|
|
1229
|
+
const ext = extname6(inputPath);
|
|
1230
|
+
if (!ext) {
|
|
1231
|
+
return `${inputPath}.remove-updater.js`;
|
|
1232
|
+
}
|
|
1233
|
+
const base = basename6(inputPath, ext);
|
|
1234
|
+
return join6(dirname6(inputPath), `${base}.remove-updater${ext}`);
|
|
1235
|
+
};
|
|
1236
|
+
var isSafeStandaloneUpdate = (path) => {
|
|
1237
|
+
const parent = path.parentPath;
|
|
1238
|
+
if (!parent) return false;
|
|
1239
|
+
if (parent.isExpressionStatement()) return true;
|
|
1240
|
+
if (parent.isForStatement() && path.key === "update") return true;
|
|
1241
|
+
return false;
|
|
1242
|
+
};
|
|
1243
|
+
var removeUpdaters = (code, filename) => {
|
|
1244
|
+
const ast = parse7(code, createParseOptions(filename));
|
|
1245
|
+
let replacedCount = 0;
|
|
1246
|
+
patchDefault(traverse6)(ast, {
|
|
1247
|
+
UpdateExpression(path) {
|
|
1248
|
+
if (!isSafeStandaloneUpdate(path)) return;
|
|
1249
|
+
const operator = path.node.operator === "++" ? "+=" : "-=";
|
|
1250
|
+
const left = t5.cloneNode(path.node.argument, true);
|
|
1251
|
+
const replacement = t5.assignmentExpression(
|
|
1252
|
+
operator,
|
|
1253
|
+
left,
|
|
1254
|
+
t5.numericLiteral(1)
|
|
1255
|
+
);
|
|
1256
|
+
path.replaceWith(replacement);
|
|
1257
|
+
replacedCount += 1;
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
return {
|
|
1261
|
+
code: patchDefault(generate6)(ast).code,
|
|
1262
|
+
replacedCount
|
|
1263
|
+
};
|
|
1264
|
+
};
|
|
1265
|
+
var remove_updater_default = createCommand((program2) => {
|
|
1266
|
+
program2.command("remove-updater").description("Replace safe update expressions with += or -=").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(
|
|
1267
|
+
async (fileArgument, options) => {
|
|
1268
|
+
await timeout(
|
|
1269
|
+
async ({ finish }) => {
|
|
1270
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
1271
|
+
if (!filename) {
|
|
1272
|
+
showError("No file provided");
|
|
1273
|
+
return finish();
|
|
1274
|
+
}
|
|
1275
|
+
try {
|
|
1276
|
+
const fileContent = readFileSync7(filename, "utf8");
|
|
1277
|
+
const defaultOutputPath = createDefaultOutputPath6(filename);
|
|
1278
|
+
let outputPath = options.output;
|
|
1279
|
+
if (!outputPath) {
|
|
1280
|
+
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
1281
|
+
outputPath = promptPath || defaultOutputPath;
|
|
1282
|
+
}
|
|
1283
|
+
const loader = loading7("Removing update expressions...").start();
|
|
1284
|
+
try {
|
|
1285
|
+
const { code: output, replacedCount } = removeUpdaters(
|
|
1286
|
+
fileContent,
|
|
1287
|
+
filename
|
|
1288
|
+
);
|
|
1289
|
+
writeFileSync6(outputPath, output, "utf8");
|
|
1290
|
+
loader.succeed(
|
|
1291
|
+
`Saved remove-updater file to: ${outputPath} (${diff(fileContent, output).length} lines changed, ${replacedCount} updates replaced)`
|
|
1292
|
+
);
|
|
1293
|
+
return finish();
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
loader.fail("Failed to apply remove-updater transform");
|
|
1296
|
+
showError(
|
|
1297
|
+
`Error transforming file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1298
|
+
);
|
|
1299
|
+
return finish();
|
|
1300
|
+
}
|
|
1301
|
+
} catch (error) {
|
|
1302
|
+
showError(
|
|
1303
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1304
|
+
);
|
|
1305
|
+
return finish();
|
|
1306
|
+
}
|
|
1307
|
+
},
|
|
1308
|
+
options.unlimited ? null : 120 * 1e3
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1038
1314
|
// commands/remove-unused/index.ts
|
|
1039
|
-
import { readFileSync as
|
|
1040
|
-
import { basename as
|
|
1041
|
-
import { parse as
|
|
1042
|
-
import
|
|
1043
|
-
import
|
|
1044
|
-
import * as
|
|
1045
|
-
import
|
|
1046
|
-
var
|
|
1047
|
-
const ext =
|
|
1315
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
1316
|
+
import { basename as basename7, dirname as dirname7, extname as extname7, join as join7 } from "path";
|
|
1317
|
+
import { parse as parse8 } from "@babel/parser";
|
|
1318
|
+
import traverse7 from "@babel/traverse";
|
|
1319
|
+
import generate7 from "@babel/generator";
|
|
1320
|
+
import * as t6 from "@babel/types";
|
|
1321
|
+
import loading8 from "loading-cli";
|
|
1322
|
+
var createDefaultOutputPath7 = (inputPath) => {
|
|
1323
|
+
const ext = extname7(inputPath);
|
|
1048
1324
|
if (!ext) {
|
|
1049
1325
|
return `${inputPath}.remove-unused.js`;
|
|
1050
1326
|
}
|
|
1051
|
-
const base =
|
|
1052
|
-
return
|
|
1327
|
+
const base = basename7(inputPath, ext);
|
|
1328
|
+
return join7(dirname7(inputPath), `${base}.remove-unused${ext}`);
|
|
1053
1329
|
};
|
|
1054
1330
|
var removeUnusedVariables = (code, filename) => {
|
|
1055
|
-
const ast =
|
|
1331
|
+
const ast = parse8(code, createParseOptions(filename));
|
|
1056
1332
|
let changed = false;
|
|
1057
|
-
patchDefault(
|
|
1333
|
+
patchDefault(traverse7)(ast, {
|
|
1058
1334
|
Scope(path) {
|
|
1059
1335
|
for (const binding of Object.values(path.scope.bindings)) {
|
|
1060
1336
|
if (!binding.referenced && binding.constantViolations.length === 0 && binding.path.key !== "handler" && !binding.path.isFunctionExpression()) {
|
|
1061
|
-
if (
|
|
1337
|
+
if (t6.isProgram(binding.scope.block) && (binding.kind === "var" || binding.kind === "hoisted")) {
|
|
1062
1338
|
continue;
|
|
1063
1339
|
}
|
|
1064
1340
|
const targets = binding.path.parentKey === "params" ? [...binding.referencePaths, ...binding.constantViolations] : [
|
|
@@ -1067,11 +1343,11 @@ var removeUnusedVariables = (code, filename) => {
|
|
|
1067
1343
|
...binding.constantViolations
|
|
1068
1344
|
];
|
|
1069
1345
|
for (const targetPath of targets) {
|
|
1070
|
-
if (targetPath.isVariableDeclarator() && (
|
|
1346
|
+
if (targetPath.isVariableDeclarator() && (t6.isArrayPattern(targetPath.node.id) && targetPath.node.id.elements.length > 1 || t6.isObjectPattern(targetPath.node.id) && targetPath.node.id.properties.length > 1)) {
|
|
1071
1347
|
continue;
|
|
1072
1348
|
}
|
|
1073
1349
|
if (targetPath.key === "consequent" || targetPath.key === "alternate" || targetPath.key === "body") {
|
|
1074
|
-
targetPath.replaceWith(
|
|
1350
|
+
targetPath.replaceWith(t6.blockStatement([]));
|
|
1075
1351
|
} else {
|
|
1076
1352
|
const parentPath = targetPath.parentPath;
|
|
1077
1353
|
if (parentPath?.isVariableDeclaration() && parentPath.node.declarations.length === 1) {
|
|
@@ -1087,7 +1363,7 @@ var removeUnusedVariables = (code, filename) => {
|
|
|
1087
1363
|
}
|
|
1088
1364
|
});
|
|
1089
1365
|
return {
|
|
1090
|
-
code: patchDefault(
|
|
1366
|
+
code: patchDefault(generate7)(ast).code,
|
|
1091
1367
|
changed
|
|
1092
1368
|
};
|
|
1093
1369
|
};
|
|
@@ -1102,20 +1378,20 @@ var remove_unused_default = createCommand((program2) => {
|
|
|
1102
1378
|
return finish();
|
|
1103
1379
|
}
|
|
1104
1380
|
try {
|
|
1105
|
-
const fileContent =
|
|
1106
|
-
const defaultOutputPath =
|
|
1381
|
+
const fileContent = readFileSync8(filename, "utf8");
|
|
1382
|
+
const defaultOutputPath = createDefaultOutputPath7(filename);
|
|
1107
1383
|
let outputPath = options.output;
|
|
1108
1384
|
if (!outputPath) {
|
|
1109
1385
|
const promptPath = (await createPrompt("Enter the output file path:"))?.trim();
|
|
1110
1386
|
outputPath = promptPath || defaultOutputPath;
|
|
1111
1387
|
}
|
|
1112
|
-
const loader =
|
|
1388
|
+
const loader = loading8("Removing unused variables...").start();
|
|
1113
1389
|
try {
|
|
1114
1390
|
const { code: output, changed } = removeUnusedVariables(
|
|
1115
1391
|
fileContent,
|
|
1116
1392
|
filename
|
|
1117
1393
|
);
|
|
1118
|
-
|
|
1394
|
+
writeFileSync7(outputPath, output, "utf8");
|
|
1119
1395
|
const diffLines = diff(fileContent, output).length;
|
|
1120
1396
|
loader.succeed(
|
|
1121
1397
|
`Saved remove-unused file to: ${outputPath} (${diffLines} lines changed${changed ? ", removed unused declarations" : ", no changes"})`
|
|
@@ -1165,10 +1441,10 @@ var calmGradienrain = (text) => {
|
|
|
1165
1441
|
const endHue = 300;
|
|
1166
1442
|
const saturation = 0.45;
|
|
1167
1443
|
const value = 0.8;
|
|
1168
|
-
const ease = (
|
|
1444
|
+
const ease = (t7) => t7 * t7 * (3 - 2 * t7);
|
|
1169
1445
|
return text.split("").map((char, i) => {
|
|
1170
|
-
const
|
|
1171
|
-
const hue = startHue + (endHue - startHue) *
|
|
1446
|
+
const t7 = ease(i / Math.max(text.length - 1, 1));
|
|
1447
|
+
const hue = startHue + (endHue - startHue) * t7;
|
|
1172
1448
|
const c = value * saturation;
|
|
1173
1449
|
const h = hue / 60;
|
|
1174
1450
|
const x = c * (1 - Math.abs(h % 2 - 1));
|
|
@@ -1192,10 +1468,10 @@ ${calmGradienrain(`Expose Kit v${VERSION}`)}
|
|
|
1192
1468
|
`;
|
|
1193
1469
|
|
|
1194
1470
|
// index.ts
|
|
1195
|
-
import { readFileSync as
|
|
1471
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
1196
1472
|
var __filename = fileURLToPath(import.meta.url);
|
|
1197
|
-
var __dirname =
|
|
1198
|
-
var pkg = JSON.parse(
|
|
1473
|
+
var __dirname = dirname8(__filename);
|
|
1474
|
+
var pkg = JSON.parse(readFileSync9(join8(__dirname, "package.json"), "utf8"));
|
|
1199
1475
|
console.log(showCredit(pkg.version));
|
|
1200
1476
|
console.log();
|
|
1201
1477
|
var program = new Command();
|
|
@@ -1209,7 +1485,9 @@ var commands = [
|
|
|
1209
1485
|
safe_scope_default,
|
|
1210
1486
|
expand_array_default,
|
|
1211
1487
|
expand_object_default,
|
|
1488
|
+
object_packer_default,
|
|
1212
1489
|
pre_evaluate_default,
|
|
1490
|
+
remove_updater_default,
|
|
1213
1491
|
remove_unused_default
|
|
1214
1492
|
];
|
|
1215
1493
|
for (const command of commands) {
|
package/dist/package.json
CHANGED