Commit Graph

72 Commits

Author SHA1 Message Date
leaysgur 5ff57f83c0 fix(formatter/sort-imports): handle custom side effect groups (#26217)
Fixes #26165

- `side_effect` is predefined selector, it cannot be used as custom group name
- respect custom group which uses `side_effect` as side-effect-import correctly
- fix metadata detection bug
2026-09-01 03:56:36 +00:00
leaysgur c07fe7c217 feat(oxfmt): support experimentalOperatorPosition (#25643)
Fixes #16366

---

Option name requires `experimental` prefix for now.

Values are:

- `"start"`
- `"end"`(default)

This is also available on playground.
2026-08-14 08:12:16 +00:00
leaysgur fed6681eda docs(oxfmt): skip expanding overrides options (#25572)
Follow up on #25544.

Oxlint also omits `overrides[].rules`.
2026-08-13 02:35:53 +00:00
Rahul Mishra 6a07fa6c79 fix(docs): cap generated Markdown heading depth (#25544)
`#` was repeated for each level without a max, which created this
problem
https://oxc.rs/docs/guide/usage/formatter/config-file-reference.html
<img width="1452" height="1154" alt="Screenshot 2026-08-12 at 18-24-43"
src="https://github.com/user-attachments/assets/9f1ac473-2e7b-4514-81a4-d528c7b6c0e6"
/>

capped `#` at max of 6
2026-08-13 11:23:56 +09:00
leaysgur 00f490d7f7 refactor(oxfmt,formatter): split sortImports validation and use type enum (#25432)
Reduce runtime validation.

Also, by using type `enum`, IDE and TS types are also covered.
2026-08-09 15:07:41 +00:00
leaysgur e6e584b9be fix(oxfmt): type jsdoc. enum options (#25008)
Fixes #24999
2026-07-28 01:22:23 +00:00
Boshen baf022d74d refactor(ast)!: remove old AstBuilder methods (#24563)
Closes the migration tracked in #23043.

The new builder API (methods on the AST types themselves) has been in place for a while, all Oxc crates are migrated, and every crate which uses `AstBuilder` already enables `disable_old_builder` in its tests. The module docs said "after a few weeks, we will remove `AstBuilder`'s own methods entirely" — this does that.

## What's removed

- `crates/oxc_ast/src/generated/ast_builder.rs` and `builder/methods.rs` — `AstBuilder`'s own node and primitive constructors.
- `AstBuilderGenerator`, which produced the former.
- The `disable_old_builder` Cargo feature, plus the dev-dependency hacks it required across 33 manifests. Eight crates depended on `oxc_ast` *purely* to turn the feature on; those deps and their `cargo-shear` ignore entries are gone too.

## One thing worth reviewing

`AstBuilderGenerator` owned the `#[builder(default)]` / `#[builder(skip)]` attr registration that `BuilderMethodsGenerator` only *reads* — its doc comment said as much. Deleting it naively would have silently dropped `skip`/`default` handling for the 12 AST types using those attrs, so `attrs()` and `parse_attr()` move to `BuilderMethodsGenerator`.

The evidence this was faithful: after regenerating, `builder_methods.rs` and every other generated file are **byte-identical**. The only generated change in the diff is the deletion.

## Breaking changes

- `AstBuilder`'s own methods are gone. Use the AST type methods: `Statement::new_expression_statement(span, expr, &builder)` instead of `builder.statement_expression(span, expr)`.
- `AstBuilder` is no longer `Copy`/`Clone`, and its `allocator` field is private — use the `allocator` method from `GetAllocator`.
- `AstBuilder` and `NONE` are no longer re-exported from the crate root; import them from `oxc_ast::builder`. (The `disable_old_builder` feature already gated these off, so nothing in-tree used the root path.)
- The `disable_old_builder` feature no longer exists — remove it from any manifest that sets it.

A migration note covering all of the above is in `crates/oxc_ast/src/builder/mod.rs`.

---

Implemented with AI assistance (Claude Code); design, review, and verification driven by the author per the repo AI-usage policy.
2026-07-21 15:22:46 +00:00
leaysgur 415fe1e7bb fix(oxfmt): error on ignorePatterns that cannot match files outside the config directory (#24286)
Patterns in `ignorePatterns` use gitignore-style matching rooted at the config file's directory, so a `..` component can never match anything.

Reject such patterns at config load time instead of silently accepting them, and document the scoping.

Refs: #24276
2026-07-08 05:31:23 +00:00
overlookmotel 85a6853e0b fix(tasks): enable disable_old_builder Cargo feature for oxc_ast crate for all tasks (#23885)
Part of #23043.

We don't enable `oxc_ast`'s `disable_old_builder` Cargo feature in any of our published crates, or crates that are depended on by published crates.

Tasks are private to the repo, so enable this feature on them, to ensure no usage of legacy `AstBuilder` methods sneak in during the transition period before we delete these methods.
2026-06-28 12:13:17 +00:00
Sysix b0d39d7942 test(website): fix tests for win32 (#23398)
fixes the tests on main:
https://github.com/oxc-project/oxc/actions/runs/27479376607/job/81224340552

introduced in https://github.com/oxc-project/oxc/pull/23387
2026-06-14 11:59:06 +00:00
Sysix 49e5649653 test(website): don't snapshot on schema validation (#23387)
It sounds stupid to create a snapshot from an already existing file.
Works on https://github.com/oxc-project/oxc/issues/22955 showed they will always match.

The PR changes the tests so it just checks if the existing file matches the output, without snapshots.
2026-06-13 21:14:05 +00:00
leaysgur f88961ae29 docs(oxfmt): annotate each config option with supported languages (#22953)
Currently, our config file is Prettier-compatible, which is not easy to tell which options apply to which languages.

(I've felt this way for a while, so) I've added some notes to clarify.
2026-06-04 08:28:02 +00:00
leaysgur 43b997847b fix(formatter/sort_imports): Treat subpath imports as internal (#22440)
Closes #22371, follows https://github.com/azat-io/eslint-plugin-perfectionist/pull/732

---

As a baseline, while the result effectively follows the behavior of a perfectionist, there is no fundamental reason why it must be done that way.

Node.js subpaths are more flexible and aren't necessarily "internal", you can also alias external modules.

However, I do think it's consistent in the sense that it treats them the same way as other conventions like `@`.
2026-05-15 00:45:24 +00:00
leaysgur 6e8e8185c0 feat(oxfmt): Experimental .svelte support (#21700)
Part of #19715

Note that:

> Users are required to perform 2 steps below
> 1️⃣ Install svelte/compiler@^5.0.0 and/or @astrojs/compiler@^2.9.1 manually
> 2️⃣ Enable option in config
2026-05-11 01:24:37 +00:00
leaysgur 330fe31f82 refactor(config): Update doc comment for GlobSet (#22197)
Follow up on #22147.
2026-05-07 02:13:27 +00:00
leaysgur 7a6d69a6ff fix(tasks/website): Render both prop-level and type-level description (#22196)
When a property references a type via `$ref` and both have doc comments, the markdown renderer was dropping the property-level description.

```rs
/// A set of glob patterns.                                // ← type-level
pub struct GlobSet(Vec<String>);
```
```rs
pub struct OxfmtOverrideConfig {
    /// Glob patterns to match files for this override.    // ← property-level
    pub files: GlobSet,
}
```

Before:

```
#### overrides[n].files

A set of glob patterns.
```

After:

```
#### overrides[n].files

Glob patterns to match files for this override.

A set of glob patterns.
```

At present, some definitions may seem redundant, but since unifying them at the prop-level seemed inconvenient for linter use cases, I decided to provide both.

The intended convention is generic invariants on the type-level, contextual purpose on the property-level.
2026-05-07 02:13:26 +00:00
camc314 fb3067ca2b refactor(oxfmt): use shared GlobSet for overrides (#22147)
uses oxlint's `GlobSet` for overrides over `Vec<String>`.

This helpe move out some shared normalization code from oxlint and oxfmt to the shared config crate.

Hopefully this change is ok for you @leaysgur  - I was originally hoping to share somethign else, but it seems trickier than I expected, so I just moved this out instead, which feels to me a good change
2026-05-06 16:14:04 +00:00
Sysix 41a4cb992f docs(website): sanitize sub sections (#22118) 2026-05-05 08:26:16 +00:00
leaysgur 5aa7fe1b12 feat(oxfmt): Add --disable-nested-config CLI flag (#21514)
Fixes #21420
2026-04-17 01:20:46 +00:00
leaysgur 50c389b64f fix(oxfmt): Support .editorconfig quote_type (#20989)
Fixes #20563

---

- [x] Merge https://github.com/oxc-project/editorconfig-parser/pull/42
- [x] Release https://github.com/oxc-project/editorconfig-parser/pull/43
- [x] Update crates version
- [x] Implement
- [x] Test
- [x] Update schema, snapshots
2026-04-07 02:03:35 +00:00
leaysgur 4216380bc0 fix(oxfmt): Support .editorconfig tab_width fallback (#20988)
https://github.com/prettier/prettier/blob/90983f40dce5e20beea4e5618b5e0426a6a7f4f0/src/config/editorconfig/editorconfig-to-prettier.js#L25-L30
2026-04-03 02:28:39 +00:00
leaysgur 6ef440af18 feat(oxfmt): Support bool for object style options (#20853)
Fixes #20793
2026-03-30 02:05:35 +00:00
leaysgur 416865ac32 feat(formatter,oxfmt): Add doc comments for JsdocConfig (#20644)
Follow up #19828
2026-03-23 09:00:46 +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 bc2021765c fix(oxlint,oxfmt): Omit useless | null for Option<T> field from schema (#20273)
Currently, fields defined as `key: Option<T>` are represented in TS as `key?: T | null`.

However, passing `null` actually just treats it as `None`, which only creates noise.
2026-03-12 09:48:46 +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
Connor Shea d631b318b8 fix(linter): Improve config option docs rendering for rules with enum configs (#20018)
Claude's summary:

- Enhanced `schema_markdown.rs` to properly handle `allOf` schemas
created by the `RemoveRefSiblings` visitor
- When a `$ref` has sibling properties (like `description`), schemars'
draft-07 visitor wraps it in an `allOf`
- The renderer now resolves through `allOf` structures to find the
actual referenced schema

----

This fixes the problem discovered in
https://github.com/oxc-project/oxc/pull/19387#issuecomment-3999084412.

This actually improves the generated docs for a few rules:
- `typescript/no-deprecated`
- `no-floating-promises`
- `react/forbid-dom-props`
- `typescript/no-misused-spread`
- `typescript/only-throw-error`
- `typescript/prefer-readonly-parameter-types`
- `typescript/prefer-nullish-coalescing`
- `typescript/restrict-template-expressions`

Basically, any rule that has a struct nested inside an array has better
docs now, as the docs generator actually handles their schema correctly
now.

AI Disclosure: Generated by Claude Code.


Examples:

no-deprecated

````md
## Configuration

This rule accepts a configuration object with the following properties:

### allow

type: `array`

default: `[]`

An array of type or value specifiers that are allowed to be used even if deprecated.
Use this to allow specific deprecated APIs that you intentionally want to continue using.

#### allow[n]

type: `object | string`

Type or value specifier for matching specific declarations

Supports four types of specifiers:

1. **String specifier** (deprecated): Universal match by name

```json
"Promise"
```

2. **File specifier**: Match types/values declared in local files

```json
{ "from": "file", "name": "MyType" }
{ "from": "file", "name": ["Type1", "Type2"] }
{ "from": "file", "name": "MyType", "path": "./types.ts" }
```

3. **Lib specifier**: Match TypeScript built-in lib types

```json
{ "from": "lib", "name": "Promise" }
{ "from": "lib", "name": ["Promise", "PromiseLike"] }
```

4. **Package specifier**: Match types/values from npm packages

```json
{ "from": "package", "name": "Observable", "package": "rxjs" }
{ "from": "package", "name": ["Observable", "Subject"], "package":
"rxjs" }
```

##### allow[n].from

type: `"file"`

##### allow[n].name

type: `array | string`

Name specifier that can be a single string or array of strings

###### allow[n].name[n]

type: `string`

##### allow[n].path

type: `string`

Optional file path to specify where the types or values must be declared.
If omitted, all files will be matched.
````

react/forbid-dom-props

````md
## Configuration

Configuration for the `forbid-dom-props` rule.

This rule accepts a configuration object with the following properties:

### forbid

type: `array`

An array of prop names or objects that are forbidden on DOM elements.

Each array element can be a string with the property name, or an object
with `propName`, an optional `disallowedFor` array of DOM node names,
and an optional custom `message`.

Examples:

- `["error", { "forbid": ["id", "style"] }]`
- `["error", { "forbid": [{ "propName": "className", "message": "Use class instead" }] }]`
- `["error", { "forbid": [{ "propName": "style", "disallowedFor": ["div", "span"] }] }]`

#### forbid[n]

type: `object | string`

A forbidden prop, either as a plain prop name string or with options.

##### forbid[n].disallowedFor

type: `string[]`

A list of DOM element names (e.g. `["div", "span"]`) on which this
prop is forbidden. If empty or omitted, the prop is forbidden on all
DOM elements.

##### forbid[n].message

type: `string`

A custom message to display when this prop is used.

##### forbid[n].propName

type: `string`

The name of the prop to forbid.
````

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-05 17:51:24 -07:00
leaysgur f398bc9318 refactor(formatter,oxfmt): Use Sort prefix for tailwind options (#19568)
Internal changes to ensure consistency.
2026-02-20 08:56:22 +00:00
leaysgur 984dc07f4f feat(oxfmt): Strip "experimental"SortXxx prefix (#19567)
- `experimentalSortImports` 👉🏻 `sortImports`
- `experimentalSortPackageJson` 👉🏻 `sortPackageJson`
- `experimentalTailwindcss` 👉🏻 `sortTailwindcss`

To avoid breaking changes, the old name is retained as an alias.
2026-02-20 08:56:22 +00:00
leaysgur 6c61b7092a fix(oxfmt): Fix outdated sortImports.groups doc comments (#19513) 2026-02-18 04:28:38 +00:00
leaysgur 9c34f7226b feat(formatter/sort_imports)!: Report invalid group name with renaming side-effect > side_effect (#19416)
- Breaking: Rename ambiguous modifier/selector names
  - `side-effect` → `side_effect`
  - `side-effect-style` → `side_effect_style`
  - Now `-` is used only for joiner (`modifier-modifier-selector`)
    - before: `value-side-effect-style` 🆚 after: `value-side_effect_style`
- Breaking: Add config-time validation for invalid group names
  - previously silently ignored...
  - or wrongly applied (and user didn't notice)
2026-02-16 05:05:08 +00:00
leaysgur 4baebefa81 feat(formatter/sort_imports): Support { newlinesBetween: bool } inside groups (#19358)
Fixes #17830

Introduce new variant for `groups` like:

```json
  // "newlinesBetween": true, // Default
  "groups": [
      ["value-builtin", "value-external"],
      { "newlinesBetween": false }, // 👈🏻
      "value-parent",
      "value-sibling"
  ]
```

This allows you to specify line breaks globally between groups while reverting them at any position.

Conversely, you can also add line breaks at any position while specifying `newlinesBetween: false`.
2026-02-14 14:12:48 +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 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
leaysgur 8536dce989 feat(oxfmt): Support glob for CLI paths (#18976)
Fixes #13705

- Support glob patterns like `*.js`, `**/*.ts`, and `{a,b}.js` in CLI paths
- Globs are pre-expanded to make `ignore` crate respects `.gitignore`
  - Existing cases that don't use glob will NOT be affected in terms of performance

This also fixes bug that `oxfmt a.js a.js` formats the same file 2 times 🙈
2026-02-06 07:59:55 +00:00
leaysgur 6ee2d59cd6 feat(oxfmt): Use oxc_formatter in js-in-xxx part (#18373)
Fixes #16608 partially.

This PR overrides Prettier's default JS/TS formatting process with a custom transform-plugin.
As a result, `oxc_formatter` will be used in the `script` section of Vue, code block of Markdown, etc. And also for example, sort-imports and other features are now available.

After verification, we found that if we override `babel`, it is also applied to some expression parts of Vue.

This was unexpected and more time is needed to do things properly.
Therefore, as a first support, only enables for `markdown` and `mdx`.

Changes:

- Changed `tinypool` mode from `worker_threads` to `child_process`
  - Calling NAPI (API) again via `worker_threads` from NAPI (CLI) causes a hang...
- Implemented `prettier-plugin-oxfmt` using the existing `format()` API
  - What's truly desired is something equivalent to `textToDoc()`, but this is the only option currently we have
- Handling of options corresponding to Prettier's `embed()` processing flow
  - Plugins only support primitive types
  - NAPI also cannot handle options that cannot be serialized to JSON

Following PRs will cover:

- Improvements to option handling
- Tests
2026-02-06 05:50:04 +00:00
connorshea 8126390ecb chore(test): Regenerate insta snapshots. (#18818)
Make insta stop logging massive diffs to the console for no reason. Regenerated with `cargo insta test --force-update-snapshots`

This was caused by the update to insta here: https://github.com/oxc-project/oxc/pull/18817
2026-02-02 00:06:52 +00:00
Luca Fischer ee30de98cf feat(oxfmt): add config migration from biome (#18638)
Added Biome-to-oxfmt configuration migration, based on the Prettier
implementation.

I wasn't sure if I should exclude settings that match oxfmt's defaults
from the generated config, but I'm happy to do so if you’d like
2026-01-28 21:09:13 +09:00
leaysgur 4e9a5e5410 refactor(oxfmt): Update TS type and tailwind option docs (#18284)
- Use `Pick<Options, ...>` from Prettier to reuse fully compatible option types
- Fix misleading documentation for Tailwind `attributes` and `functions`:
  - Clarify they use exact match (not prefix)
  - Correct `attributes` default from `["class", "className"]` to `[]`
    - `class`/`className` are hardcoded, option is for additional
2026-01-20 08:58:36 +00:00
leaysgur a95b9bb54e feat(oxfmt): Support oxfmtrc overrides config (#18068)
Fixes #17585
2026-01-19 07:39:43 +00:00
nilptr 984d5c1ca6 feat(oxfmt/sort-imports): support options.customGroups (#17576)
#17076 

### Authorship & Use of AI

All code changes in this pull request are completed by a human (myself).
ChatGPT is used **only** to assist with writing comments and this PR
description.

### Commit Structure

The changes are split into small, meaningful commits.
Each commit should be reviewable independently.

## Current State of the Implementation

For easier comparison, I forked
[actual](https://github.com/nilptr/actual) and made a few auxiliary
changes on a separate branch
[nilptr/feat/oxfmt-custom-groups](https://github.com/nilptr/actual/tree/nilptr/feat/oxfmt-custom-groups).

The auxiliary changes include:

- Upgraded `oxfmt` to address the incompatible binding API.
- Updated `eslint.config.mjs` to lint and fix .ts files.
- Updated `.oxfmtrc` to enable `experimentalSortImports`, keeping it
consistent with `eslint.config.mjs`.

### How to Compare? 

1. Clone `git@github.com:nilptr/actual.git` and check out
`nilptr/feat/oxfmt-custom-groups` branch.
2. Run `yarn install`
3. Run `NAPI_RS_NATIVE_LIBRARY_PATH=/path/to/binding.node yarn
fmt:oxfmt`

    The native binding can be obtained in one of the following ways:
- Download the
[oxfmt.darwin-arm64.node.zip](https://github.com/user-attachments/files/24402116/oxfmt.darwin-arm64.node.zip)
built by me (if you trust it, or scan it with
[VirusTotal](https://www.virustotal.com/gui/home/upload)).
- Build it by yourself: clone my repo, run `pnpm build`, and locate the
.node binding file under `apps/oxfmt/src-js`.
    
4. Inspect the results with `git diff` — the diff shows the differences
between perfectionist and oxfmt

### Observed Differences

There are 9 differences in total:

- **4 differences** are unrelevant to `experimentalSortImports`. (be the
way, they are introduced after I rebased main branch)
- **5 differences** are relevant to `experimentalSortImports`, but are
not caused by the group-matching logic, which is the focus of this PR.
  - 4 of them are blank lines after side-effect imports being removed
  - 1 of them is the wrong `ImportLineMetadata.source`

<img width="4064" height="2152" alt="image"
src="https://github.com/user-attachments/assets/8b4cb860-19d6-42b9-a0a4-6db0b3e40194"
/>

<img width="4064" height="2152" alt="image"
src="https://github.com/user-attachments/assets/e2616d7b-b4b2-4dbc-a0d3-ea15d1c0177e"
/>

------

I believe we can start review now.
While the review is ongoing, I will also try to see whether the observed
differences can be fixed in this PR.

---------

Co-authored-by: Yuji Sugiura <y.sugiura.0316@gmail.com>
2026-01-19 10:23:49 +09:00
leaysgur 7c664cfdf0 refactor(apps,website): Use the same generate_schema_json() function (#18025)
The initial goal was to extract the schema generation utility from `oxfmtrc.rs`.

However, I found that `oxc_linter` also defines a similar function, so I unified them into `website_common`.

- Added `generate_schema_json<T>()` to `website_common`
- Removed duplicated implementations from `oxfmtrc.rs` and `oxlintrc.rs`
- Moved `test_schema_json` from `oxc_linter` to `website_linter` too

NOTE: When running `cargo t -p oxc_linter`, it previously generated `npm/oxlint/configuration_schema.json`. Now use `just linter-schema-json` instead.
2026-01-15 07:33:59 +00:00
Yuji Sugiura 0e7176dde4 chore(oxfmt): Fix Oxfmtrc.printWidth typo (#18017)
`’` -> `'` 🙈
2026-01-15 14:19:28 +09:00
leaysgur 48d8dfe3e8 refactor(oxfmt): Generate better JSON schema for sort_imports.groups option (#18014)
Fixes #17651

Stopped manual deserialization and switched to using `enum` to ensure the correct types are generated.
2026-01-15 05:04:21 +00:00
Boshen f91dd95b4d fix(website): remove unnecessary null types from schema markdown (#17997)
## Summary

- Filter out `| null` from type annotations in website documentation markdown
- Keeps JSON schema files unchanged (they still have proper null types for validation)
- Makes documentation cleaner since users typically omit optional fields rather than setting them to null

**Before:** `type: boolean | null`
**After:** `type: boolean`

## Test plan

- [x] `cargo test -p website_formatter test_schema_markdown`
- [x] `cargo test -p website_linter test_schema_markdown`

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-14 13:57:08 +00:00
leaysgur cc3e74bdff feat(oxfmt): Add Prettier specific fields in Oxfmtrc (#17981)
Like `vueIndentScriptAndStyle`, fixes #17741
2026-01-14 07:25:21 +00:00
leaysgur 6ffe31503c feat(oxfmt): Add more Oxfmtrc fields description (#17979)
Added more description with consistent notation.
2026-01-14 07:25:20 +00:00
Dunqing 62b7a01728 docs(formatter): clarify experimentalTailwindcss configuration comments (#17898) 2026-01-12 02:25:45 +00:00
leaysgur 1aea211424 refactor(oxfmt): Move Oxfmtrc to apps/oxfmt (#17824)
Before this PR, `Oxfmtrc` was defined in `oxc_formatter` to avoid the circular reference `oxc_language_server` > `oxfmt` > `oxc_language_server`....

But now, `oxc_language_server` does not depend on `Oxfmtrc` since LSP implementation has moved to `apps/oxfmt`.

Therefore, by this PR, `Oxfmtrc` is moved to its proper location, in `apps/oxfmt`.

- Moved `Oxfmtrc` from `oxc_formatter` to `apps/oxfmt`
- Re-exposed from `apps/oxfmt`
- Now only `tasks/website_formatter` depends on it
- Also aligned JSON schema generation with `oxlint` by `just formatter-schema-json`

NOTE: In `oxc_formatter`, there are 2 places (`ir_transform` and `fixtures` tests) where we manually convert options from JSON. I'd like to fix this too in the future.
2026-01-09 15:11:36 +00:00
leaysgur d7b5c0acd3 refactor(formatter)!: Remove Expand::Always variant (#17770)
Fixes #17330
2026-01-08 01:25:32 +00:00