## Summary
Fixes#26097.
The minify function did not work on class private fields,because their
mappings were not forwarded to codegen:
```rs
class Foo {
#privateField = 1;
method() {
return this.#privateField;
}
}
```
And this PR is to make it match what's expected:
```rs
class Foo {
#e = 1;
method() {
return this.#e;
}
}
```
This follows up on #24741 and addresses API feedback received after it was merged.
### Feature
`mangleProps.include` and `mangleProps.exclude` now accept JavaScript `RegExp` values instead of strings.
The binding copies the regular expression source and flags before async minification starts, then compiles the pattern once with Rust's regex engine. Native and WASI bindings expose the same API. The core Rust minifier API is unchanged.
### Example
```js
mangleProps: {
include: /^_/,
exclude: /^__public/,
}
```
### Limitation
Matching uses Rust regex syntax. The `i`, `m`, `s`, and `u` flags are supported. Unsupported JavaScript syntax or flags are returned as option errors.
### AI assistance
OpenAI Codex was used for research, implementation, review, and testing. I reviewed and take responsibility for the changes.
The property mangler added in #24740 is not available through `oxc-minify`. This adds `mangleProps` for configuring it and `mangleCache` for reusing chosen property names.
### Feature
- `include` selects property names to mangle. `exclude` and `reserved` keep names unchanged.
- `quoted` also mangles quoted property names. `debug` produces readable output names.
- `cache` fixes a property to a chosen name. A `false` value keeps the original name.
- Property mangling works in both sync and async APIs. It is separate from identifier mangling.
- When property mangling is enabled and the call succeeds, the result includes the updated `mangleCache`.
- Invalid `mangleProps` regexes and cache entries are returned in `result.errors`.
### Design
The binding converts JavaScript values into core minifier options and results. The core minifier still chooses names and rewrites properties, so both APIs follow the same rules.
A parser error may leave an incomplete AST. In that case, property mangling is skipped and no partial cache is returned.
### Example
```js
const result = minifySync(
"test.js",
"let local; obj._often; obj._rare; obj._often;",
{
compress: false,
mangle: false,
mangleProps: { include: "^_" },
},
);
result.code; // "let local;obj.e;obj.t;obj.e;"
result.mangleCache; // { _often: "e", _rare: "t" }
```
### Limitation
- `include` and `exclude` use Rust regex syntax. They match anywhere unless the pattern includes anchors.
- Do not reuse the cache on already-mangled output. A mapping is not always safe to apply twice.
- The cache only remembers recorded mappings. It cannot find unchanged names in another input or in external code. Reserve, exclude, or pin those names before the first call.
- String cache targets must be valid JavaScript `IdentifierName` values and cannot be `__proto__`, `constructor`, or `prototype`. The original name `__proto__` cannot be a cache key.
AI assistance: OpenAI Codex and Claude were used for research, implementation, adversarial review, and verification. The contributor remains responsible for reviewing, understanding, and submitting the changes under the repository AI usage policy.
## Summary
close: #13067
Part of https://github.com/oxc-project/oxc/issues/19673
Depends on #20217.
Port known-globals lists from Rolldown to Oxc's side-effect detection:
- **Global identifiers** (Math, Array, console, DOM classes, etc.) are now considered side-effect-free to access via `is_known_global_identifier`, matching Rolldown's `GLOBAL_IDENT` set
- **Property reads** like `Math.PI`, `console.log`, `Object.keys` are considered side-effect-free via `is_known_global_property`
- **3-level chains** like `Object.prototype.hasOwnProperty` are supported via `is_known_global_property_deep`
## Test plan
- [x] Added tests for known global identifiers (Math, Array, Object, console, etc.)
- [x] Added tests for known global property reads (Math.PI, Object.keys, etc.)
- [x] Added tests for 3-level chains (Object.prototype.hasOwnProperty, etc.)
- [x] Existing minifier test expectations updated for improved side-effect detection
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(napi/minify): expose `treeshake` options
## Completed:
- [x] Understand the problem: Need to expose TreeShakeOptions to JavaScript users
- [x] Explore existing code structure and TreeShakeOptions in oxc_minifier
- [x] Build the project to ensure clean state
- [x] Add TreeShakeOptions struct with all fields
- [x] Update CompressOptions to accept optional treeshake field
- [x] Implement conversion from NAPI TreeShakeOptions to oxc_minifier::TreeShakeOptions
- [x] Build and verify TypeScript definitions are generated correctly
- [x] Add tests for treeshake options
- [x] Run all tests successfully
- [x] Format code with just fmt
- [x] Address all review feedback:
- Renamed TreeShakeOptionsNapi to TreeShakeOptions
- Changed property_read_side_effects to accept boolean | 'always'
- Changed @default from true to 'always' for property_read_side_effects
- Reverted From implementation back to use reference (From<&TreeShakeOptions>)
- Changed to TryFrom to properly handle validation errors
- Added validation for propertyReadSideEffects string values
- Fixed clippy lint for inline format args
## Changes Made:
1. Added `TreeShakeOptions` struct with fields:
- `annotations`: Whether to respect pure annotations (@__PURE__, #__NO_SIDE_EFFECTS__)
- `manual_pure_functions`: List of function names to treat as pure
- `property_read_side_effects`: Whether property reads have side effects (boolean | 'always', default: 'always')
- `unknown_global_side_effects`: Whether accessing global variables has side effects
2. Updated `CompressOptions` to include optional `treeshake` field
3. Implemented `TryFrom<&TreeShakeOptions>` trait with proper error handling for invalid values
4. Added validation that rejects invalid string values for propertyReadSideEffects
5. Added tests covering treeshake functionality including error cases
6. Fixed all lint issues
All tests pass successfully!
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
> Add bindings for treeshake option here:
> https://github.com/oxc-project/oxc/blob/3fbb307367a31817a297dee299fec580912675db/napi/minify/src/options.rs#L90
</details>
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
closes#13174
This should reduce sourcemap memory usage by a huge amount.
These tokens were added in esbuild for code coverage: https://github.com/evanw/esbuild/commit/c4d45e6b5766b1a1b56bf24b7dadb240de91332b
But esbuild has an optimization to not generate these tokens when `}` is not on the same line
```
if class.CloseBraceLoc.Start > class.BodyLoc.Start {
p.addSourceMapping(class.CloseBraceLoc)
}
```
We should revisit these tokens later in the future.
Just noticed that we can use a static list here. I think this has no downsides. To have better compression, we can actually count the characters, but I guess there won't be much difference normally.
Changed the mangler to reuse variable names where possible.
This will reduce the code size as shorter variable names can be used in
more places. But requires global information and limits parallelism in a
single file and requires more memory.
---------
Co-authored-by: Boshen <boshenc@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>