Commit Graph

54 Commits

Author SHA1 Message Date
leaysgur 876fbe30f1 fix(oxfmt): expand Fill parts in tsx-in-vue (#26427)
Fixes #26398, closes #26399.

---

Our Rust printer knows how to expand `Fill` with `Interned`, but Prettier printer does not.
2026-09-08 01:29:38 +00:00
leaysgur 1a83a8ddb2 fix(oxfmt): mirror printer line suppression and restore dedent-to-root (#25573)
Fixes #25568, #25569
2026-08-13 03:50:19 +00:00
leaysgur 0fa91283fd refactor(formatter,formatter_tests): move out prettier JS,TS,JSDoc conformance from tasks/ (#25477)
Migration from tasks/prettier_conformance to each crate test using oxc_formatter_tests, for JS/TS and JSDoc.
2026-08-12 00:48:32 +00:00
leaysgur 95dc917441 fix(oxfmt): drop IR Space at line start for js-in-xxx (#25460)
Closes #25042
2026-08-10 04:24:03 +00:00
leaysgur ab52a593f3 fix(formatter): format xxx-in-js inside JSDoc js fence (#25414)
Such as CSS-in-JS-in-JSDoc_Markdown-in-JS. 😇
2026-08-09 14:49:15 +00:00
leaysgur 1a2c64a356 fix(formatter,oxfmt): apply effective print width for JSDoc fence (#25413)
As JSDoc is always contained within the ` * ` fenced comments, the `printWidth` option should not have been used as is.

The dedicated `jsdocPrintWidth` option has not yet been implemented. #24633
2026-08-09 14:49:14 +00:00
leaysgur 2eaede9b0b fix(formatter_core): unify leading-BOM handlings (#25340)
Follow up on #25333.
2026-08-09 14:32:09 +00:00
leaysgur fd02a8956e feat(oxfmt): dispatch yaml-in-css(frontmatter) to oxc_formatter_yaml (#25336)
Using the `Dispatcher` set up so far, detect the YAML front matter and process it using `oxc_formatter_yaml`.
2026-08-09 14:15:05 +00:00
leaysgur 567089f3c5 refactor(oxfmt): route JSDoc fence through the dispatcher (#25334)
Markdown code fences can also be written in JSDoc, and other languages can be formatted as inline code within them.
2026-08-09 13:54:12 +00:00
leaysgur 52b146f025 refactor(formatter_core): share split_bom helper (#25333)
In order to standardise the handling of front matter, it was also necessary to standardise the handling of the BOM, which may appear before the FM.
2026-08-09 13:06:35 +00:00
leaysgur a9e76e9e1f fix(oxfmt): rework tsx-in-vue support (#25106)
Follow-up to #25063.

tsx-in-vue was supported in #25063 with a parse-retry (ts fails → retry as tsx), chosen to keep the common ts path single-parse.

However, this leaves a hole: a `lang="tsx"` block without JSX parses fine as plain ts, so the retry never fires and the lone generic comma is removed:

```vue
<script setup lang="tsx">
const identity = <T,>(x: T) => x; // → <T>(x: T) => x, breaks as TS17008
</script>
```

Since parse failure fundamentally cannot detect this, the only fix is to scan the `lang` declaration itself.

The JS host now scans the SFC once per file and passes `_oxfmtVueScriptLang: "tsx"` down to `textToDoc()`. This makes the retry obsolete, so it is removed.

This PR also settles the comma policy: keep it only where it is load-bearing.

- JSX grammar (`<T>` would be a JSX opener)
- and `.mts/.cts` (TS7060, #18928)

and remove it everywhere else, keyed on the grammar, regardless of context.

Deliberate divergence: Prettier keys on filepath and keeps the comma in ts-in-vue/svelte (while its own ts-in-md embed uses `dummy.ts` as `filepath` and removes it). Plain-TS sources now behave identically wherever they live.
2026-07-30 05:27:07 +00:00
leaysgur 1b57f783fb feat(oxfmt): support tsx-in-vue (#25063)
Part of #16608, closes #25046.

---

Even with a simple regexp, I don't want to impact the performance of the vast majority of ts-in-vue paths.

With this approach, only tsx-in-vue use cases will be affected, and even that will be kept to a minimum since it can be handled entirely on the Rust side. (JS <-> Rust roundtrip is also slow)
2026-07-29 07:27:43 +00:00
leaysgur 0c16cb5aba feat(oxfmt)!: Format parser:yaml files by oxc_formatter_yaml (#24890)
Format `.yaml`, `.yml` and others by `oxc_formatter_yaml`.

Also handle maybe-json-or-yaml files like `.prettierrc`.
2026-07-28 06:16:26 +00:00
leaysgur 9bf5c71ac7 refactor(formatter_core): introduce exact_line_breaks builder (#24865)
Introduce `exact_line_breaks(count)` IR builder.

This produces a line element that prints exactly `count` line breaks, exempt from the printer's hardline collapsing / empty-line capping.

Blank runs inside verbatim values (YAML block/flow scalars, GraphQL block strings) are the value itself and must not be normalized.
Previously this was emulated by emitting raw `\n` text followed by a re-arming `hard_line_break()`..., hack.

Also removed the printer behavior that trims end of line whitespaces.
2026-07-24 04:05:12 +00:00
leaysgur 6fe866af30 fix(oxfmt): keep tailwind classes glued to template expr with preserveWhitespace (#24609)
Fixes #24464

When `preserveWhitespace` was enabled, the ignore process was being skipped.
2026-07-17 01:07:45 +00:00
leaysgur eeabc4a55f fix(formatter_css): bail on EOF-recovered parse errors (#24282)
Also updated the code to reflect the changes in `oxc-css-parser` 0.0.6.
2026-07-08 02:17:08 +00:00
leaysgur 4f4313ef47 feat(formatter_css): update oxc-css-parser 0.0.5 (#24120)
Fixes #24000, #24057, and #24116.

Updating `oxc-css-parser` to 0.0.4 involved a massive amount of fixes, making it a major update.
However, this should allow us to catch cases that were previously missed (even potentially).
2026-07-03 14:06:30 +00:00
leaysgur 0ccd8a14b7 feat(formatter_graphql): update oxc-graphql-parser 0.0.5 (#24106)
Part of #23923

Supports more syntax like:

- Fragment arguments
- Extends directives
2026-07-03 10:11:20 +00:00
leaysgur 7d663d3fd0 chore(oxfmt): update prettier to 3.9.1 (#23931)
Part of https://github.com/oxc-project/oxc/issues/23923
2026-07-03 07:12:06 +00:00
leaysgur dbf27196fc chore(formatter_css): use oxc-css-parser (#23920) 2026-06-29 04:15:34 +00:00
leaysgur 2dc451ca8b chore(formatter_graphql): use oxc-graphql-parser (#23919) 2026-06-29 04:15:34 +00:00
leaysgur 259e0cdf60 feat(oxfmt,formatter_graphql)!: support draft syntax with removing prettier fallback (#23326)
- Fork `apollo-rs` to be compatible with Prettier(`latest` for now)
  - https://github.com/leaysgur/apollo-rs
- By doing this, Prettier fallback is no longer needed
- And now all prettier_conformance are passed, no parse error skip

> [!WARNING]
> TODO: Move fork under `oxc-project` org and replace refs
2026-06-29 03:15:25 +00:00
leaysgur 43aa5fe1ef refactor(formatter_css): update oxc_formatter_css to support sortTailwindcss option (#23323)
- Before this PR: If `sortTailwindcss` option is enabled for CSS/LESS/SCSS, it was formatted by Prettier
- After this PR: `oxc_formatter_css` also handles `sortTailwindcss` as like `oxc_formatter` does
2026-06-29 03:15:24 +00:00
leaysgur 9d2a9579c1 refactor(oxfmt): use Rust formatters for jsdoc code fence (#23322)
In addition to basic embedded (e.g. css-in-js), JSDoc also contain code fence as markdown.

This PR makes JSDoc code fence also formatted by `oxc_formatter_(css|graphql)` if specified.
2026-06-29 03:15:24 +00:00
leaysgur accbc49def feat(oxfmt)!: format parser:css,less,scss files + css-in-js by oxc_formatter_css (#23321)
- Use `oxc_formatter_css` from Oxfmt to handle CSS/LESS/SCSS files
- css-in-js is also handled by `oxc_formatter_css`
  - But it will fallback to Prettier if formatting failed
  - No fallback for no-embedded path
- At the point of this PR, it will fallback to Prettier when tailwind is required to format

NOTE: Both fallback will be removed in later PR.

In that sense, as a result of this series of PRs, Oxfmt's CSS support will no longer be 100% compatible compared to Prettier.

Since the parsers used are also different, it will no longer be possible to support certain postcss-plugin-specific syntax, invalid syntax or legacy syntax.

> [!WARNING]
> TODO: Move fork under `oxc-project` org and replace refs
2026-06-29 03:15:24 +00:00
leaysgur 01de9ece8b feat(oxfmt): format parser:graphql files by oxc_formatter_graphql (#23318)
- Use `oxc_formatter_graphql` from Oxfmt to handle `.gql` and `.graphql` files
- At point of this PR, gql-in-js is still handled by Prettier

As described in #23317, Prettier supports more syntax than ours, so for now fallback to Prettier when `oxc_formatter_graphql` failed to format.

NOTE: This fallback will be removed in later PR.
2026-06-29 02:55:30 +00:00
leaysgur 5d1117a707 chore(oxfmt): update svelte@5.56 to support declaration tags (#23108)
Follow up on #23087 + #22993, thanks @firatciftci !

NOTE: This is internal updates. If users want it, need to update `svelte` deps by yourself.
2026-06-08 03:47:16 +00:00
leaysgur 2aedd52ce6 fix(oxfmt): avoid JS promise rejects for all TSFN call sites (#23107)
Fixes #20525, (thanks @oxura !)

```sh
# Many files that route to the Prettier `formatFile` callback and fail to parse
mkdir -p /tmp/repro
for i in $(seq 1 500); do printf '<template><div></template>' > /tmp/repro/broken$i.vue; done

# Run repeatedly with default concurrency
for run in $(seq 1 10); do node apps/oxfmt/dist/cli.js --write /tmp/repro; done
```

Within a few runs it crashes non-deterministically (exit codes varied: 133 / 138 / 139, and sometimes 2 = clean error report), with the same fatal as #20525:

```
# Fatal error in , line 0
# Check failed: object_ != kGlobalHandleZapValue.   (or: node->IsInUse())
...
napi_reference_unref
<napi::error::Error as ...Drop>::drop
core::ptr::drop_in_place<napi::error::Error>
oxfmt::core::external_formatter::wrap_format_file::{{closure}}
```

Each broken file makes the `formatFile` callback reject; the resulting `napi::Error` is dropped on the TSFN await path and reaches `napi_reference_unref` during teardown → V8 fatal check.

After this fix (callback resolves errors as data), the same workload runs clean.
2026-06-08 02:54:09 +00:00
leaysgur 6eda4ebad8 test(oxfmt): Add tests for #22780 (#22815)
Refs: #22780
2026-05-29 01:26:11 +00:00
leaysgur 47fb154918 test(oxfmt): Add tests and conformance (#21832) 2026-05-11 01:24:38 +00:00
leaysgur 7faba51ae4 refactor(oxfmt): Use FormatConfig as SoT (#21981)
In Oxfmt, there is only one config file, but there were multiple conversion paths to the specific options used by subsequent formatters.

For example, it would generate `FormatOptions` for `oxc_formatter`, while assembling the necessary `JSON` for `prettier`.

There was a lack of consistency here, as some paths referenced the parsed `FormatConfig` while others referenced the raw JSON of `Oxfmtrc`. This inconsistency led to issues like the one mentioned in #21919.

In this PR, I have established `FormatConfig` as the single SoT, ensuring that all options are derived from it.
2026-05-01 01:52:26 +00:00
leaysgur ce561a2d79 test(oxfmt): Place all format tests under the test/api dir (#21462) 2026-04-15 09:13:39 +00:00
leaysgur 098db4649e test(oxfmt): Add css-in-jsdoc-in-js-in-vue tests (#20646)
😂
2026-03-23 09:00:47 +00:00
Dunqing 4fec907ad5 feat(formatter): add JSDoc comment formatting support (#19828)
## Summary

Implements native JSDoc comment formatting in oxfmt, porting behavior from [prettier-plugin-jsdoc](https://github.com/hosseinmd/prettier-plugin-jsdoc) (v1.8.0). Tracked in #19702.

### Conformance

**145/145 (100%)** compatibility with prettier-plugin-jsdoc test suite.

- 1 fixture intentionally skipped (`descriptions/032-jsx-tsx-css`) — requires embedded CSS/HTML formatter callbacks not available in the standalone conformance runner
- Run with: `cargo run -p oxc_prettier_conformance -- --jsdoc`

Prettier conformance (non-JSDoc):
- **JS**: 746/753 (99.07%)
- **TS**: 591/601 (98.34%)

### Real-World Repository Testing

Validated against 5 real-world repositories (7,542 JSDoc tags total) using Prettier 3.8.1 + prettier-plugin-jsdoc 1.8.0 as baseline:

| Repository | JSDoc Tags | Files with Diffs |
|------------|-----------|-----------------|
| evolu      | 134       | 13              |
| wxt        | 1,183     | 1               |
| typedoc    | 792       | 11              |
| Chart.js   | 1,276     | 4               |
| svelte     | 4,157     | 5               |
| **Total**  | **7,542** | **34**          |

All 34 remaining diffs are **intentional design differences**, not bugs:
- `{@link}` kept atomic (upstream breaks across lines) — ~11 files
- `{@includeCode}` placed on own line (upstream splits tag syntax) — 3 files
- Sub-list continuation indent normalized to 4-space — 5 files
- `?Type` expanded to `Type | null` — 1 file
- Minor line-break position differences — 5 files
- Double-space normalized to single space — 1 file

10 upstream bugs documented in `tasks/prettier_conformance/jsdoc/upstream-jsdoc-bugs.md` — oxfmt intentionally produces correct output where the upstream plugin has known issues.

### Performance

Measured with `hyperfine` using `oxfmt --check` on real-world repos (16 threads):

| Repository | Without JSDoc | With JSDoc | Overhead    |
|------------|--------------|------------|-------------|
| evolu      | 434ms        | 427ms      | ~0% (noise) |
| wxt        | 410ms        | 410ms      | ~0% (noise) |
| typedoc    | 532ms        | 567ms      | ~7%         |
| Chart.js   | 497ms        | 479ms      | ~0% (noise) |
| svelte     | 510ms        | 549ms      | ~8%         |

typedoc and svelte (highest JSDoc density) show measurable ~7-8% wall-clock overhead. The rest are within noise. CPU time overhead is ~1-2% as JSDoc work parallelizes across threads.

### Architecture

The formatting pipeline processes each JSDoc comment through these stages:

1. **Parse** — Extract JSDoc structure via `oxc_jsdoc` (description, tags with type/name/comment)
2. **Normalize** — Canonicalize tag aliases (`@return` → `@returns`), normalize types (`Array.<T>` → `T[]`, `?Type` → `Type | null`), normalize markdown emphasis (`__bold__` → `**bold**`, `*italic*` → `_italic_`)
3. **Sort & Group** — Sort tags by upstream priority weights within `@typedef`/`@callback` groups; reorder `@param` tags to match function signature
4. **Format** — Route each tag to its specific formatter (type+name+comment, type+comment, generic, example); format descriptions via markdown AST with word wrapping; format embedded code blocks
5. **Serialize** — Assemble final comment with `/** ... */` wrapper, `* ` prefixes, and single-line optimization

**Key modules:**
- `serialize.rs` — Main pipeline orchestrator (`JsdocFormatter` struct)
- `tag_formatters.rs` — Tag-specific formatters (type+name+comment, type+comment, generic, example)
- `normalize.rs` — Type/emphasis/capitalization normalization
- `mdast_serialize.rs` — Markdown AST → formatted text serialization with `tag_string_length` offset
- `wrap.rs` — Word wrapping with `first_line_offset`, atomic JSDoc link tokens, table formatting
- `embedded.rs` — Embedded JS/TS/JSX/TSX code formatting in @example blocks
- `imports.rs` — `@import` tag parsing, merging, and sorting
- `param_order.rs` — `@param` tag reordering to match function signature
- `line_buffer.rs` — Single-allocation line accumulator

### Options Support

All 11 options from prettier-plugin-jsdoc are implemented:

| Option | Default | Status |
|--------|---------|--------|
| `capitalizeDescriptions` | `true` | ✅ |
| `commentLineStrategy` | `"singleLine"` | ✅ |
| `separateTagGroups` | `false` | ✅ |
| `separateReturnsFromParam` | `false` | ✅ |
| `bracketSpacing` | `false` | ✅ |
| `descriptionWithDot` | `false` | ✅ |
| `addDefaultToDescription` | `true` | ✅ |
| `preferCodeFences` | `false` | ✅ |
| `lineWrappingStyle` | `"greedy"` | ✅ (greedy + balance) |
| `descriptionTag` | `false` | ✅ |
| `keepUnparsableExampleIndent` | `false` | ✅ |

**Not yet ported** (no conformance fixtures): `jsdocVerticalAlignment`, `tsdoc` mode — can be added when needed.

### Features

- **Description formatting**: Capitalize first letter, normalize markdown emphasis, wrap text to print width
- **Markdown AST processing**: Parse descriptions via mdast for heading normalization, list formatting, reference links, code blocks, blockquotes, tables
- **Tag description wrapping**: Matches upstream's `tagStringLength` architecture — full description passes through markdown AST with first-line offset
- **Tag normalization**: 17 tag synonyms, sort by upstream priority weights within groups
- **Type formatting**: Normalize JSDoc types, format via the formatter's TS parser (simulating upstream's `formatType()`), handle rest params, bracket spacing
- **@example formatting**: Format embedded JS/TS/JSX/TSX code; fenced code blocks with language detection
- **@import handling**: Parse, merge by module path, sort (third-party before relative), format consolidated imports
- **@param reordering**: Reorder tags to match function signature parameter order
- **Default value handling**: Extract `[name=value]` defaults with "Default is \`value\`" suffix

### Upstream Fidelity

Verified against [prettier-plugin-jsdoc](https://github.com/hosseinmd/prettier-plugin-jsdoc) v1.8.0 source:

- **Identical**: Tag synonyms (17), sort priorities (46 tags), grouping logic (`TAGS_GROUP_HEAD`, `TAGS_GROUP_CONDITION`), type normalization pipeline, rest param handling, JSDoc link protection, emphasis normalization, capitalization rules
- **Architecture aligned**: Tag description wrapping uses `tag_string_length` / `first_line_offset` (equivalent to upstream's `!...?` prefix trick), balance mode effective width calculation, greedy fallback
- **10 upstream bugs documented** — oxfmt intentionally produces correct output where the plugin has known issues (HTML comment wrapping, `{@link}` off-by-one, `{@includeCode}` splitting, `@type` capitalization inconsistency, etc.)

### Optimization Techniques

- Single `LineBuffer` allocation per comment (one contiguous `String`, not `Vec<String>`)
- `Cow<'_, str>` throughout normalization — borrows when unchanged, allocates only when modified
- Fast-path skip of mdast parsing for plain-text descriptions (`needs_mdast_parsing()` heuristic)
- Fast-path skip of TS formatter for simple types (`needs_formatter_pass()` check)
- `SmallVec<[usize; 4]>` for import tag indices (stack allocation for common case)

## Test plan

- [x] `cargo test -p oxc_formatter` — 335 tests pass (76 unit + 259 fixture)
- [x] `cargo run -p oxc_prettier_conformance -- --jsdoc` — 145/145 (100%)
- [x] Prettier conformance: JS 746/753 (99.07%), TS 591/601 (98.34%)
- [x] Real-world repos: 34 diffs across 5 repos (7,542 JSDoc tags) — all design differences
- [x] Performance: 0-8% overhead across 5 real-world repos (typedoc ~7%, svelte ~8%, rest within noise)
- [x] `cargo clippy -p oxc_formatter --all-targets` — clean
- [x] `cargo fmt -- --check` — clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-23 07:44:47 +00:00
leaysgur 7c233f42d2 fix(formatter,oxfmt): Handle nested BinaryExpression for tailwind trailing spaces (#20450)
Fixes #20397

`can_collapse_whitespace()` walks the ancestor chain looking for `BinaryExpression(+)` to determine if boundary whitespace must be preserved.

The loop broke on the first non-`BinaryExpression` ancestor, so a `ConditionalExpression` (ternary) between the string and the outer `+` caused an immediate break. So, the `BinaryExpression` was never seen.

Prettier's `canCollapseWhitespaceIn()` iterates the entire ancestor path without breaking, reacting only to `BinaryExpression(+)` and `TemplateLiteral` nodes via if checks.
2026-03-17 15:06:32 +00:00
leaysgur 88ee826b90 fix(oxfmt): Handle literalline for script-in-vue (#20130)
Fixes #20084, closes #20085

Currently, in the context of `js-in-vue`, there are 2 types of code paths:

- Script block: `run_full()`
  - Converts a **string** formatted by `oxc_formatter` into Prettier's Doc format by splitting it into lines, joining with `hardline`
- Other cases: `run_fragment()`
  - Converts the **IR** formatted by `oxc_formatter` into Prettier's Doc format through an IR -> Doc implementation

The current issue can be described as a bug in the former.

As a result of simply splitting by lines, newlines within strings (newlines within `TemplateLiteral`s) are also treated as `hardline` (which are affected by parent indentation, it should be `literalline`), causing the nesting to deepen with each format.

To fix this, the former code path now also goes through an IR -> Doc conversion process.

Additionally, by doing this, the `printWidth` is also handled correctly.

In #20085, which involves re-converting a formatted string into an AST and then traversing it, was deemed undesirable.
2026-03-12 23:55:23 +00:00
leaysgur 172fc072f3 feat(oxfmt): .js/.ts config file support (#20135)
Fixes #19711, also resolves some of the demands for nested configs.
2026-03-11 04:34:48 +00:00
leaysgur 57bbbd3678 test(oxfmt): Move conformance tests to standalone script (#19947) 2026-03-03 07:22:49 +00:00
leaysgur e54058538c fix(oxfmt): Support tailwind sort for CSS/LESS/SCSS (#19803)
Fixes #19801

Since this is a clear fix, I'll merge it without review.
2026-02-27 03:59:06 +00:00
leaysgur 93bb861dc3 fix(formatter): Trim trailing whitespace before breaking line (#19740)
This doesn't seem to be an issue with native js/ts format paths, but it appears to cause problems when converting Prettier Docs, such as with gql-in-js.

Without this change,

```gql
type Mutation {
    create__TYPE_NAME__(input: Create__TYPE_NAME__Input!): __TYPE_NAME__!
      @skipAuth
```

will be formatted:

```gql
type Mutation {
    create__TYPE_NAME__(input: Create__TYPE_NAME__Input!): __TYPE_NAME__!
      @skipAuth
```

See trailing ` ` after `__TYPE_NAME__!`.
2026-02-26 15:24:02 +00:00
leaysgur 72ce141c5a test(oxfmt): Add xxx-in-js-conformance (#19739)
Convert `cmp.js` to vitest test case.
2026-02-26 15:24:02 +00:00
leaysgur 4ce37b0fc4 test(oxfmt): Add js-in-xxx prettier conformance (#19563)
Add conformance test `assert(oxfmt(vueFile) === prettier(vueFile))`.

Currently, fixtures are downloaded individually and are not executed in CI.

It might have been better to change CI to download prettier's submodules and refer to them?, but for now.
2026-02-24 10:17:36 +00:00
leaysgur 035933c443 feat(formatter,oxfmt): Support js-in-vue (partially) (#19514)
### Overview

Part of #16608

This PR applies `oxc_formatter` to the js-in-vue section.

However, it is not complete and is only applied to the following parts within js-in-vue:

- `script` block
  - and `generic="..."`
- `v-for` LHS
- `v-slot`

In the `script` block, `external_callback` is used like a regular JS file, but it isn't for others.

TL;DR: Now you can use sort-imports for Vue files.

### Review points

The points I'd like to ask your review are the following:

- Addition of `format_node()` to `oxc_formatter`
  - Made it possible to process any type that implements `Format`, not just `Program`
- The implementation of `js-in-vue` fragment was separated as much as possible to avoid impacting existing code
- `oxc_formatter` IR to prettier `Doc`

### TODOs

- [x] Planning
- [x] Implementation
- [x] Check benchmark
- [x] Check coverage
- [x] Understand & refactor
  - [x] oxfmt: JS side
  - [x] oxfmt: Rust side
  - [x] oxfmt: to_doc.rs
  - [x] oxc_formatter: fragment_format
- [x] Check benchmark again
- [x] Check coverage again
- [x] Check ecosystem-ci
- [x] Tests 👉🏻 #19563
2026-02-24 10:17:35 +00:00
leaysgur d1c2fb628a feat(formatter/sort_imports): Support customGroups attributes(selector and modifiers) (#19356)
Fixes #19264

The original issue only mentioned `modifiers`, but I've implemented `selector` as well.
While the original implementation also supports more attributes, I believe this is sufficient for now.
2026-02-13 05:15:00 +00:00
leaysgur 875587ad77 test(formatter,oxfmt): Use practical glob patterns in tests (#19295)
No behavior changes.

Generally, when using `customElementPattern`, we assume it targets everything under the directory.
2026-02-12 04:07:29 +00:00
leaysgur 856a01ff40 feat(formatter/sort_imports)!: Replace prefix match with glob pattern in customGroups.elementNamePattern (#19066)
Fixes #18726

Support glob matching instead of prefix matching.

The original used regex, but there was no necessity for it, and this approach offers better performance.

In any case, it will be a braking change.

```js
// before: Matches react, reactify, react-router, etc
"elementNamePattern": ["react"]
// after: Matches react only

// before: Matches loot-core, loot-core/foo, etc
"elementNamePattern": ["loot-core"]
// after: Matches only loot-core, should update to
"elementNamePattern": ["loot-core/*"]
```
2026-02-10 02:14:10 +00:00
Dunqing 23c0753951 feat(oxfmt): better Tailwind CSS intergration (#19000)
### Resolve issues:
* close: https://github.com/oxc-project/oxc/issues/18072

The new version of `prettier-plugin-tailwindcss` solved all root causes mentioned in the description of the above issue, see the commit history at https://github.com/tailwindlabs/prettier-plugin-tailwindcss/commits/main/

* close: https://github.com/oxc-project/oxc/issues/17972
* close: https://github.com/oxc-project/oxc/issues/18459
* close: https://github.com/oxc-project/oxc/issues/18628

These three issues are related to resolving the TailwindCSS configuration of that plugin, the new version decoupled with Prettier, and provides a public `createSorter` sorting API to `/sorter`, so that we can configure `base` correctly, which is the key for the plugin to resolve `stylesheet` and `config` from `base`.

### Key change on Oxfmt side

In this PR, the `stylesheets` and `config` options are normalized to absolute paths using the Oxfmt configuration directory before calling `createSorter` and delegating to `Prettier`.

The reason is as follows:

For formatting non-JS/TS files, Oxfmt delegates to Prettier. Therefore, we should continue using `prettier-plugin-tailwindcss` to handle this, ensuring that Prettier's configuration resolution remains intact. I made a change in [that plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/blob/125a8bc77639529a5a0c7e4e8a02174d7ed2d70b/src/config.ts#L50-L54) to prevent resolution when both `stylesheet` and `config` are absolute paths. This change is valid and could enhance the plugin's performance for both Oxfmt and Prettier users. The plugin needs to resolve the Prettier configuration to obtain the directory of the configuration file and join it with `stylesheet` and `config`. If they are already absolute, there is no need to join them.

### Benchmark
> Copy from https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/438

Note: `new` means the current branch, `old` means the latest package in npm, so it includes a few optimizations that have already been merged into the main branch, not all in this branch.

Benchmark repo: https://github.com/dubinc/dub
```shell
Benchmark 3: oxfmt-new
  Time (mean ± σ):     999.8 ms ±  32.1 ms    [User: 8968.9 ms, System: 2246.7 ms]
  Range (min … max):   977.2 ms … 1022.5 ms    2 runs

Benchmark 4: oxfmt-old
  Time (mean ± σ):      1.628 s ±  0.027 s    [User: 13.239 s, System: 4.980 s]
  Range (min … max):    1.609 s …  1.647 s    2 runs

Summary
  oxfmt-new ran
    1.63 ± 0.06 times faster than oxfmt-old
```

Benchmark repo: https://github.com/tailwindcsslab/headlessui

```shell
Benchmark 3: oxfmt-new
  Time (mean ± σ):     778.8 ms ±  28.9 ms    [User: 7633.6 ms, System: 912.9 ms]
  Range (min … max):   738.3 ms … 806.9 ms    4 runs

Benchmark 4: oxfmt-old
  Time (mean ± σ):      1.033 s ±  0.034 s    [User: 10.048 s, System: 1.454 s]
  Range (min … max):    0.994 s …  1.073 s    4 runs

Summary
  oxfmt-new ran
    1.33 ± 0.07 times faster than oxfmt-old
```
2026-02-09 11:43:40 +00:00
leaysgur dc335d1071 fix(oxfmt): Temporarily disable the override for js-in-xxx (not ready yet) (#19043)
Unfortunately...

Once override a built-in for `markdown`, it applies to all embedded formatting within that file!

This means that overrides occur with js-in-**vue**-in-markdown, and since we haven't addressed this yet, the code breaks.

````md
# MD

```vue
<!-- VUE -->
<script>
  // JS
</script>

<template>
  <li v-for="function _(IT_BREAKS_HERE 💥) {} in items"></li>
</template>
````
2026-02-09 08:59:38 +00:00
leaysgur 5ea5bda86c fix(oxfmt): Handle isSingleJsxExpressionStatementInMarkdown() check for js-in-md (#19042) 2026-02-09 08:59:37 +00:00
Boshen 9da6b0bf4a test(oxfmt): remove unnecessary timeout from Tailwind CSS test (#19050)
## Summary
- Remove the 30s timeout and associated comment from the first Tailwind CSS sorting test, added in #18339

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-02-06 10:56:25 +00:00