webfuscator 0.9.5 → 1.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.
- package/README.md +35 -62
- package/dist/obfuscator.d.ts.map +1 -1
- package/dist/obfuscator.js +5 -10
- package/dist/obfuscator.js.map +1 -1
- package/dist/options.d.ts +4 -3
- package/dist/options.d.ts.map +1 -1
- package/dist/transforms/mangle-properties.d.ts +1 -1
- package/dist/transforms/mangle-properties.js +1 -1
- package/package.json +8 -16
- package/src/obfuscator.ts +9 -12
- package/src/options.ts +4 -3
- package/src/transforms/mangle-properties.ts +1 -1
- package/dist/preparation/rewrite-class-fields.d.ts +0 -43
- package/dist/preparation/rewrite-class-fields.d.ts.map +0 -1
- package/dist/preparation/rewrite-class-fields.js +0 -270
- package/dist/preparation/rewrite-class-fields.js.map +0 -1
- package/src/preparation/rewrite-class-fields.ts +0 -320
package/README.md
CHANGED
|
@@ -1,90 +1,63 @@
|
|
|
1
1
|
# webfuscator
|
|
2
2
|
|
|
3
|
-
`webfuscator` is a Babel-based JavaScript obfuscator. It parses source
|
|
3
|
+
`webfuscator` is a Babel-based JavaScript obfuscator. It parses a JavaScript source string, applies configurable transforms, and returns JavaScript source.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Renames variables, functions, and labels
|
|
8
|
-
- Mangles selected property names
|
|
9
|
-
- Inlines functions and folds constants
|
|
10
|
-
- Rewrites loops, conditionals, and switch statements
|
|
11
|
-
- Turns numbers and other literals into string-based expressions
|
|
12
|
-
- Removes dead code
|
|
13
|
-
- Generates short, hexadecimal, random, keyword-like, or numbered names
|
|
14
|
-
- Seeds built-in randomization for reproducible output
|
|
5
|
+
[Read the documentation](https://webfuscator.mintlify.app/) for the quickstart, configuration guides, API details, and a reference page for every transform.
|
|
15
6
|
|
|
16
7
|
## Install
|
|
17
8
|
|
|
18
9
|
```sh
|
|
19
|
-
npm install webfuscator
|
|
10
|
+
npm install --save-dev webfuscator
|
|
20
11
|
```
|
|
21
12
|
|
|
13
|
+
The package is ESM-only, includes TypeScript declarations, and requires Node.js `^22.18.0 || >=24.11.0`.
|
|
14
|
+
|
|
22
15
|
## Usage
|
|
23
16
|
|
|
24
17
|
```js
|
|
25
18
|
import { obfuscate } from 'webfuscator'
|
|
26
19
|
|
|
27
|
-
const source = `
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
20
|
+
const source = `export default function square(value) {
|
|
21
|
+
return value * value
|
|
22
|
+
}`
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const code = obfuscate(source, {
|
|
36
|
-
stringGeneratorMode: 'mangled', // Other modes: hexadecimal, randomized, zeroWidth, number
|
|
24
|
+
const output = obfuscate(source, {
|
|
25
|
+
minify: true,
|
|
37
26
|
seed: 0,
|
|
38
|
-
transforms: {
|
|
27
|
+
transforms: {
|
|
28
|
+
renameIdentifiers: true,
|
|
29
|
+
},
|
|
39
30
|
})
|
|
40
31
|
```
|
|
41
32
|
|
|
42
|
-
`obfuscate(code, options?)`
|
|
33
|
+
`obfuscate(code, options?)` is synchronous. It does not execute the input or write files.
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
Configurable transforms are disabled by default; preparation passes always run.
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
outside its input, so unrestricted mangling can break callers. Use `regex` to
|
|
48
|
-
limit mangling to private application properties, such as names ending in `_`:
|
|
37
|
+
## Documentation
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
- [Quickstart](https://webfuscator.mintlify.app/getting-started/quickstart)
|
|
40
|
+
- [JavaScript API](https://webfuscator.mintlify.app/reference/api)
|
|
41
|
+
- [Configure transforms](https://webfuscator.mintlify.app/guides/configure-transforms)
|
|
42
|
+
- [Obfuscator options](https://webfuscator.mintlify.app/reference/options)
|
|
43
|
+
- [Property mangling](https://webfuscator.mintlify.app/reference/property-mangling-options)
|
|
44
|
+
- [String generator modes](https://webfuscator.mintlify.app/reference/string-generator-modes)
|
|
45
|
+
- [Report a bug](https://webfuscator.mintlify.app/troubleshooting/report-a-bug)
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
})
|
|
47
|
+
## Development
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pnpm install
|
|
51
|
+
pnpm test
|
|
52
|
+
pnpm check
|
|
53
|
+
pnpm docs:check
|
|
62
54
|
```
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- `cache` is a mutable `Map<string, string>` that reuses mappings across separate
|
|
70
|
-
inputs. `onlyCache` limits mangling to keys already in that map.
|
|
71
|
-
- `nameGenerator(index)` receives a zero-based ordinal and returns the next name.
|
|
72
|
-
Without it, the transform uses its own `stringGeneratorMode` or the top-level
|
|
73
|
-
mode.
|
|
74
|
-
- `debug: true` emits names in the form `_$source$_`. A string value becomes the
|
|
75
|
-
suffix.
|
|
76
|
-
- `keepQuoted: true` reserves quoted property names everywhere. `'strict'` keeps
|
|
77
|
-
quoted occurrences unchanged but allows unquoted occurrences of the same name
|
|
78
|
-
to be mangled.
|
|
79
|
-
- `onlyAnnotated` limits mangling to names marked with
|
|
80
|
-
`/*@__MANGLE_PROP__*/`. `/*@__KEY__*/` marks a string literal as a use of the
|
|
81
|
-
selected property name. Either annotation may use `#` instead of `@`.
|
|
82
|
-
- `undeclared` includes unquoted member accesses rooted at identifiers that are
|
|
83
|
-
not declared in the input. Bracket-string accesses are considered either way.
|
|
84
|
-
|
|
85
|
-
## Issues and pull requests
|
|
86
|
-
|
|
87
|
-
Both are open. For bugs, include the input and options you used.
|
|
56
|
+
Read [AGENTS.md](./AGENTS.md) before changing transforms or analysis code.
|
|
57
|
+
|
|
58
|
+
## Responsible use
|
|
59
|
+
|
|
60
|
+
Use `webfuscator` only on software you own or are authorized to modify. Read [DISCLOSURE](./DISCLOSURE) for the project's dual-use policy.
|
|
88
61
|
|
|
89
62
|
## License
|
|
90
63
|
|
package/dist/obfuscator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obfuscator.d.ts","sourceRoot":"","sources":["../src/obfuscator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAmC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"obfuscator.d.ts","sourceRoot":"","sources":["../src/obfuscator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAmC,MAAM,aAAa,CAAA;AAoIrF,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAsD/E"}
|
package/dist/obfuscator.js
CHANGED
|
@@ -3,7 +3,6 @@ import { parse } from '@babel/parser';
|
|
|
3
3
|
import { dotToBracket } from './preparation/dot-to-bracket.js';
|
|
4
4
|
import { expandDestructuring } from './preparation/expand-destructuring.js';
|
|
5
5
|
import { expandTemplateLiterals } from './preparation/expand-template-literals.js';
|
|
6
|
-
import { rewriteClassFields } from './preparation/rewrite-class-fields.js';
|
|
7
6
|
import { splitSequenceExpressions } from './preparation/split-sequence-expressions.js';
|
|
8
7
|
import { splitVariableDeclarations } from './preparation/split-variable-declarations.js';
|
|
9
8
|
import { stringifyObjectKeys } from './preparation/stringify-object-keys.js';
|
|
@@ -47,12 +46,11 @@ const DEFAULT_SEED = 0;
|
|
|
47
46
|
// Real inputs settle in a handful of iterations. Hitting this cap signals an
|
|
48
47
|
// algorithmic bug; never raise it as a workaround.
|
|
49
48
|
const FIXED_POINT_ITERATION_CAP = 10;
|
|
50
|
-
// Mangling must see quoted access
|
|
51
|
-
//
|
|
49
|
+
// Mangling must see quoted access before preparation erases that distinction.
|
|
50
|
+
// It is opt-in because outside code may use the same properties.
|
|
52
51
|
const BEFORE_PREPARATION = [['mangleProperties', mangleProperties]];
|
|
53
52
|
// Shape-normalizing passes. Always run; never exposed in `options.transforms`.
|
|
54
53
|
const PREPARATION = [
|
|
55
|
-
['rewriteClassFields', asBoolean(rewriteClassFields)],
|
|
56
54
|
['expandDestructuring', asBoolean(expandDestructuring)],
|
|
57
55
|
['wrapSingleStatements', asBoolean(wrapSingleStatements)],
|
|
58
56
|
['splitSequenceExpressions', asBoolean(splitSequenceExpressions)],
|
|
@@ -158,14 +156,11 @@ export function obfuscate(code, options = {}) {
|
|
|
158
156
|
}
|
|
159
157
|
run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)));
|
|
160
158
|
}
|
|
161
|
-
return run(log, 'generate', () => generate(ast, { shouldPrintComment }).code);
|
|
159
|
+
return run(log, 'generate', () => generate(ast, { minified: options.minify ?? false, shouldPrintComment }).code);
|
|
162
160
|
}
|
|
163
161
|
function isEnabled(name, options) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
options.transforms.mangleProperties !== false);
|
|
167
|
-
}
|
|
168
|
-
return options.transforms?.[name] !== false;
|
|
162
|
+
const entry = options.transforms?.[name];
|
|
163
|
+
return entry !== undefined && entry !== false;
|
|
169
164
|
}
|
|
170
165
|
// Boolean entries inherit the base. An override replaces its string mode.
|
|
171
166
|
function ctxFor(name, options, base) {
|
package/dist/obfuscator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obfuscator.js","sourceRoot":"","sources":["../src/obfuscator.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAKrC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"obfuscator.js","sourceRoot":"","sources":["../src/obfuscator.ts"],"names":[],"mappings":"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"}
|
package/dist/options.d.ts
CHANGED
|
@@ -47,12 +47,13 @@ type TransformsMap = Partial<Record<SimpleTransform, boolean>> & {
|
|
|
47
47
|
specialsToStrings?: TransformEntry;
|
|
48
48
|
};
|
|
49
49
|
export interface ObfuscatorOptions {
|
|
50
|
+
/** Print Babel's minified output instead of its standard formatted output. */
|
|
51
|
+
minify?: boolean;
|
|
50
52
|
/** Logs each pipeline step and its elapsed milliseconds to stderr. */
|
|
51
53
|
verbose?: boolean;
|
|
52
54
|
/**
|
|
53
|
-
* Per-transform toggles and string-generator overrides.
|
|
54
|
-
*
|
|
55
|
-
* transforms default to enabled.
|
|
55
|
+
* Per-transform toggles and string-generator overrides. Omitted transforms
|
|
56
|
+
* are disabled. Preparation passes always run and are not configurable.
|
|
56
57
|
*/
|
|
57
58
|
transforms?: TransformsMap;
|
|
58
59
|
/**
|
package/dist/options.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAA;AAE3E;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB,aAAa,GACb,cAAc,GACd,YAAY,GACZ,eAAe,GACf,uBAAuB,GACvB,wBAAwB,GACxB,eAAe,GACf,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,uBAAuB,GACvB,kBAAkB,GAClB,8BAA8B,GAC9B,wBAAwB,GACxB,iBAAiB,GACjB,iCAAiC,GACjC,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,oBAAoB,GACpB,wBAAwB,GACxB,yBAAyB,GACzB,2BAA2B,GAC3B,4BAA4B,GAC5B,kBAAkB,GAClB,aAAa,GACb,gCAAgC,GAChC,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,CAAA;AAGvB,KAAK,cAAc,GAAG,OAAO,GAAG;IAAE,mBAAmB,CAAC,EAAE,yBAAyB,CAAA;CAAE,CAAA;AAEnF,2DAA2D;AAC3D,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAE7D,0EAA0E;AAC1E,MAAM,WAAW,uBAAuB;IACtC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC/B,sFAAsF;IACtF,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,yBAAyB,CAAA;IAC/C,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,KAAK,eAAe,GAAG,OAAO,CAC5B,aAAa,EACb,kBAAkB,GAAG,mBAAmB,GAAG,mBAAmB,CAC/D,CAAA;AAED,KAAK,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,GAAG;IAC/D,gBAAgB,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAA;IACpD,iBAAiB,CAAC,EAAE,cAAc,CAAA;IAClC,iBAAiB,CAAC,EAAE,cAAc,CAAA;CACnC,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAA;AAE3E;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB,aAAa,GACb,cAAc,GACd,YAAY,GACZ,eAAe,GACf,uBAAuB,GACvB,wBAAwB,GACxB,eAAe,GACf,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,uBAAuB,GACvB,kBAAkB,GAClB,8BAA8B,GAC9B,wBAAwB,GACxB,iBAAiB,GACjB,iCAAiC,GACjC,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,oBAAoB,GACpB,wBAAwB,GACxB,yBAAyB,GACzB,2BAA2B,GAC3B,4BAA4B,GAC5B,kBAAkB,GAClB,aAAa,GACb,gCAAgC,GAChC,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,CAAA;AAGvB,KAAK,cAAc,GAAG,OAAO,GAAG;IAAE,mBAAmB,CAAC,EAAE,yBAAyB,CAAA;CAAE,CAAA;AAEnF,2DAA2D;AAC3D,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAE7D,0EAA0E;AAC1E,MAAM,WAAW,uBAAuB;IACtC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC/B,sFAAsF;IACtF,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,yBAAyB,CAAA;IAC/C,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,KAAK,eAAe,GAAG,OAAO,CAC5B,aAAa,EACb,kBAAkB,GAAG,mBAAmB,GAAG,mBAAmB,CAC/D,CAAA;AAED,KAAK,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,GAAG;IAC/D,gBAAgB,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAA;IACpD,iBAAiB,CAAC,EAAE,cAAc,CAAA;IAClC,iBAAiB,CAAC,EAAE,cAAc,CAAA;CACnC,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,aAAa,CAAA;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,yBAAyB,CAAA;IAC/C,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAGD,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,uBAAuB,CAAA;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,EAAE,yBAAyB,CAAA;CAC/C"}
|
|
@@ -6,7 +6,7 @@ import type { TransformContext } from '../options.js';
|
|
|
6
6
|
* that this pipeline must leave unchanged.
|
|
7
7
|
*
|
|
8
8
|
* This pass runs before shape preparation, while Babel still distinguishes
|
|
9
|
-
* `obj.name` from `obj["name"]
|
|
9
|
+
* `obj.name` from `obj["name"]`.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* // ◀️ before
|
|
@@ -11,7 +11,7 @@ import { StringGenerator } from '../utils/string-generator.js';
|
|
|
11
11
|
* that this pipeline must leave unchanged.
|
|
12
12
|
*
|
|
13
13
|
* This pass runs before shape preparation, while Babel still distinguishes
|
|
14
|
-
* `obj.name` from `obj["name"]
|
|
14
|
+
* `obj.name` from `obj["name"]`.
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* // ◀️ before
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webfuscator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "JavaScript obfuscator built on Babel",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"babel",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
25
|
-
"url": "git+https://github.com/esoware/webfuscator.git"
|
|
25
|
+
"url": "git+https://github.com/esoware/webfuscator.git",
|
|
26
|
+
"directory": "packages/webfuscator"
|
|
26
27
|
},
|
|
27
28
|
"files": [
|
|
28
29
|
"DISCLOSURE",
|
|
@@ -42,17 +43,12 @@
|
|
|
42
43
|
}
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
|
-
"prepublishOnly": "pnpm check",
|
|
46
|
-
"
|
|
46
|
+
"prepublishOnly": "pnpm --workspace-root check",
|
|
47
|
+
"prepack": "pnpm run build",
|
|
47
48
|
"build": "node --eval \"require('node:fs').rmSync('dist', { force: true, recursive: true })\" && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
48
|
-
"
|
|
49
|
-
"lint:fix": "oxlint --fix src tests",
|
|
50
|
-
"format": "oxfmt \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
51
|
-
"format:check": "oxfmt --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
52
|
-
"typecheck": "tsc --noEmit",
|
|
53
|
-
"knip": "knip",
|
|
49
|
+
"check": "pnpm run typecheck && pnpm run test",
|
|
54
50
|
"test": "vitest run",
|
|
55
|
-
"
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
56
52
|
},
|
|
57
53
|
"dependencies": {
|
|
58
54
|
"@babel/generator": "^8.0.0",
|
|
@@ -62,15 +58,11 @@
|
|
|
62
58
|
},
|
|
63
59
|
"devDependencies": {
|
|
64
60
|
"@types/node": "^26.2.0",
|
|
65
|
-
"knip": "^6.32.2",
|
|
66
|
-
"oxfmt": "^0.64.0",
|
|
67
|
-
"oxlint": "^1.79.0",
|
|
68
61
|
"tsc-alias": "^1.9.2",
|
|
69
62
|
"typescript": "^7.0.2",
|
|
70
63
|
"vitest": "^4.1.11"
|
|
71
64
|
},
|
|
72
65
|
"engines": {
|
|
73
66
|
"node": "^22.18.0 || >=24.11.0"
|
|
74
|
-
}
|
|
75
|
-
"packageManager": "pnpm@11.22.0"
|
|
67
|
+
}
|
|
76
68
|
}
|
package/src/obfuscator.ts
CHANGED
|
@@ -7,7 +7,6 @@ import type { ObfuscatorOptions, TransformContext, TransformName } from 'src/opt
|
|
|
7
7
|
import { dotToBracket } from 'src/preparation/dot-to-bracket'
|
|
8
8
|
import { expandDestructuring } from 'src/preparation/expand-destructuring'
|
|
9
9
|
import { expandTemplateLiterals } from 'src/preparation/expand-template-literals'
|
|
10
|
-
import { rewriteClassFields } from 'src/preparation/rewrite-class-fields'
|
|
11
10
|
import { splitSequenceExpressions } from 'src/preparation/split-sequence-expressions'
|
|
12
11
|
import { splitVariableDeclarations } from 'src/preparation/split-variable-declarations'
|
|
13
12
|
import { stringifyObjectKeys } from 'src/preparation/stringify-object-keys'
|
|
@@ -61,13 +60,12 @@ type TransformFn = (ast: File, ctx: TransformContext) => boolean
|
|
|
61
60
|
type Phase = readonly [name: string, fn: TransformFn]
|
|
62
61
|
type ConfigurablePhase = readonly [name: TransformName, fn: TransformFn]
|
|
63
62
|
|
|
64
|
-
// Mangling must see quoted access
|
|
65
|
-
//
|
|
63
|
+
// Mangling must see quoted access before preparation erases that distinction.
|
|
64
|
+
// It is opt-in because outside code may use the same properties.
|
|
66
65
|
const BEFORE_PREPARATION: readonly ConfigurablePhase[] = [['mangleProperties', mangleProperties]]
|
|
67
66
|
|
|
68
67
|
// Shape-normalizing passes. Always run; never exposed in `options.transforms`.
|
|
69
68
|
const PREPARATION: readonly Phase[] = [
|
|
70
|
-
['rewriteClassFields', asBoolean(rewriteClassFields)],
|
|
71
69
|
['expandDestructuring', asBoolean(expandDestructuring)],
|
|
72
70
|
['wrapSingleStatements', asBoolean(wrapSingleStatements)],
|
|
73
71
|
['splitSequenceExpressions', asBoolean(splitSequenceExpressions)],
|
|
@@ -187,17 +185,16 @@ export function obfuscate(code: string, options: ObfuscatorOptions = {}): string
|
|
|
187
185
|
run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)))
|
|
188
186
|
}
|
|
189
187
|
|
|
190
|
-
return run(
|
|
188
|
+
return run(
|
|
189
|
+
log,
|
|
190
|
+
'generate',
|
|
191
|
+
() => generate(ast, { minified: options.minify ?? false, shouldPrintComment }).code,
|
|
192
|
+
)
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
function isEnabled(name: TransformName, options: ObfuscatorOptions): boolean {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
options.transforms?.mangleProperties !== undefined &&
|
|
197
|
-
options.transforms.mangleProperties !== false
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
return options.transforms?.[name] !== false
|
|
196
|
+
const entry = options.transforms?.[name]
|
|
197
|
+
return entry !== undefined && entry !== false
|
|
201
198
|
}
|
|
202
199
|
|
|
203
200
|
// Boolean entries inherit the base. An override replaces its string mode.
|
package/src/options.ts
CHANGED
|
@@ -88,12 +88,13 @@ type TransformsMap = Partial<Record<SimpleTransform, boolean>> & {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export interface ObfuscatorOptions {
|
|
91
|
+
/** Print Babel's minified output instead of its standard formatted output. */
|
|
92
|
+
minify?: boolean
|
|
91
93
|
/** Logs each pipeline step and its elapsed milliseconds to stderr. */
|
|
92
94
|
verbose?: boolean
|
|
93
95
|
/**
|
|
94
|
-
* Per-transform toggles and string-generator overrides.
|
|
95
|
-
*
|
|
96
|
-
* transforms default to enabled.
|
|
96
|
+
* Per-transform toggles and string-generator overrides. Omitted transforms
|
|
97
|
+
* are disabled. Preparation passes always run and are not configurable.
|
|
97
98
|
*/
|
|
98
99
|
transforms?: TransformsMap
|
|
99
100
|
/**
|
|
@@ -17,7 +17,7 @@ import { StringGenerator } from 'src/utils/string-generator'
|
|
|
17
17
|
* that this pipeline must leave unchanged.
|
|
18
18
|
*
|
|
19
19
|
* This pass runs before shape preparation, while Babel still distinguishes
|
|
20
|
-
* `obj.name` from `obj["name"]
|
|
20
|
+
* `obj.name` from `obj["name"]`.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* // ◀️ before
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { File } from '@babel/types';
|
|
2
|
-
/**
|
|
3
|
-
* Moves safe instance fields into the constructor and safe static fields into
|
|
4
|
-
* static blocks. The whole class stays intact unless every field can be lowered.
|
|
5
|
-
*
|
|
6
|
-
* `Object.defineProperty` preserves CreateDataProperty semantics. A plain
|
|
7
|
-
* assignment could invoke an inherited setter or fail on an inherited read-only
|
|
8
|
-
* property. Static blocks also preserve the class binding and `this`.
|
|
9
|
-
*
|
|
10
|
-
* Accessor collisions, special keys, inferred names, constructor parameter
|
|
11
|
-
* scope, and relocated `this`, `super`, or `new.target` can all expose a rewrite.
|
|
12
|
-
* Private or computed fields, derived classes, `with`, and a shadowed `Object`
|
|
13
|
-
* are therefore refused.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* // ◀️ before
|
|
17
|
-
* class A {
|
|
18
|
-
* x = 1;
|
|
19
|
-
* static z = 2;
|
|
20
|
-
* }
|
|
21
|
-
*
|
|
22
|
-
* // ▶️ after
|
|
23
|
-
* class A {
|
|
24
|
-
* constructor() {
|
|
25
|
-
* Object.defineProperty(this, "x", {
|
|
26
|
-
* value: 1,
|
|
27
|
-
* writable: true,
|
|
28
|
-
* enumerable: true,
|
|
29
|
-
* configurable: true
|
|
30
|
-
* });
|
|
31
|
-
* }
|
|
32
|
-
* static {
|
|
33
|
-
* Object.defineProperty(this, "z", {
|
|
34
|
-
* value: 2,
|
|
35
|
-
* writable: true,
|
|
36
|
-
* enumerable: true,
|
|
37
|
-
* configurable: true
|
|
38
|
-
* });
|
|
39
|
-
* }
|
|
40
|
-
* }
|
|
41
|
-
*/
|
|
42
|
-
export declare function rewriteClassFields(ast: File): void;
|
|
43
|
-
//# sourceMappingURL=rewrite-class-fields.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rewrite-class-fields.d.ts","sourceRoot":"","sources":["../../src/preparation/rewrite-class-fields.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAKxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAElD"}
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import traverse from '@babel/traverse';
|
|
2
|
-
import * as t from '@babel/types';
|
|
3
|
-
import { isInsideWith, isProtoKey } from '../utils/ast.js';
|
|
4
|
-
import { isPrimitiveLiteral } from '../utils/literal.js';
|
|
5
|
-
/**
|
|
6
|
-
* Moves safe instance fields into the constructor and safe static fields into
|
|
7
|
-
* static blocks. The whole class stays intact unless every field can be lowered.
|
|
8
|
-
*
|
|
9
|
-
* `Object.defineProperty` preserves CreateDataProperty semantics. A plain
|
|
10
|
-
* assignment could invoke an inherited setter or fail on an inherited read-only
|
|
11
|
-
* property. Static blocks also preserve the class binding and `this`.
|
|
12
|
-
*
|
|
13
|
-
* Accessor collisions, special keys, inferred names, constructor parameter
|
|
14
|
-
* scope, and relocated `this`, `super`, or `new.target` can all expose a rewrite.
|
|
15
|
-
* Private or computed fields, derived classes, `with`, and a shadowed `Object`
|
|
16
|
-
* are therefore refused.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* // ◀️ before
|
|
20
|
-
* class A {
|
|
21
|
-
* x = 1;
|
|
22
|
-
* static z = 2;
|
|
23
|
-
* }
|
|
24
|
-
*
|
|
25
|
-
* // ▶️ after
|
|
26
|
-
* class A {
|
|
27
|
-
* constructor() {
|
|
28
|
-
* Object.defineProperty(this, "x", {
|
|
29
|
-
* value: 1,
|
|
30
|
-
* writable: true,
|
|
31
|
-
* enumerable: true,
|
|
32
|
-
* configurable: true
|
|
33
|
-
* });
|
|
34
|
-
* }
|
|
35
|
-
* static {
|
|
36
|
-
* Object.defineProperty(this, "z", {
|
|
37
|
-
* value: 2,
|
|
38
|
-
* writable: true,
|
|
39
|
-
* enumerable: true,
|
|
40
|
-
* configurable: true
|
|
41
|
-
* });
|
|
42
|
-
* }
|
|
43
|
-
* }
|
|
44
|
-
*/
|
|
45
|
-
export function rewriteClassFields(ast) {
|
|
46
|
-
traverse(ast, visitor);
|
|
47
|
-
}
|
|
48
|
-
const FORBIDDEN_STATIC_KEYS = new Set([
|
|
49
|
-
'length',
|
|
50
|
-
'name',
|
|
51
|
-
'prototype',
|
|
52
|
-
'__proto__',
|
|
53
|
-
'caller',
|
|
54
|
-
'arguments',
|
|
55
|
-
]);
|
|
56
|
-
const visitor = {
|
|
57
|
-
Class(path) {
|
|
58
|
-
const memberPaths = path.get('body.body');
|
|
59
|
-
const instanceFields = [];
|
|
60
|
-
const staticFields = [];
|
|
61
|
-
let hasPrivateField = false;
|
|
62
|
-
let hasComputedAccessor = false;
|
|
63
|
-
const instanceAccessorKeys = new Set();
|
|
64
|
-
const staticAccessorKeys = new Set();
|
|
65
|
-
let ctorPath = null;
|
|
66
|
-
for (const memberPath of memberPaths) {
|
|
67
|
-
const member = memberPath.node;
|
|
68
|
-
if (t.isClassProperty(member)) {
|
|
69
|
-
;
|
|
70
|
-
(member.static ? staticFields : instanceFields).push(member);
|
|
71
|
-
}
|
|
72
|
-
else if (t.isClassPrivateProperty(member)) {
|
|
73
|
-
hasPrivateField = true;
|
|
74
|
-
}
|
|
75
|
-
else if (t.isClassMethod(member) && member.kind === 'constructor') {
|
|
76
|
-
ctorPath = memberPath;
|
|
77
|
-
}
|
|
78
|
-
else if (t.isClassMethod(member) && (member.kind === 'get' || member.kind === 'set')) {
|
|
79
|
-
const name = plainKeyName(member.key);
|
|
80
|
-
if (member.computed || name === null) {
|
|
81
|
-
hasComputedAccessor = true;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
;
|
|
85
|
-
(member.static ? staticAccessorKeys : instanceAccessorKeys).add(name);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (instanceFields.length === 0 && staticFields.length === 0) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (!canDesugar(path, {
|
|
93
|
-
instanceFields,
|
|
94
|
-
staticFields,
|
|
95
|
-
hasPrivateField,
|
|
96
|
-
hasComputedAccessor,
|
|
97
|
-
instanceAccessorKeys,
|
|
98
|
-
staticAccessorKeys,
|
|
99
|
-
ctorPath,
|
|
100
|
-
})) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
// Path methods keep Babel's queued sibling paths aligned after each edit.
|
|
104
|
-
for (const memberPath of memberPaths) {
|
|
105
|
-
const member = memberPath.node;
|
|
106
|
-
if (!t.isClassProperty(member)) {
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (member.static) {
|
|
110
|
-
memberPath.replaceWith(t.staticBlock([defineField(t.thisExpression(), member)]));
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
memberPath.remove();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (instanceFields.length > 0) {
|
|
117
|
-
const installs = instanceFields.map((field) => defineField(t.thisExpression(), field));
|
|
118
|
-
if (ctorPath) {
|
|
119
|
-
ctorPath.get('body').unshiftContainer('body', installs);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
path
|
|
123
|
-
.get('body')
|
|
124
|
-
.unshiftContainer('body', t.classMethod('constructor', t.identifier('constructor'), [], t.blockStatement(installs)));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
function canDesugar(path, c) {
|
|
130
|
-
if (c.hasPrivateField || c.hasComputedAccessor || path.node.superClass != null) {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
// `with` and outer bindings can redirect the synthesized `Object` reference.
|
|
134
|
-
if (isInsideWith(path) || objectIsShadowed(path, c.ctorPath)) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
if (c.instanceFields.length > 0 && c.ctorPath && !hasSimpleParams(c.ctorPath.node)) {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
for (const field of c.instanceFields) {
|
|
141
|
-
if (!instanceFieldIsSafe(field, c.ctorPath != null, c.instanceAccessorKeys)) {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
for (const field of c.staticFields) {
|
|
146
|
-
if (!staticFieldIsSafe(field, c.staticAccessorKeys)) {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
function objectIsShadowed(path, ctorPath) {
|
|
153
|
-
return (path.scope.getBinding('Object') != null ||
|
|
154
|
-
(ctorPath != null && ctorPath.scope.getBinding('Object') != null));
|
|
155
|
-
}
|
|
156
|
-
// ECMA-262 10.2.2 initializes base-class fields before parameter defaults.
|
|
157
|
-
// Moving fields into the body reverses that order for non-simple parameters.
|
|
158
|
-
function hasSimpleParams(ctor) {
|
|
159
|
-
return ctor.params.every((param) => t.isIdentifier(param));
|
|
160
|
-
}
|
|
161
|
-
function instanceFieldIsSafe(field, hasCtor, accessorKeys) {
|
|
162
|
-
if (field.computed || !isPlainKey(field.key) || isProtoKey(field.key)) {
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
if (shadowsAccessor(field.key, accessorKeys)) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
if (field.value != null && isAnonymousFunctionDefinition(field.value)) {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
if (hasCtor) {
|
|
172
|
-
// Only a literal cannot capture a constructor parameter or local.
|
|
173
|
-
return field.value == null || isPrimitiveLiteral(field.value);
|
|
174
|
-
}
|
|
175
|
-
return field.value == null || !initObservesMethodContext(field.value, false);
|
|
176
|
-
}
|
|
177
|
-
function staticFieldIsSafe(field, accessorKeys) {
|
|
178
|
-
if (field.computed || !isPlainKey(field.key) || isForbiddenStaticKey(field.key)) {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
if (shadowsAccessor(field.key, accessorKeys)) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
if (field.value == null) {
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
if (isAnonymousFunctionDefinition(field.value)) {
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
// Static blocks can change how these context-sensitive forms resolve.
|
|
191
|
-
return !containsPrivateName(field.value) && !initObservesMethodContext(field.value, true);
|
|
192
|
-
}
|
|
193
|
-
// CreateDataProperty ignores a same-named accessor. Lowering could reorder it.
|
|
194
|
-
function shadowsAccessor(key, accessorKeys) {
|
|
195
|
-
const name = plainKeyName(key);
|
|
196
|
-
return name !== null && accessorKeys.has(name);
|
|
197
|
-
}
|
|
198
|
-
function containsPrivateName(node) {
|
|
199
|
-
let found = false;
|
|
200
|
-
t.traverseFast(node, (child) => {
|
|
201
|
-
if (t.isPrivateName(child)) {
|
|
202
|
-
found = true;
|
|
203
|
-
}
|
|
204
|
-
return found ? t.traverseFast.stop : undefined;
|
|
205
|
-
});
|
|
206
|
-
return found;
|
|
207
|
-
}
|
|
208
|
-
// These descriptor flags match CreateDataProperty.
|
|
209
|
-
function defineField(target, field) {
|
|
210
|
-
return t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('defineProperty')), [
|
|
211
|
-
target,
|
|
212
|
-
t.stringLiteral(plainKeyName(field.key)),
|
|
213
|
-
t.objectExpression([
|
|
214
|
-
t.objectProperty(t.identifier('value'), fieldValue(field)),
|
|
215
|
-
t.objectProperty(t.identifier('writable'), t.booleanLiteral(true)),
|
|
216
|
-
t.objectProperty(t.identifier('enumerable'), t.booleanLiteral(true)),
|
|
217
|
-
t.objectProperty(t.identifier('configurable'), t.booleanLiteral(true)),
|
|
218
|
-
]),
|
|
219
|
-
]));
|
|
220
|
-
}
|
|
221
|
-
function fieldValue(field) {
|
|
222
|
-
return field.value ?? t.unaryExpression('void', t.numericLiteral(0));
|
|
223
|
-
}
|
|
224
|
-
// Numeric and BigInt keys both pass through ToPropertyKey, so `1` and `1n`
|
|
225
|
-
// name `"1"`.
|
|
226
|
-
function plainKeyName(key) {
|
|
227
|
-
if (t.isIdentifier(key)) {
|
|
228
|
-
return key.name;
|
|
229
|
-
}
|
|
230
|
-
if (t.isStringLiteral(key)) {
|
|
231
|
-
return key.value;
|
|
232
|
-
}
|
|
233
|
-
if (t.isNumericLiteral(key) || t.isBigIntLiteral(key)) {
|
|
234
|
-
return String(key.value);
|
|
235
|
-
}
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
function isPlainKey(key) {
|
|
239
|
-
return plainKeyName(key) !== null;
|
|
240
|
-
}
|
|
241
|
-
function isForbiddenStaticKey(key) {
|
|
242
|
-
if (t.isIdentifier(key) || t.isStringLiteral(key)) {
|
|
243
|
-
return FORBIDDEN_STATIC_KEYS.has(plainKeyName(key));
|
|
244
|
-
}
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
// A descriptor would infer `"value"` instead of the field key as `.name`.
|
|
248
|
-
function isAnonymousFunctionDefinition(node) {
|
|
249
|
-
return (t.isArrowFunctionExpression(node) ||
|
|
250
|
-
(t.isFunctionExpression(node) && node.id == null) ||
|
|
251
|
-
(t.isClassExpression(node) && node.id == null));
|
|
252
|
-
}
|
|
253
|
-
// Relocation changes `new.target`, `super`, and static `this`. Nested non-arrow
|
|
254
|
-
// functions rebind them and do not count.
|
|
255
|
-
function initObservesMethodContext(node, forbidThis) {
|
|
256
|
-
let found = false;
|
|
257
|
-
t.traverseFast(node, (child) => {
|
|
258
|
-
if (t.isFunction(child) && !t.isArrowFunctionExpression(child)) {
|
|
259
|
-
return t.traverseFast.skip;
|
|
260
|
-
}
|
|
261
|
-
if (t.isSuper(child) ||
|
|
262
|
-
(t.isMetaProperty(child) && child.meta.name === 'new' && child.property.name === 'target') ||
|
|
263
|
-
(forbidThis && t.isThisExpression(child))) {
|
|
264
|
-
found = true;
|
|
265
|
-
}
|
|
266
|
-
return found ? t.traverseFast.skip : undefined;
|
|
267
|
-
});
|
|
268
|
-
return found;
|
|
269
|
-
}
|
|
270
|
-
//# sourceMappingURL=rewrite-class-fields.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rewrite-class-fields.js","sourceRoot":"","sources":["../../src/preparation/rewrite-class-fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import traverse from '@babel/traverse'
|
|
2
|
-
import type { NodePath } from '@babel/traverse'
|
|
3
|
-
import * as t from '@babel/types'
|
|
4
|
-
import type { File } from '@babel/types'
|
|
5
|
-
|
|
6
|
-
import { isInsideWith, isProtoKey } from 'src/utils/ast'
|
|
7
|
-
import { isPrimitiveLiteral } from 'src/utils/literal'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Moves safe instance fields into the constructor and safe static fields into
|
|
11
|
-
* static blocks. The whole class stays intact unless every field can be lowered.
|
|
12
|
-
*
|
|
13
|
-
* `Object.defineProperty` preserves CreateDataProperty semantics. A plain
|
|
14
|
-
* assignment could invoke an inherited setter or fail on an inherited read-only
|
|
15
|
-
* property. Static blocks also preserve the class binding and `this`.
|
|
16
|
-
*
|
|
17
|
-
* Accessor collisions, special keys, inferred names, constructor parameter
|
|
18
|
-
* scope, and relocated `this`, `super`, or `new.target` can all expose a rewrite.
|
|
19
|
-
* Private or computed fields, derived classes, `with`, and a shadowed `Object`
|
|
20
|
-
* are therefore refused.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // ◀️ before
|
|
24
|
-
* class A {
|
|
25
|
-
* x = 1;
|
|
26
|
-
* static z = 2;
|
|
27
|
-
* }
|
|
28
|
-
*
|
|
29
|
-
* // ▶️ after
|
|
30
|
-
* class A {
|
|
31
|
-
* constructor() {
|
|
32
|
-
* Object.defineProperty(this, "x", {
|
|
33
|
-
* value: 1,
|
|
34
|
-
* writable: true,
|
|
35
|
-
* enumerable: true,
|
|
36
|
-
* configurable: true
|
|
37
|
-
* });
|
|
38
|
-
* }
|
|
39
|
-
* static {
|
|
40
|
-
* Object.defineProperty(this, "z", {
|
|
41
|
-
* value: 2,
|
|
42
|
-
* writable: true,
|
|
43
|
-
* enumerable: true,
|
|
44
|
-
* configurable: true
|
|
45
|
-
* });
|
|
46
|
-
* }
|
|
47
|
-
* }
|
|
48
|
-
*/
|
|
49
|
-
export function rewriteClassFields(ast: File): void {
|
|
50
|
-
traverse(ast, visitor)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const FORBIDDEN_STATIC_KEYS = new Set([
|
|
54
|
-
'length',
|
|
55
|
-
'name',
|
|
56
|
-
'prototype',
|
|
57
|
-
'__proto__',
|
|
58
|
-
'caller',
|
|
59
|
-
'arguments',
|
|
60
|
-
])
|
|
61
|
-
|
|
62
|
-
const visitor = {
|
|
63
|
-
Class(path: NodePath<t.Class>) {
|
|
64
|
-
const memberPaths = path.get('body.body')
|
|
65
|
-
const instanceFields: t.ClassProperty[] = []
|
|
66
|
-
const staticFields: t.ClassProperty[] = []
|
|
67
|
-
let hasPrivateField = false
|
|
68
|
-
let hasComputedAccessor = false
|
|
69
|
-
const instanceAccessorKeys = new Set<string>()
|
|
70
|
-
const staticAccessorKeys = new Set<string>()
|
|
71
|
-
let ctorPath: NodePath<t.ClassMethod> | null = null
|
|
72
|
-
|
|
73
|
-
for (const memberPath of memberPaths) {
|
|
74
|
-
const member = memberPath.node
|
|
75
|
-
if (t.isClassProperty(member)) {
|
|
76
|
-
;(member.static ? staticFields : instanceFields).push(member)
|
|
77
|
-
} else if (t.isClassPrivateProperty(member)) {
|
|
78
|
-
hasPrivateField = true
|
|
79
|
-
} else if (t.isClassMethod(member) && member.kind === 'constructor') {
|
|
80
|
-
ctorPath = memberPath as NodePath<t.ClassMethod>
|
|
81
|
-
} else if (t.isClassMethod(member) && (member.kind === 'get' || member.kind === 'set')) {
|
|
82
|
-
const name = plainKeyName(member.key)
|
|
83
|
-
if (member.computed || name === null) {
|
|
84
|
-
hasComputedAccessor = true
|
|
85
|
-
} else {
|
|
86
|
-
;(member.static ? staticAccessorKeys : instanceAccessorKeys).add(name)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (instanceFields.length === 0 && staticFields.length === 0) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
if (
|
|
95
|
-
!canDesugar(path, {
|
|
96
|
-
instanceFields,
|
|
97
|
-
staticFields,
|
|
98
|
-
hasPrivateField,
|
|
99
|
-
hasComputedAccessor,
|
|
100
|
-
instanceAccessorKeys,
|
|
101
|
-
staticAccessorKeys,
|
|
102
|
-
ctorPath,
|
|
103
|
-
})
|
|
104
|
-
) {
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Path methods keep Babel's queued sibling paths aligned after each edit.
|
|
109
|
-
for (const memberPath of memberPaths) {
|
|
110
|
-
const member = memberPath.node
|
|
111
|
-
if (!t.isClassProperty(member)) {
|
|
112
|
-
continue
|
|
113
|
-
}
|
|
114
|
-
if (member.static) {
|
|
115
|
-
memberPath.replaceWith(t.staticBlock([defineField(t.thisExpression(), member)]))
|
|
116
|
-
} else {
|
|
117
|
-
memberPath.remove()
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (instanceFields.length > 0) {
|
|
122
|
-
const installs = instanceFields.map((field) => defineField(t.thisExpression(), field))
|
|
123
|
-
if (ctorPath) {
|
|
124
|
-
ctorPath.get('body').unshiftContainer('body', installs)
|
|
125
|
-
} else {
|
|
126
|
-
path
|
|
127
|
-
.get('body')
|
|
128
|
-
.unshiftContainer(
|
|
129
|
-
'body',
|
|
130
|
-
t.classMethod(
|
|
131
|
-
'constructor',
|
|
132
|
-
t.identifier('constructor'),
|
|
133
|
-
[],
|
|
134
|
-
t.blockStatement(installs),
|
|
135
|
-
),
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
interface Collected {
|
|
143
|
-
instanceFields: t.ClassProperty[]
|
|
144
|
-
staticFields: t.ClassProperty[]
|
|
145
|
-
hasPrivateField: boolean
|
|
146
|
-
hasComputedAccessor: boolean
|
|
147
|
-
instanceAccessorKeys: Set<string>
|
|
148
|
-
staticAccessorKeys: Set<string>
|
|
149
|
-
ctorPath: NodePath<t.ClassMethod> | null
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function canDesugar(path: NodePath<t.Class>, c: Collected): boolean {
|
|
153
|
-
if (c.hasPrivateField || c.hasComputedAccessor || path.node.superClass != null) {
|
|
154
|
-
return false
|
|
155
|
-
}
|
|
156
|
-
// `with` and outer bindings can redirect the synthesized `Object` reference.
|
|
157
|
-
if (isInsideWith(path) || objectIsShadowed(path, c.ctorPath)) {
|
|
158
|
-
return false
|
|
159
|
-
}
|
|
160
|
-
if (c.instanceFields.length > 0 && c.ctorPath && !hasSimpleParams(c.ctorPath.node)) {
|
|
161
|
-
return false
|
|
162
|
-
}
|
|
163
|
-
for (const field of c.instanceFields) {
|
|
164
|
-
if (!instanceFieldIsSafe(field, c.ctorPath != null, c.instanceAccessorKeys)) {
|
|
165
|
-
return false
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
for (const field of c.staticFields) {
|
|
169
|
-
if (!staticFieldIsSafe(field, c.staticAccessorKeys)) {
|
|
170
|
-
return false
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return true
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function objectIsShadowed(
|
|
177
|
-
path: NodePath<t.Class>,
|
|
178
|
-
ctorPath: NodePath<t.ClassMethod> | null,
|
|
179
|
-
): boolean {
|
|
180
|
-
return (
|
|
181
|
-
path.scope.getBinding('Object') != null ||
|
|
182
|
-
(ctorPath != null && ctorPath.scope.getBinding('Object') != null)
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ECMA-262 10.2.2 initializes base-class fields before parameter defaults.
|
|
187
|
-
// Moving fields into the body reverses that order for non-simple parameters.
|
|
188
|
-
function hasSimpleParams(ctor: t.ClassMethod): boolean {
|
|
189
|
-
return ctor.params.every((param) => t.isIdentifier(param))
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function instanceFieldIsSafe(
|
|
193
|
-
field: t.ClassProperty,
|
|
194
|
-
hasCtor: boolean,
|
|
195
|
-
accessorKeys: Set<string>,
|
|
196
|
-
): boolean {
|
|
197
|
-
if (field.computed || !isPlainKey(field.key) || isProtoKey(field.key)) {
|
|
198
|
-
return false
|
|
199
|
-
}
|
|
200
|
-
if (shadowsAccessor(field.key, accessorKeys)) {
|
|
201
|
-
return false
|
|
202
|
-
}
|
|
203
|
-
if (field.value != null && isAnonymousFunctionDefinition(field.value)) {
|
|
204
|
-
return false
|
|
205
|
-
}
|
|
206
|
-
if (hasCtor) {
|
|
207
|
-
// Only a literal cannot capture a constructor parameter or local.
|
|
208
|
-
return field.value == null || isPrimitiveLiteral(field.value)
|
|
209
|
-
}
|
|
210
|
-
return field.value == null || !initObservesMethodContext(field.value, false)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function staticFieldIsSafe(field: t.ClassProperty, accessorKeys: Set<string>): boolean {
|
|
214
|
-
if (field.computed || !isPlainKey(field.key) || isForbiddenStaticKey(field.key)) {
|
|
215
|
-
return false
|
|
216
|
-
}
|
|
217
|
-
if (shadowsAccessor(field.key, accessorKeys)) {
|
|
218
|
-
return false
|
|
219
|
-
}
|
|
220
|
-
if (field.value == null) {
|
|
221
|
-
return true
|
|
222
|
-
}
|
|
223
|
-
if (isAnonymousFunctionDefinition(field.value)) {
|
|
224
|
-
return false
|
|
225
|
-
}
|
|
226
|
-
// Static blocks can change how these context-sensitive forms resolve.
|
|
227
|
-
return !containsPrivateName(field.value) && !initObservesMethodContext(field.value, true)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// CreateDataProperty ignores a same-named accessor. Lowering could reorder it.
|
|
231
|
-
function shadowsAccessor(key: t.Node, accessorKeys: Set<string>): boolean {
|
|
232
|
-
const name = plainKeyName(key)
|
|
233
|
-
return name !== null && accessorKeys.has(name)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function containsPrivateName(node: t.Node): boolean {
|
|
237
|
-
let found = false
|
|
238
|
-
t.traverseFast(node, (child) => {
|
|
239
|
-
if (t.isPrivateName(child)) {
|
|
240
|
-
found = true
|
|
241
|
-
}
|
|
242
|
-
return found ? t.traverseFast.stop : undefined
|
|
243
|
-
})
|
|
244
|
-
return found
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// These descriptor flags match CreateDataProperty.
|
|
248
|
-
function defineField(target: t.Expression, field: t.ClassProperty): t.ExpressionStatement {
|
|
249
|
-
return t.expressionStatement(
|
|
250
|
-
t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('defineProperty')), [
|
|
251
|
-
target,
|
|
252
|
-
t.stringLiteral(plainKeyName(field.key)!),
|
|
253
|
-
t.objectExpression([
|
|
254
|
-
t.objectProperty(t.identifier('value'), fieldValue(field)),
|
|
255
|
-
t.objectProperty(t.identifier('writable'), t.booleanLiteral(true)),
|
|
256
|
-
t.objectProperty(t.identifier('enumerable'), t.booleanLiteral(true)),
|
|
257
|
-
t.objectProperty(t.identifier('configurable'), t.booleanLiteral(true)),
|
|
258
|
-
]),
|
|
259
|
-
]),
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function fieldValue(field: t.ClassProperty): t.Expression {
|
|
264
|
-
return field.value ?? t.unaryExpression('void', t.numericLiteral(0))
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Numeric and BigInt keys both pass through ToPropertyKey, so `1` and `1n`
|
|
268
|
-
// name `"1"`.
|
|
269
|
-
function plainKeyName(key: t.Node): string | null {
|
|
270
|
-
if (t.isIdentifier(key)) {
|
|
271
|
-
return key.name
|
|
272
|
-
}
|
|
273
|
-
if (t.isStringLiteral(key)) {
|
|
274
|
-
return key.value
|
|
275
|
-
}
|
|
276
|
-
if (t.isNumericLiteral(key) || t.isBigIntLiteral(key)) {
|
|
277
|
-
return String(key.value)
|
|
278
|
-
}
|
|
279
|
-
return null
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function isPlainKey(key: t.Node): boolean {
|
|
283
|
-
return plainKeyName(key) !== null
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function isForbiddenStaticKey(key: t.Node): boolean {
|
|
287
|
-
if (t.isIdentifier(key) || t.isStringLiteral(key)) {
|
|
288
|
-
return FORBIDDEN_STATIC_KEYS.has(plainKeyName(key)!)
|
|
289
|
-
}
|
|
290
|
-
return false
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// A descriptor would infer `"value"` instead of the field key as `.name`.
|
|
294
|
-
function isAnonymousFunctionDefinition(node: t.Node): boolean {
|
|
295
|
-
return (
|
|
296
|
-
t.isArrowFunctionExpression(node) ||
|
|
297
|
-
(t.isFunctionExpression(node) && node.id == null) ||
|
|
298
|
-
(t.isClassExpression(node) && node.id == null)
|
|
299
|
-
)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Relocation changes `new.target`, `super`, and static `this`. Nested non-arrow
|
|
303
|
-
// functions rebind them and do not count.
|
|
304
|
-
function initObservesMethodContext(node: t.Node, forbidThis: boolean): boolean {
|
|
305
|
-
let found = false
|
|
306
|
-
t.traverseFast(node, (child) => {
|
|
307
|
-
if (t.isFunction(child) && !t.isArrowFunctionExpression(child)) {
|
|
308
|
-
return t.traverseFast.skip
|
|
309
|
-
}
|
|
310
|
-
if (
|
|
311
|
-
t.isSuper(child) ||
|
|
312
|
-
(t.isMetaProperty(child) && child.meta.name === 'new' && child.property.name === 'target') ||
|
|
313
|
-
(forbidThis && t.isThisExpression(child))
|
|
314
|
-
) {
|
|
315
|
-
found = true
|
|
316
|
-
}
|
|
317
|
-
return found ? t.traverseFast.skip : undefined
|
|
318
|
-
})
|
|
319
|
-
return found
|
|
320
|
-
}
|