Skip to content

feat(formatter,oxfmt): Support js-in-vue (partially)#19514

Merged
graphite-app[bot] merged 1 commit intomainfrom
02-18-feat_formatter_oxfmt_support_js-in-vue_partially_
Feb 24, 2026
Merged

feat(formatter,oxfmt): Support js-in-vue (partially)#19514
graphite-app[bot] merged 1 commit intomainfrom
02-18-feat_formatter_oxfmt_support_js-in-vue_partially_

Conversation

@leaysgur
Copy link
Member

@leaysgur leaysgur commented Feb 18, 2026

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

  • Planning
  • Implementation
  • Check benchmark
  • Check coverage
  • Understand & refactor
    • oxfmt: JS side
    • oxfmt: Rust side
    • oxfmt: to_doc.rs
    • oxc_formatter: fragment_format
  • Check benchmark again
  • Check coverage again
  • Check ecosystem-ci
  • Tests 👉🏻 test(oxfmt): Add js-in-xxx prettier conformance #19563

Copy link
Member Author

leaysgur commented Feb 18, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions github-actions bot added A-cli Area - CLI A-formatter Area - Formatter C-enhancement Category - New feature or request labels Feb 18, 2026
@leaysgur
Copy link
Member Author

leaysgur commented Feb 18, 2026

Coverage vs pretteier/tests/format/**/*.vue: LGTM.

👀 COVERAGE: 100.00% / PASS: 88 | DIFF: 0 | ERROR: 0 | TOTAL: 88

Perf: Not bad.

=========================================
Benchmarking Mixed (embedded)
=========================================

Target: Storybook repository (mixed with embedded languages)
- 1 warmup runs, 3 benchmark runs
- Git reset before each run

Benchmark 1: node ~/Codes/oxc/apps/oxfmt/dist-main/cli.js --config ./oxfmtrc.json ./data/**/*.vue
  Time (mean ± σ):     353.7 ms ±   1.9 ms    [User: 1862.3 ms, System: 228.8 ms]
  Range (min … max):   351.5 ms … 355.1 ms    3 runs

Benchmark 2: node ~/Codes/oxc/apps/oxfmt/dist/cli.js --config ./oxfmtrc.json ./data/**/*.vue
  Time (mean ± σ):     297.5 ms ±   0.9 ms    [User: 1445.4 ms, System: 216.3 ms]
  Range (min … max):   296.8 ms … 298.6 ms    3 runs

Summary
  node ~/Codes/oxc/apps/oxfmt/dist/cli.js --config ./oxfmtrc.json ./data/**/*.vue ran
    1.19 ± 0.01 times faster than node ~/Codes/oxc/apps/oxfmt/dist-main/cli.js --config ./oxfmtrc.json ./data/**/*.vue

Mixed (embedded) benchmark complete!

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 18, 2026

Merging this PR will not alter performance

✅ 47 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing 02-18-feat_formatter_oxfmt_support_js-in-vue_partially_ (3b495e4) with main (fc3b829)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@leaysgur leaysgur force-pushed the 02-18-feat_formatter_oxfmt_support_js-in-vue_partially_ branch 24 times, most recently from 1fc104b to 291d96b Compare February 20, 2026 02:16
@leaysgur
Copy link
Member Author

leaysgur commented Feb 20, 2026

Oxfmt Ecosystem CI

suite oxfmt@latest 291d96b branch
cnpm/cnpmcore
rolldown/rolldown
vuejs/core
tale/headplane
AmanVarshney01/create-better-t-stack
huggingface/huggingface.js
actualbudget/actual
formatjs/formatjs
eggjs/egg
monkeytypegame/monkeytype
dyad-sh/dyad
fuma-nama/fumadocs
vercel/turborepo
Comfy-Org/ComfyUI_frontend
fastify/fastify-vite
vuejs/pinia
aidenybai/react-grab
openclaw/openclaw
npmx-dev/npmx.dev
getsentry/sentry-javascript
lichess-org/lila

@leaysgur leaysgur marked this pull request as ready for review February 20, 2026 05:15
@leaysgur leaysgur requested a review from Dunqing as a code owner February 20, 2026 05:15
Copilot AI review requested due to automatic review settings February 20, 2026 05:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds partial support for formatting JavaScript/TypeScript code embedded in Vue Single File Components (SFCs). The implementation introduces fragment formatting capabilities to oxc_formatter and creates a conversion layer from the formatter's internal representation (IR) to Prettier's Doc format, enabling seamless integration with Prettier's Vue plugin.

Changes:

  • Introduces format_node() API to oxc_formatter for formatting arbitrary AST nodes beyond full Program nodes
  • Implements Vue-specific formatters for v-for bindings, v-slot parameters, and <script generic="..."> type parameters
  • Creates IR-to-Prettier-Doc conversion layer for fragment formatting contexts
  • Enables sort-imports functionality for Vue files

Reviewed changes

Copilot reviewed 24 out of 26 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
crates/oxc_formatter/src/lib.rs Adds format_node() method for formatting arbitrary AST nodes; exports new public APIs
crates/oxc_formatter/src/print/fragment.rs New file containing Vue-specific formatters (FormatVueBindingParams, FormatVueScriptGeneric)
crates/oxc_formatter/src/print/parameters.rs Adds trailing separator override mechanism for Vue fragment contexts
crates/oxc_formatter/src/ast_nodes/node.rs Generalizes AstNode::new from Program-specific to generic type parameter
apps/oxfmt/src/prettier_compat/to_prettier_doc.rs New 416-line converter from oxc_formatter IR to Prettier Doc JSON format
apps/oxfmt/src/api/text_to_doc_api.rs Implements fragment and full formatting modes with parent context detection
apps/oxfmt/src/core/config.rs Adds filepath_override field for js-in-xxx external callback contexts
apps/oxfmt/src/core/format.rs Threads filepath_override through formatting pipeline
apps/oxfmt/src/core/oxfmtrc.rs Enables Vue parser support; adds filepath to plugin options
apps/oxfmt/src/core/utils.rs Refactors init_tracing() to use OnceLock for safe multiple initialization
apps/oxfmt/src/main_napi.rs Simplifies js_text_to_doc() API to return Option<String>
apps/oxfmt/src-js/libs/prettier-plugin-oxfmt/text-to-doc.ts Implements parent context detection and Doc JSON parsing
apps/oxfmt/src-js/libs/prettier-plugin-oxfmt/index.ts Adds babel-ts parser support
Test files Updates snapshots reflecting sorted import order in Vue files

@leaysgur leaysgur force-pushed the 02-18-feat_formatter_oxfmt_support_js-in-vue_partially_ branch 2 times, most recently from 7fe1a05 to 3b495e4 Compare February 24, 2026 00:37
Copy link
Member

@Dunqing Dunqing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

@graphite-app graphite-app bot added the 0-merge Merge with Graphite Merge Queue label Feb 24, 2026
@graphite-app
Copy link
Contributor

graphite-app bot commented Feb 24, 2026

Merge activity

### 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
@graphite-app graphite-app bot force-pushed the 02-18-feat_formatter_oxfmt_support_js-in-vue_partially_ branch from 3b495e4 to 035933c Compare February 24, 2026 10:17
@graphite-app graphite-app bot merged commit 035933c into main Feb 24, 2026
22 checks passed
@graphite-app graphite-app bot deleted the 02-18-feat_formatter_oxfmt_support_js-in-vue_partially_ branch February 24, 2026 10:24
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Feb 24, 2026
camc314 pushed a commit that referenced this pull request Mar 2, 2026
# Oxlint
### 🚀 Features

- 2e0e1d0 linter/no-unused-vars: Add experimental fix mode controls
(off|suggestion|fix) (#19774) (camc314)
- f34f6fa linter: Introduce typeCheck config option (#19764) (camc314)
- 694be7d linter: Introduce typeAware as config options (#19614)
(camc314)
- 655c38f semantic: Add "did you mean?" suggestions to undefined name
errors (#19102) (copilot-swe-agent)
- e97a57e linter/id-length: Use serde to deserialize rule options
(#19636) (camc314)
- c4a3677 parser: Report error for initializer in ambient context
(#19187) (camc314)
- 346045a linter/id-length: Add `checkGeneric` option (#19634) (camc314)

### 🐛 Bug Fixes

- 1b7a937 linter: Correct double-comparisons fix with swapped operands
(#19846) (camc314)
- c308857 linter/consistent_type_imports: Add missing help and notes to
diagnostics (#19827) (Daniel Osmond)
- 7682e5a linter/plugins: Decode escapes in identifier tokens (#19838)
(overlookmotel)
- f368fcd linter/consistent_type_assertions: Add missing with_help and
with_note to diagnostics (#19826) (Daniel Osmond)
- 04e6223 npm: Add `preferUnplugged` for Yarn PnP compatibility (#19829)
(Boshen)
- 86d5037 linter: Add help text to no-extend-native,
no-useless-backreference (#19733) (Anthony Amaro)
- 50e8eff linter: Add .with_help() to operator-assignment,
no-nonoctal-decimal-escape (#19732) (Anthony Amaro)
- 1417bdc linter/no-wrapper-object-types: Add help messages to missing
diagnostics (#19771) (Daniel Osmond)
- 0838477 linter/ban_ts_comment: Add help and notes to missing
diagnostics (#19781) (Daniel Osmond)
- e8c77cf linter/adjacent_overload_signatures: Add missing diagnostics
(#19780) (Daniel Osmond)
- 28834ac linter/ban_types: Add missing help and note to diagnostics
(#19782) (Daniel Osmond)
- fd938d3 linter/prefer-enum-initializers: Add help messages to missing
diagnostics (#19772) (Daniel Osmond)
- eb928ee linter/no-dynamic-delete: Add help messages to missing
diagnostics (#19768) (Daniel Osmond)
- a985666 linter/no-empty-interface: Add help messages to missing
diagnostics (#19769) (Daniel Osmond)
- 2dc0ceb linter/no-extra-non-null-assertion: Add help messages to
missing diagnostics (#19770) (Daniel Osmond)
- 95d5d66 linter/no-dupe-keys: Handle `__proto__` proto setters in
(#19762) (camc314)
- 24ff0db linter/exhaustive-deps: False positive for member expressions
in IIFEs (#19751) (Dennis Chen)
- 7243a58 linter/no-use-before-define: Honor `ignoreTypeReferences` when
value and type name collisions (#19747) (Dimava)
- eefd818 linter/explicit-module-boundary-types: Add help messages to
missing diagnostics (#19736) (Daniel Osmond)
- 0440e9a linter: Add help text to no_control_regex, no_fallthrough,
no_param_reassign (#19655) (Anthony Amaro)
- e84cb2f react/display-name: Handle merged type+value context symbols
(#19608) (camc314)
- ce7e253 linter/prefer-object-from-entries: Require exact path match in
unicorn helper (#19687) (camc314)
- f5694ce estree/tokens: Reverse field order of `regex` object in tokens
(#19679) (overlookmotel)
- b2b7a55 estree/tokens: Generate tokens for files with BOM (#19535)
(overlookmotel)
- 0722721 linter/jsx-curly-brace-presence: False positive with prop &
mixed quotes (#19674) (camc314)
- 3496acd linter: Enhance diagnostic help messages for eslint rules
(#19653) (Anthony Amaro)
- e384e94 linter: Enhance help diagnostic messages for more eslint rules
(#19658) (Anthony Amaro)
- a4d5b34 linter: Avoid non-promise catch false positives (#19574)
(camc314)
- 5706f38 linter: `unicorn/no-array-callback-reference` skip `Effect.*`
array-like methods name. (#19633) (Said Atrahouch)

### ⚡ Performance

- 05ccf9f linter/plugins: Transfer tokens via raw transfer (#19893)
(overlookmotel)
- 4b0611a estree/tokens: Introduce `ESTreeTokenConfig` trait (#19842)
(overlookmotel)
- ec88f6a estree/tokens: Serialize tokens while visiting AST (#19726)
(overlookmotel)
- d4dcf26 linter/plugins: Remove `typescript` from bundle (#19531)
(overlookmotel)
- 6a6513c linter/plugins: Use Oxc tokens in plugins (#19498) (camc314)

### 📚 Documentation

- d86f59e linter: Improve docs for no-useless-concat, mark as pending
fixer. (#19859) (connorshea)
- caa091d linter/plugins: Correct doc comments for `initTokens` (#19530)
(overlookmotel)
- 2fa936f README.md: Map npm package links to npmx.dev (#19666) (Boshen)
- dc0ff73 linter/no-useless-constructor: Warn for parameter properties
as well (#19638) (Ole Asteo)
# Oxfmt
### 🚀 Features

- 5141bc2 formatter: Support trailing ignore comments (#19304) (Andreas
Lubbe)
- 4888a99 oxfmt/lsp: Support other schemes beside `file://` and
`untitled://` (#19872) (Sysix)
- 14a0181 oxfmt: Support `graphql()` variant for gql-in-js (#19703)
(leaysgur)
- ca68ea6 oxfmt: Support gql-in-js substitution (#19670) (leaysgur)
- 035933c formatter,oxfmt: Support js-in-vue (partially) (#19514)
(leaysgur)
- 9e11dc6 parser,estree,coverage: Collect tokens in parser and convert
to ESTree format (#19497) (camc314)

### 🐛 Bug Fixes

- 8e3842d oxfmt: Avoid embedded TSFN crash by returning errors as data
(take2) (#19806) (Yuji Sugiura)
- 04e6223 npm: Add `preferUnplugged` for Yarn PnP compatibility (#19829)
(Boshen)
- e540585 oxfmt: Support tailwind sort for CSS/LESS/SCSS (#19803)
(leaysgur)
- 93bb861 formatter: Trim trailing whitespace before breaking line
(#19740) (leaysgur)
- b85f97b formatter: Drop blank line between terminal call and first
chain member (#19659) (Dunqing)

### ⚡ Performance

- b3b2d30 parser: Introduce `ParserConfig` (#19637) (overlookmotel)

### 📚 Documentation

- 2fa936f README.md: Map npm package links to npmx.dev (#19666) (Boshen)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-cli Area - CLI A-formatter Area - Formatter C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants