docs(oxfmt,formatter,formatter_css,formatter_core): update AGENTS.md (#23814)

This commit is contained in:
leaysgur committed 2026-06-29 04:15:33 +00:00
1 parent 4e030183bd
commit b4d0dc9e30
4 files changed
+28 -9

No files matched your search

+13 -3
View File
@@ -35,12 +35,12 @@ When working with file paths in CLI code, be aware of Windows path differences:
Oxfmt utilizes different implementations depending on the file extension and filename:
- Tier 1: Rust implementations using `oxc_formatter`, `oxc_formatter_json`, `oxc_formatter_graphql` or `oxc_formatter_css` found in this repository
- Tier 1: Rust implementations using `oxc_formatter`, `oxc_formatter_json`, etc found in this repository
- Tier 2: Rust implementations using external libraries like `oxc_toml`
- Tier 3: Delegations to Prettier via NAPI-JS calls (e.g., for Vue or Markdown)
- Tier 4: Delegations to Prettier that require additional plugins (e.g., for Svelte)
NOTE: Tier 1 formatters never fall back to Prettier, since they exist to reduce the dependency on Prettier.
NOTE: Rust written formatters never fall back to Prettier, since they exist to reduce the dependency on Prettier.
`oxc_formatter_css` (uses a `raffia` fork) and `oxc_formatter_graphql` (uses an `apollo-parser` fork) both should cover everything the bundled Prettier can parse for their language.
@@ -55,7 +55,17 @@ Two consumers today:
- JSDoc fenced code blocks
- html-in-js fallback (`format_js_in_html_as_fallback` in `oxc_formatter/src/print/template/embed/html.rs`)
Tailwind class sorting (`sortTailwindcss`) splits responsibilities: Rust collects classes (`className` etc. in JS/TS, `@apply` in CSS — incl. css-in-js and JSDoc fenced blocks) into `FormatElement::TailwindClass`, and the JS side sorts them in one batch (`sortTailwindClasses` → tailwind's `getClassOrder`, which needs the resolved Tailwind config). Across embedded boundaries the child's classes travel in `DispatchResult::tailwind_classes` and the parent merges them with `DispatchResult::remap_tailwind_into` (defined in `oxc_formatter_core`; a forgotten merge trips a printer `debug_assert` instead of silently dropping classes). No CSS goes to Prettier for this; the pure Rust build never collects (no sorter available).
Tailwind class sorting (`sortTailwindcss`) splits responsibilities:
- Rust collects classes into `FormatElement::TailwindClass`
- `className` etc. in JS/TS, `@apply` in CSS — incl. css-in-js and JSDoc fenced blocks
- and the JS side sorts them in one batch
- `sortTailwindClasses` → tailwind's `getClassOrder`, which needs the resolved Tailwind config
Embedded boundaries carry classes through `DispatchResult::tailwind_classes`;
each embed site calls `DispatchResult::remap_tailwind_into(collector)` before consuming `docs`.
The four data paths (JS/TS top-level / standalone CSS / embedded CSS / JSDoc fenced CSS) are documented at `ExternalFormatter::to_external_callbacks`. No CSS goes to Prettier for this; the pure Rust build never collects (no sorter available).
Consequently, managing these various formatter implementations and handling their respective options are also part of Oxfmt's responsibilities.
+10 -5
View File
@@ -50,11 +50,16 @@ After changing AST shapes or the generators, regenerate with `just ast`, never h
### Embedded language formatting
- Two directions: xxx-in-js (e.g. css/graphql/html in template literals) and js-in-xxx (e.g. vue/svelte)
- xxx-in-js goes through the `FormatDispatcher` Oxfmt assembles (Rust formatter
per language where implemented — currently GraphQL — Prettier Doc→IR fallback otherwise);
js-in-xxx works by Oxfmt injecting Prettier calls through `ExternalCallbacks`
- This crate stays unaware of Prettier and only invokes the supplied dispatcher/callbacks
Two directions: xxx-in-js (css/graphql/html in template literals) and js-in-xxx (vue/svelte).
- xxx-in-js goes through the `FormatDispatcher` Oxfmt assembles Rust based formatter, Prettier Doc→IR fallback otherwise
- As the JS host, this crate also owns the parent-side concerns in `print/template/embed/`:
- template-literal escape on returned IR,
- placeholder marker insertion / survival count / `${expr}` substitution,
- and `.raw` vs `.cooked` selection
- Language formatter crates stay free of these rules
- See `embed/mod.rs` for the shared helpers and `embed/{css,html,graphql,markdown}.rs` for each site's wiring
- js-in-xxx works with `prettier-plugin-oxfmt` which uses `format_fragment`
## Fixing IR construction
+4
View File
@@ -42,6 +42,10 @@ formatter's IR be built inside another's document (e.g. graphql-in-js):
- Cross-language contract data is first-class on `DispatchResult` (`tailwind_classes`);
only truly language-pair specific data crosses as `dyn Any` (e.g. HTML's `has_multiple_root_elements`),
core never learns concrete languages
- Consumers access `DispatchResult.docs` directly
(single-doc takes `docs.into_iter().next()`, multi-doc walks `docs`);
call `DispatchResult::remap_tailwind_into` first when the child may carry classes,
the printer's `debug_assert` catches a forgotten merge
### What belongs in core (the boundary)
+1 -1
View File
@@ -97,7 +97,7 @@ the exact set of supported positions (incl. id / attribute-value / class selecto
- Mirrors `postcss-selector-parser` degrading on at-words
- A statement-position placeholder-led selector must not absorb across a newline (raffia `placeholder_starts_qualified_rule`): `${mixin}\n& > .x {}` is two statements
- String / `url()` position: the CSS lexer keeps these opaque, so a sentinel inside them stays in a verbatim `Text` (no `EmbedPlaceholder`)
- It is counted by `count_text_sentinels` (oxfmt) and substituted inline by the host's `Text`-sentinel branch, a deliberate string-scan fallback at the edges of the typed path
- The JS host (`oxc_formatter`) counts these and substitutes them inline through its `Text`-sentinel branch, a deliberate string-scan fallback at the edges of the typed path
`tests/fixtures/embedded/scss/*-placeholders.scss` is the source of truth for which positions parse and how they print (the `embedded/` harness runs `format_to_ir` with the option on); add a fixture there when extending coverage.