Aligned the handling of line comments immediately following an opening `{`.
(For GraphQL only,) previously kept their own line, now matches other languages by inserting a line break and treating them as leading comments for the next element.
This brings it in line with Prettier's style. The only drawback is that the behavior of `-line` style comments. However, since most of these can be replaced with `-next-line` style comments, we are going to standardize on this consistent behavior for now.
prettier/prettier#1267 (won't fix)
- Extract "known divergences" section from `AGENTS.md` to explicit `DIVERGENCES.md` with code example
- Update all anchors
- Add missing pinned fixtures
Prettier uses the `conditionalGroup` IR for JS and YAML.
When this appeared in JS(containing `conditionalGroup`)-in-HTML(`script` tags)-in-JS (`oxc_formatter`), we previously bypassed the `Doc` to IR conversion.
This PR adds support for this conversion and removes the string format fallback path.
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.
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)
Audited every formatter crate against the trailing-comment width discipline.
- same-line trailing line comments ride `line_suffix` and are excluded from the fits measurement
- while trailing block comments print inline and count
Corrected the prose that misstated it.
Fixes#24843
---
Tracing back to the root cause, this is also related to what had diverged because of Prettier's inconsistent behavior.
Since I cannot determine for sure how it should be output in more complex cases (like that issue) at this point, decided to revert to being Prettier-compatible.
Also fixes#24927
- rework comment printing to follow the rules and align with other formatters
- bump `oxc-graphql-parser`
- to track comments inside a node's span more accurately
- 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
Part of #15180, closes#18891
Angular-in-JS consists of 2 cases: `template` and `styles`.
- template: Similar to html-in-js, use the `parser: angular`
- styles: Same as css-in-js (already supported)
Part of #15180
The basic flow is the same as css-in-js: replace `${expr}` with placeholder strings, let Prettier format the HTML, then substitute back with formatted `expr`s.
However, there are a few key differences:
### `options.htmlWhitespaceSensitivity`
This HTML-specific option also affects html-in-js (template wrapping strategy, hug detection), so it needed to be held in `oxc_formatter::FormatOptions`.
### `prettier.__internal.formatOptionsHiddenDefaults`
Prettier adds hidden fields to the `options` object during its internal print phase for embedded formatters.
However, `__debug.printToDoc()` runs `normalizeFormatOptions()` which strips unknown keys. Unlike internal `textToDoc()` (which uses `passThrough: true`), `printToDoc()` does not preserve them.
To work around this, we pre-register keys in `formatOptionsHiddenDefaults` so they survive normalization.
### NOTE: Not fully supported cases
#### js-in-html-in-js
Currently, the process of converting Docs to our IR does not support `conditionalGroup`.
Since Prettier only uses this for YAML and JS formatting.
YAML is never embedded, and we would like to use `oxc_formatter` for JS.
However, applying `oxc_formatter` to the **js**-in-html-in-js case was not straightforward. Therefore, I have implemented a fallback to a simpler formatting process for that case for now.
#### `label({ embed, hug })` equivalent
With current implementation, `is_huggable_html_embed_single_arg()` always hugs via early-return, ignoring line width.
Prettier uses `label({ embed, hug })` + `conditionalGroup` to try hugged first and fall back to expanded.
We have the equivalent `BestFitting` 3-variant flow in `write_grouped_arguments`, but `ExpandParent` from HTML template's `hardline` propagates through `will_break` / `propagate_expands` / fit check, forcing the expanded variant to always be chosen.
To fix, we need to add new IR for boundary (prevents `ExpandParent` propagation in `will_break` / `propagate_expands` / fit check), then add HTML embeds to `can_group_expression_argument` so they enter the existing `BestFitting` 3-variant flow.
However, I'm not sure this is worth to add. So just leave it for now.
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.