Oxc can shorten variable names and private class names, but it cannot shorten property names such as `obj._field`. This change adds optional property mangling. It replaces #23772 and gives bundlers a way to use the same property names across several files.
### Feature
- `include` selects names to mangle. `exclude` and `reserved` keep names unchanged.
- The cache can give a property a fixed output name or keep it unchanged.
- The mangler supports member access, object and class keys, destructuring, optional chains, the left side of `in`, and JSX property names.
- `mangle_quoted` also handles strings and template literals used directly as property keys. `/* @__KEY__ */` and `/* #__KEY__ */` can mark one other string or template literal as a property key.
- Short names are assigned in a stable order. More common properties get shorter names. Existing and reserved names are avoided.
- Bundlers can collect names from several programs, create one shared map, and apply it to every program.
- Numeric keys, `__proto__`, `constructor`, `prototype`, TypeScript-only keys, and private names are never changed by this pass.
### Design
Property names are part of JavaScript syntax, not local scope. For this reason, the code lives in `oxc_minifier`. It only reuses the short-name generator from `oxc_mangler`.
For one program, the order is:
```text
collect names → assign names → rewrite once → compress → mangle variables and private names
```
Property names are rewritten before compression because compression can remove information about quotes and comments.
For several programs, a bundler collects names from each program, merges the results, assigns one shared map, and rewrites each program once. Collection can run in parallel. All programs must use the same options.
The shared map keeps property names consistent inside one build. The cache has a different job: it keeps fixed names and reservations across separate minify calls.
### Example
With `include: "^_"` and `mangle_quoted: true`:
```js
obj[`_field`] = 1;
obj._field = 2;
```
becomes:
```js
obj[`e`] = 1;
obj.e = 2;
```
### Limitation
- Property mangling is unsafe when other code still uses the old property name. Public APIs and names shared with external code, host APIs, imported namespace objects, or separate builds must be excluded or reserved.
- Quote handling is per use. Without `mangle_quoted`, `obj._field` may change while `obj["_field"]` does not.
- The mangler cannot find names built at runtime or stored in arbitrary strings. Code that uses `eval`, `Function`, or `with` must reserve any affected names.
- Compression may create a matching property after this pass has finished. For example, `'f' + 'oo_'` may later become `foo_` and will not be mangled.
- TypeScript enum reverse mappings are not supported because the transform creates quoted strings.
- Multi-program support is a caller API. The caller must collect every program that shares mangled properties before assigning names.
The public `oxc-minify` API is stacked in #24741. The downstream multi-chunk integration is shown in rolldown/rolldown#10374.
Supersedes #23772.
AI assistance: OpenAI Codex and Claude were used for research, implementation, review, and testing. The contributor is responsible for reviewing and understanding the changes before submission.
## Summary
Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.
- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).
## Breaking change
Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.
Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
fixes https://github.com/rolldown/rolldown/issues/4118fixes#10626
At present, there is no option to keep legal comments when minification is turn on.
This PR allows Codegen to set legal comments with minfication turned on, with the following behavior:
* Inline: only if the attached code is not removed
* Eof: move all legal comments to the end of file, regardless of where they appear
* Linked and External: saved into `CodegenReturn::legal_comments` for the caller to use, regardless of where they appear
Code gets moved around or removed if minifier is turned on, so some legal comments may disappear from the final output.
The recommended legal comment option is Eof.
---
For Rolldown to keep legal comments, it should set `LegalComment::Inline` for chunk codegen and `LegalComment::Eof` for minification codegen.
#10196 replaced the anti-pattern of `str.push_str(&format!("..."));` with `let _ = write!(str, "...");`.
However, this ignores the `Result` returned by `write!` macro. It's unspecified what happens when the `String` reaches capacity - it may return `Result::Err`, or may panic. Ensure we get a panic, rather than silently generating incorrect output by calling `unwrap()` on the `Result`.
This problem could never arise in practice on 64-bit systems because max capacity of `String` is enormous, but it's not impossible on 32-bit systems (e.g. WASM).
Replace `#[allow]` with `#[expect]` through the whole codebase.
This also surfaced many places where the `#[allow]` attributes were outdated/pointless and could be removed entirely.
Only places `#[allow]` remains are:
1. In generated code and macros, where lint errors may or may not be triggered depending on the generated code.
2. A few places where clippy malfunctions. These use e.g. `#[allow(unused, clippy::allow_attributes)]`.
It seems to be that the easiest way to rename variables is to use
rename_symbol from SymbolTable and to let it be applied during codegen -
this is what Mangler does.
This PR changes Codegen to accept (any) SymbolTable instead of just
Mangler itself, and for Mangler build output to be a new SymbolTable,
after consuming itself (which makes it clear at the type level if a
Mangler has been built or not).
This also moves the few symbol table helper methods from Mangler to
SymbolTable itself, and adds an example of Mangler use to it's
documentation.
Codegen dependencies now include semantic (which was transient by
mangler before). It's dependency on Mangler could be removed, though
I've left it to allow easy linking of docs (with_symbol_table points
users to Mangler, hopefully helps with migration?)
Adds `top_level` option which is similar to [terser's `toplevel`
option](https://terser.org/docs/cli-usage/#cli-mangle-options).
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This PR introduces two type alias to avoid the confusing const generic `pub struct Codegen<'a, const MINIFY: bool>`
* CodeGenerator - Code generator without whitespace removal.
* WhitespaceRemover - Code generator with whitespace removal.
Usage is changed to a builder pattern:
```rust
CodeGenerator::new()
.enable_comment(...)
.enable_sourcemap(...)
.build(&program);
```
- Adds option to `CodegenOptions` - `enable_typescript` to enable output
of TS.
- Stops skipping output that is TS when `enable_typescript` is enabled
- Adds TS support to
- Function
- FormalParameter
- BindingPattern
- Adds basic tests for TS generation
---------
Co-authored-by: Boshen <boshenc@gmail.com>