Split out from #26919 to reduce the size of the diff on that PR.
That PR requires `popcnt` CPU feature for SIMD implementation. Alter all `#[cfg(...)]` blocks to include `target_feature = "popcnt"`.
`oxc_lexer` has 2 implementations:
1\. SIMD-based on x86_64 with AVX2.
2\. Scalar/SWAR fallback which works on all platforms.
Both produce the same output.
This PR enables running the lexer conformance on either implementation. Which implementation is tested depends on what build flags are passed to `cargo coverage`.
It turns out that it's possible to test the SIMD implementation on Mac by compiling as x86_64, and running it under Rosetta 2.
This PR also adds `just` recipes to run tests and conformance on either implementation:
- `just test-lexer`
- `just test-lexer-simd`
- `just conformance-lexer`
- `just conformance-lexer-simd`
These commands should work correctly on any of Linux x86, Windows x86, Mac aarch64.
Adds linter call count tracking to provide some durable evidence of call count reductions. This does not include the actual rule timings so that it is consistent across machines.
## Summary
- Remove `--workspace` flag from cargo aliases in `.cargo/config.toml`
- Remove `--workspace` flag from CI workflow commands
The workspace has no `default-members` set, so cargo commands run from the workspace root already operate on all members by default, making `--workspace` redundant.
## Test plan
- CI will verify the changes work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Adds support for formatting embedded languages (CSS, GraphQL, HTML, Markdown) in JavaScript/TypeScript template literals using Prettier via NAPI bindings.
## Motivation
JavaScript/TypeScript developers often embed CSS, GraphQL queries, HTML, and Markdown in their code using tagged template literals. Without proper formatting support, these embedded languages remain unformatted, leading to inconsistent code style and reduced readability.
This PR enables oxfmt to format these embedded languages using Prettier, providing a seamless formatting experience similar to Prettier's own embedded language support.
## Changes
### Core Functionality
- **Embedded language detection**: Recognizes `css`, `styled`, `gql`, `graphql`, `html`, `md`, and `markdown` template tags
- **Prettier integration**: Uses `@prettier/sync` for synchronous formatting of embedded code
- **NAPI bridge**: Rust-to-JavaScript interop using NAPI ThreadsafeFunction
- **Graceful fallback**: Returns original code if formatting fails or tag is unsupported
### Implementation Details
**Rust side** (`crates/oxc_formatter/`, `apps/oxfmt/src/prettier_plugins/`):
- New `EmbeddedFormatter` trait with callback-based API
- NAPI bindings using `FnArgs` pattern for clean multi-argument calls
- Template formatter enhancement to detect and format tagged templates
- Proper indentation handling: splits Prettier output into lines, uses `hard_line_break()` separators, wraps in `indent()` for context-aware indentation
- Arena allocator pattern to avoid borrow checker conflicts
**JavaScript side** (`apps/oxfmt/src-js/`):
- TypeScript bindings with clean signatures: `formatEmbeddedCode(tagName: string, code: string)`
- Prettier configuration: 80 char width, 2 space indent, semicolons, double quotes
- Tag-to-parser mapping for supported languages
- Error handling with console logging and fallback
**Testing**:
- E2E test suite using Vitest (8 test cases)
- Test fixtures for each supported language
- Snapshot testing with timing normalization for stability
- All tests passing consistently
## Examples
**Before** (unformatted):
```js
const styles = css`.button { color: red; background: blue; }`;
```
**After** (formatted with proper indentation):
```js
const styles = css`
.button {
color: red;
background: blue;
}
`;
```
**Supported tags:**
```js
// CSS
const styles = css`...`;
const component = styled`...`;
// GraphQL
const query = gql`...`;
const schema = graphql`...`;
// HTML
const template = html`...`;
// Markdown
const docs = md`...`;
const readme = markdown`...`;
```
## Testing
```bash
# Run oxfmt tests
just oxfmt
# Watch mode for development
just watch-oxfmt
```
All 8 E2E tests pass:
- ✓ embedded_css
- ✓ embedded_graphql
- ✓ embedded_html
- ✓ embedded_markdown
- ✓ mixed_embedded
- ✓ no_embedded
- ✓ unsupported_tag
- ✓ check_mode
## Related
Related to #13427
## Future Work
Potential enhancements:
- Support for additional embedded languages (SQL, YAML, etc.)
- Custom Prettier configuration via oxfmt config
- Performance optimization for large embedded blocks
- Integration with language servers for inline diagnostics
Fix `just oxlint` and `just watch-oxlint`. They were broken because `oxlint` is now a NAPI package.
Remove `cargo oxlint` command, because `oxlint` needs to be built with NAPI-RS now.
- part of https://github.com/oxc-project/oxc/issues/12223
- supersedes stack: https://github.com/oxc-project/oxc/pull/12228
This PR adds the ability to add node type information to indicate what node types a lint rule acts on. The lint rule runner can use this information to optimize running lint rules by skipping nodes, files, or rules that don't apply.
This is a simple version that is focused on creating the framework for automatically generating the rule runner code. This is not the end of optimizations. Currently only 102 rules have node type information, while 471 rules have no node type information and will not be skipped. Adding node type information for more rules will improve performance. We may also be able to skip more nodes and files by being clever about how we use this information. For example, filtering out any rules which do not run on any node type, if the file contains no relevant node types for the rule.
- Adds a new `RuleRunner` trait which includes information needed for indicating whether a rule has node type info or not
- Adds a `oxc_linter_codegen` task which is used to generate the implementation of `RuleRunner` trait for all lint rules. This is mostly written by AI, so worth a bit of skepticism, but I've tried to manually verify the results and it looks good (just lacking more complex detection).
- Currently, only rules that contain a single top-level `if` statement (or chain of `else if`), or a single `match` statement will have their node type info generated. This should give us a high level of confidence, since these patterns are relatively easy to verify and identify, but it's only a subset of all rules. Next steps will be to add support for `let...else`
- Adjusts the main linting loop to use the node type information to skip rules for node types that don't apply
- Updates CI to include a check for any uncommitted linter codegen changes
---
## Benchmarks
In the latest version of this PR, CodSpeed shows an up to +13% increase in linter performance across large and small files. In the real-world, I've seen a ~5-15% improvement in performance, but in some cases close to zero for very small files. In either case, there appears to be little downside and a lot of potential upside here.
<img width="769" height="242" alt="Screenshot 2025-08-24 at 9 29 30 PM" src="https://github.com/user-attachments/assets/d2c430c4-17a9-4606-85d5-c66c734975d9" />
<img width="757" height="308" alt="Screenshot 2025-08-24 at 9 30 24 PM" src="https://github.com/user-attachments/assets/5508464f-de55-4f4e-9ddd-58f215c4ce85" />
<img width="976" height="368" alt="Screenshot 2025-08-24 at 9 34 52 PM" src="https://github.com/user-attachments/assets/203f83c7-46f3-49f1-a1a8-e18f7ec8483b" />
- related: https://github.com/oxc-project/backlog/issues/5
This PR adds a reliable method of tracking the number of allocations made while running the parser. This includes both arena allocations (via a new feature), as well as system allocations (by creating a new global allocator). Reductions in these numbers should correlate to real-world performance improvements that aren't quantified in CodSpeed currently. This will also help prevent regressions where we accidentally allocate lots more memory than we expect.
Originally I had included total system bytes allocated, but it was tricky to get this number to match exactly between platforms. I opted not try and make this perfect but instead use the total number of allocations which is a good proxy for bytes anyway.
* Fix `cargo benchmark` - previous it failed with an error.
* Add `just benchmark-one` to run a single benchmark e.g. `just
benchmark-one parser`.
* Simplify `default` feature in `tasks/benchmark/Cargo.toml`.