Skip to content

Commit 267557c

Browse files
committed
fix(formatter,oxfmt): embed only original JSDoc plugin supported languages (#27241)
May support more languages in the future, but for now embed only css / less / scss / json / yaml / html, as original (`parserSynonyms`) does. https://github.com/fardad-dev/prettier-plugin-jsdoc/blob/75825bae4a9e0f74a0539aeeada777d3e54e38d2/src/descriptionFormatter.ts#L16
1 parent 4333fe8 commit 267557c

7 files changed

Lines changed: 38 additions & 38 deletions

File tree

‎apps/oxfmt/AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ Per-language options are NOT built up front: `ResolvedDispatchConfig` maps them
107107

108108
A separate string-out channel (the session's `string_embedder` service, NOT the dispatcher) carries JSDoc's string-in/string-out consumer:
109109

110-
- JSDoc fenced code blocks: routing follows ONE rule, the same `dispatcher::route` table
110+
- JSDoc fenced code blocks: the host (`oxc_formatter`) embeds only the `prettier-plugin-jsdoc` set (css/less/scss/json/yaml/html), then routing follows ONE rule, the same `dispatcher::route` table
111111
- a `Native` fence language formats through `FormatSession::dispatch_to_string` via a thin string adapter (`embed/jsdoc_fence.rs::format_native_fence`, EVERY build, the pure Rust build wires it via `services::for_root`)
112-
- md/html/angular fences stay on the Prettier string path (`embed/prettier_string.rs`, napi only; their Doc→IR conversion has unrepresentable cases);
112+
- html fences stay on the Prettier string path (`embed/prettier_string.rs`, napi only; its Doc→IR conversion has unrepresentable cases);
113113
- everything else stays verbatim
114114
- the embedder carries the caller's effective print width; both branches honor it (native via `PrintWidth` override, Prettier via `printWidth` in the options JSON), so a fence prints at the same width a JS/TS snippet in the same position would (see `upstream-jsdoc-bugs.md` #11 for the deliberate divergence from upstream's flat `printWidth - 4`)
115115

‎apps/oxfmt/src/core/embed/mod.rs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
//! - [`services`] (every build): the root `SessionServices` assembly (`for_root`, one definition per build)
1212
//! - [`jsdoc_fence`] (every build): the JSDoc native-fence string adapter over the registry
1313
//! - [`prettier_doc`] (napi only): Prettier Doc→IR path for the `Route::Prettier` set
14-
//! - [`prettier_string`] (napi only): the Prettier string paths of the string-out channel
15-
//! (md/html/angular JSDoc fences; results re-embed line-by-line)
14+
//! - [`prettier_string`] (napi only): the Prettier string paths of the string-out channel (html JSDoc fences; results re-embed line-by-line)
1615
1716
#[cfg(feature = "napi")]
1817
use std::sync::Arc;

‎apps/oxfmt/src/core/embed/prettier_string.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::core::{
3030
/// Build the napi build's string embedder installed on the session.
3131
///
3232
/// Dispatches by language identifier: the native registry when available, otherwise Prettier via `format_embedded`.
33-
/// The JSDoc fenced consumer reaches every language.
33+
/// The JSDoc fenced consumer sends only its embedded set (`EMBEDDED_FENCE_LANGUAGES` in `oxc_formatter`).
3434
///
3535
/// `sort_tailwind` is the SAME pre-bound sorter as the session's Tailwind service
3636
/// (options JSON already applied by `services::for_root`), for the `@apply` classes a CSS fence collects.

‎apps/oxfmt/test/api/jsdoc.test.ts‎

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ describe("JSDoc", () => {
5454
);
5555
});
5656

57-
it("should format fenced scss, less and graphql through the native dispatch registry", async () => {
57+
it("should format fenced scss and less through the native dispatch registry, keeping graphql verbatim", async () => {
5858
const source = `
5959
/**
6060
* \`\`\`scss
@@ -91,19 +91,14 @@ describe("JSDoc", () => {
9191
* \`\`\`
9292
*
9393
* \`\`\`graphql
94-
* query Q {
95-
* user {
96-
* id
97-
* name
98-
* }
99-
* }
94+
* query Q { user { id name } }
10095
* \`\`\`
10196
*/
10297
`.trimStart(),
10398
);
10499
});
105100

106-
it("should format fenced json, json5 and yaml via the native registry", async () => {
101+
it("should format fenced json and yaml via the native registry, keeping json5 verbatim", async () => {
107102
const source = `
108103
/**
109104
* \`\`\`json
@@ -132,7 +127,7 @@ describe("JSDoc", () => {
132127
* \`\`\`
133128
*
134129
* \`\`\`json5
135-
* { a: 1 }
130+
* {a:1,}
136131
* \`\`\`
137132
*
138133
* \`\`\`yaml
@@ -148,17 +143,17 @@ describe("JSDoc", () => {
148143
it("should print native fences at the fence's effective width, not the full printWidth", async () => {
149144
// Effective width at top level = printWidth(100) - " * "(3) - 4 = 93,
150145
// the same width JS/TS snippets in the same position already use.
151-
// The 94-char field line must break; the 92-char one must not.
146+
// The 94-char line must break; the 93-char one must not.
152147
// (Upstream `prettier-plugin-jsdoc` uses a flat printWidth - 4, which overflows `printWidth` for indented comments;
153148
// see crates/oxc_formatter/tests/jsdoc/upstream-jsdoc-bugs.md)
154149
const source = `
155150
/**
156-
* \`\`\`graphql
157-
* query { fieldName(argOne: "value1", argTwo: "value2", argThree: "value3", four: 4444, five: 5555577) }
151+
* \`\`\`json
152+
* { "argOne": "value1", "argTwo": "value2", "argThree": "value3", "four": 4444, "five": 555555 }
158153
* \`\`\`
159154
*
160-
* \`\`\`graphql
161-
* query { fieldName(argOne: "value1", argTwo: "value2", argThree: "value3", four: 4444, five: 55555) }
155+
* \`\`\`json
156+
* { "argOne": "value1", "argTwo": "value2", "argThree": "value3", "four": 4444, "five": 55555 }
162157
* \`\`\`
163158
*/
164159
`.trim();
@@ -168,22 +163,18 @@ describe("JSDoc", () => {
168163
expect(result.code).toBe(
169164
`
170165
/**
171-
* \`\`\`graphql
172-
* query {
173-
* fieldName(
174-
* argOne: "value1"
175-
* argTwo: "value2"
176-
* argThree: "value3"
177-
* four: 4444
178-
* five: 5555577
179-
* )
166+
* \`\`\`json
167+
* {
168+
* "argOne": "value1",
169+
* "argTwo": "value2",
170+
* "argThree": "value3",
171+
* "four": 4444,
172+
* "five": 555555
180173
* }
181174
* \`\`\`
182175
*
183-
* \`\`\`graphql
184-
* query {
185-
* fieldName(argOne: "value1", argTwo: "value2", argThree: "value3", four: 4444, five: 55555)
186-
* }
176+
* \`\`\`json
177+
* { "argOne": "value1", "argTwo": "value2", "argThree": "value3", "four": 4444, "five": 55555 }
187178
* \`\`\`
188179
*/
189180
`.trimStart(),

‎crates/oxc_formatter/AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ After changing AST shapes or the generators, regenerate with `just ast`, never h
4545
- See `tests/jsdoc/fixtures` for the covered behavior
4646
- See also `tests/jsdoc/upstream-jsdoc-bugs.md`
4747
- Implemented in Rust as a comment-text rewrite at print time (`formatter/trivia.rs`), not an IR transform
48-
- Non-JS fenced code blocks go through the session's optional `StringEmbedder`; without it (or on failure) they stay verbatim
48+
- Non-JS fenced code blocks of the `prettier-plugin-jsdoc` set go through the session's optional `StringEmbedder`;
49+
without it (or on failure), and for any other language, they stay verbatim
4950
- Covered by plain fixture-pair tests (`--test jsdoc`, committed input/expected pairs);
5051
a mismatch is a failing test, not a tracked conformance-report entry
5152

‎crates/oxc_formatter/src/formatter/jsdoc/embedded.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ fn parse_and_build<'a>(
2525
Some(code)
2626
}
2727

28-
/// Returns `true` if the fenced code block language is JS/TS/JSX/TSX.
28+
/// Returns `true` if the fenced code block language is JS/TS/JSX/TSX (case-insensitive).
2929
pub(super) fn is_js_ts_lang(lang: &str) -> bool {
30-
matches!(lang, "js" | "javascript" | "jsx" | "ts" | "typescript" | "tsx")
30+
["js", "javascript", "jsx", "ts", "typescript", "tsx"]
31+
.iter()
32+
.any(|name| lang.eq_ignore_ascii_case(name))
3133
}
3234

3335
/// Count unescaped backticks on a line and update template literal depth.

‎crates/oxc_formatter/src/formatter/jsdoc/mdast_serialize/nodes.rs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -743,12 +743,17 @@ fn serialize_code(
743743
}
744744
}
745745

746+
/// Non-JS/TS fence languages a description embeds: the `prettier-plugin-jsdoc` set (its `parserSynonyms`),
747+
/// matched case-insensitively as there.
748+
/// Any other stays verbatim; add one on demand, as long as the host's dispatcher routes it.
749+
const EMBEDDED_FENCE_LANGUAGES: [&str; 6] = ["css", "less", "scss", "json", "yaml", "html"];
750+
746751
/// Format code block content in a JSDoc Markdown description.
747752
///
748753
/// Routing:
749754
/// - JS/TS code (fenced with a JS/TS lang tag, fenced with no lang tag, or indented blocks):
750755
/// formatted in-process via [`format_jsdoc_js_snippet`] (`oxc_formatter`'s own parser/formatter).
751-
/// - Non-JS/TS fenced code (css, html, graphql, etc.):
756+
/// - Non-JS/TS fenced code of [`EMBEDDED_FENCE_LANGUAGES`]:
752757
/// when the session carries a string embedder, routed through it (the string channel);
753758
/// absent one (Rust-only conformance, or the language has no native branch), preserved verbatim.
754759
///
@@ -764,8 +769,10 @@ fn format_code_value<'a>(
764769
if let Some(l) = lang
765770
&& !is_js_ts_lang(l)
766771
{
767-
if let Some(embed) = opts.session.string_embedder()
768-
&& let Ok(formatted) = embed(l, code, width)
772+
if let Some(language) =
773+
EMBEDDED_FENCE_LANGUAGES.into_iter().find(|name| l.eq_ignore_ascii_case(name))
774+
&& let Some(embed) = opts.session.string_embedder()
775+
&& let Ok(formatted) = embed(language, code, width)
769776
{
770777
return Cow::Owned(formatted);
771778
}

0 commit comments

Comments
 (0)