Skip to content

Commit 356a549

Browse files
committed
docs(oxfmt): Add markdownDescription fields and unify the schema generation process.
With this change, the descriptions for each field in the JSON schema are rendered with proper markdown formatting in VS Code and other editors based on VS Code. This now matches the implementation for the Oxlintrc schema generation.
1 parent ac3569a commit 356a549

File tree

4 files changed

+132
-49
lines changed

4 files changed

+132
-49
lines changed

crates/oxc_formatter/src/service/oxfmtrc.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::path::Path;
22

3-
use schemars::JsonSchema;
3+
use schemars::{JsonSchema, schema_for};
44
use serde::{Deserialize, Deserializer, Serialize};
55
use serde_json::Value;
66

@@ -532,6 +532,60 @@ impl Oxfmtrc {
532532
// e.g. `plugins`, `htmlWhitespaceSensitivity`, `vueIndentScriptAndStyle`, etc.
533533
// Other options defined independently by plugins are also left as they are.
534534
}
535+
536+
/// Generates the JSON schema for Oxfmtrc configuration files.
537+
///
538+
/// # Panics
539+
/// Panics if the schema generation fails.
540+
pub fn generate_schema_json() -> String {
541+
let mut schema = schema_for!(Oxfmtrc);
542+
543+
// Allow comments and trailing commas for vscode-json-languageservice
544+
// NOTE: This is NOT part of standard JSON Schema specification
545+
// https://github.com/microsoft/vscode-json-languageservice/blob/fb83547762901f32d8449d57e24666573016b10c/src/jsonLanguageTypes.ts#L151-L159
546+
schema.schema.extensions.insert("allowComments".to_string(), serde_json::Value::Bool(true));
547+
schema
548+
.schema
549+
.extensions
550+
.insert("allowTrailingCommas".to_string(), serde_json::Value::Bool(true));
551+
552+
// Inject markdownDescription fields for better editor support (e.g., VS Code)
553+
let mut json = serde_json::to_value(&schema).unwrap();
554+
Self::inject_markdown_descriptions(&mut json);
555+
556+
serde_json::to_string_pretty(&json).unwrap()
557+
}
558+
559+
/// Recursively inject `markdownDescription` fields into the JSON schema.
560+
/// This is a non-standard field that some editors (like VS Code) use to render
561+
/// markdown in hover tooltips.
562+
fn inject_markdown_descriptions(value: &mut serde_json::Value) {
563+
match value {
564+
serde_json::Value::Object(map) => {
565+
// If this object has a `description` field, copy it to `markdownDescription`
566+
if let Some(serde_json::Value::String(desc_str)) = map.get("description") {
567+
map.insert(
568+
"markdownDescription".to_string(),
569+
serde_json::Value::String(desc_str.clone()),
570+
);
571+
}
572+
573+
// Recursively process all values in the object
574+
for value in map.values_mut() {
575+
Self::inject_markdown_descriptions(value);
576+
}
577+
}
578+
serde_json::Value::Array(items) => {
579+
// Recursively process all items in the array
580+
for item in items {
581+
Self::inject_markdown_descriptions(item);
582+
}
583+
}
584+
_ => {
585+
// Primitive values don't need processing
586+
}
587+
}
588+
}
535589
}
536590

537591
// ---

crates/oxc_formatter/tests/schema.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,7 @@ use project_root::get_project_root;
88
#[test]
99
fn test_schema_json() {
1010
let path = get_project_root().unwrap().join("npm/oxfmt/configuration_schema.json");
11-
let mut schema = schemars::schema_for!(Oxfmtrc);
12-
// Allow comments and trailing commas for vscode-json-languageservice
13-
// NOTE: This is NOT part of standard JSON Schema specification
14-
// https://github.com/microsoft/vscode-json-languageservice/blob/fb83547762901f32d8449d57e24666573016b10c/src/jsonLanguageTypes.ts#L151-L159
15-
schema.schema.extensions.insert("allowComments".to_string(), serde_json::Value::Bool(true));
16-
schema
17-
.schema
18-
.extensions
19-
.insert("allowTrailingCommas".to_string(), serde_json::Value::Bool(true));
20-
let json = serde_json::to_string_pretty(&schema).unwrap();
11+
let json = Oxfmtrc::generate_schema_json();
2112
let existing_json = fs::read_to_string(&path).unwrap_or_default();
2213
if existing_json.trim() != json.trim() {
2314
std::fs::write(&path, &json).unwrap();

crates/oxc_formatter/tests/snapshots/schema_json.snap

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,24 @@ expression: json
1717
{
1818
"type": "null"
1919
}
20-
]
20+
],
21+
"markdownDescription": "Include parentheses around a sole arrow function parameter. (Default: `\"always\"`)"
2122
},
2223
"bracketSameLine": {
2324
"description": "Put the `>` of a multi-line JSX element at the end of the last line\ninstead of being alone on the next line. (Default: `false`)",
2425
"type": [
2526
"boolean",
2627
"null"
27-
]
28+
],
29+
"markdownDescription": "Put the `>` of a multi-line JSX element at the end of the last line\ninstead of being alone on the next line. (Default: `false`)"
2830
},
2931
"bracketSpacing": {
3032
"description": "Print spaces between brackets in object literals. (Default: `true`)",
3133
"type": [
3234
"boolean",
3335
"null"
34-
]
36+
],
37+
"markdownDescription": "Print spaces between brackets in object literals. (Default: `true`)"
3538
},
3639
"embeddedLanguageFormatting": {
3740
"description": "Control whether formats quoted code embedded in the file. (Default: `\"auto\"`)",
@@ -42,7 +45,8 @@ expression: json
4245
{
4346
"type": "null"
4447
}
45-
]
48+
],
49+
"markdownDescription": "Control whether formats quoted code embedded in the file. (Default: `\"auto\"`)"
4650
},
4751
"endOfLine": {
4852
"description": "Which end of line characters to apply. (Default: `\"lf\"`)",
@@ -53,7 +57,8 @@ expression: json
5357
{
5458
"type": "null"
5559
}
56-
]
60+
],
61+
"markdownDescription": "Which end of line characters to apply. (Default: `\"lf\"`)"
5762
},
5863
"experimentalSortImports": {
5964
"description": "Experimental: Sort import statements. Disabled by default.",
@@ -64,7 +69,8 @@ expression: json
6469
{
6570
"type": "null"
6671
}
67-
]
72+
],
73+
"markdownDescription": "Experimental: Sort import statements. Disabled by default."
6874
},
6975
"experimentalSortPackageJson": {
7076
"description": "Experimental: Sort `package.json` keys. (Default: true)",
@@ -79,14 +85,16 @@ expression: json
7985
],
8086
"items": {
8187
"type": "string"
82-
}
88+
},
89+
"markdownDescription": "Ignore files matching these glob patterns. Current working directory is used as the root."
8390
},
8491
"jsxSingleQuote": {
8592
"description": "Use single quotes instead of double quotes in JSX. (Default: `false`)",
8693
"type": [
8794
"boolean",
8895
"null"
89-
]
96+
],
97+
"markdownDescription": "Use single quotes instead of double quotes in JSX. (Default: `false`)"
9098
},
9199
"objectWrap": {
92100
"description": "How to wrap object literals when they could fit on one line or span multiple lines. (Default: `\"preserve\"`)\nNOTE: In addition to Prettier's `\"preserve\"` and `\"collapse\"`, we also support `\"always\"`.",
@@ -97,7 +105,8 @@ expression: json
97105
{
98106
"type": "null"
99107
}
100-
]
108+
],
109+
"markdownDescription": "How to wrap object literals when they could fit on one line or span multiple lines. (Default: `\"preserve\"`)\nNOTE: In addition to Prettier's `\"preserve\"` and `\"collapse\"`, we also support `\"always\"`."
101110
},
102111
"printWidth": {
103112
"description": "The line length that the printer will wrap on. (Default: `100`)",
@@ -106,7 +115,8 @@ expression: json
106115
"null"
107116
],
108117
"format": "uint16",
109-
"minimum": 0.0
118+
"minimum": 0.0,
119+
"markdownDescription": "The line length that the printer will wrap on. (Default: `100`)"
110120
},
111121
"quoteProps": {
112122
"description": "Change when properties in objects are quoted. (Default: `\"as-needed\"`)",
@@ -117,28 +127,32 @@ expression: json
117127
{
118128
"type": "null"
119129
}
120-
]
130+
],
131+
"markdownDescription": "Change when properties in objects are quoted. (Default: `\"as-needed\"`)"
121132
},
122133
"semi": {
123134
"description": "Print semicolons at the ends of statements. (Default: `true`)",
124135
"type": [
125136
"boolean",
126137
"null"
127-
]
138+
],
139+
"markdownDescription": "Print semicolons at the ends of statements. (Default: `true`)"
128140
},
129141
"singleAttributePerLine": {
130142
"description": "Put each attribute on a new line in JSX. (Default: `false`)",
131143
"type": [
132144
"boolean",
133145
"null"
134-
]
146+
],
147+
"markdownDescription": "Put each attribute on a new line in JSX. (Default: `false`)"
135148
},
136149
"singleQuote": {
137150
"description": "Use single quotes instead of double quotes. (Default: `false`)",
138151
"type": [
139152
"boolean",
140153
"null"
141-
]
154+
],
155+
"markdownDescription": "Use single quotes instead of double quotes. (Default: `false`)"
142156
},
143157
"tabWidth": {
144158
"description": "Number of spaces per indentation level. (Default: `2`)",
@@ -147,7 +161,8 @@ expression: json
147161
"null"
148162
],
149163
"format": "uint8",
150-
"minimum": 0.0
164+
"minimum": 0.0,
165+
"markdownDescription": "Number of spaces per indentation level. (Default: `2`)"
151166
},
152167
"trailingComma": {
153168
"description": "Print trailing commas wherever possible. (Default: `\"all\"`)",
@@ -158,14 +173,16 @@ expression: json
158173
{
159174
"type": "null"
160175
}
161-
]
176+
],
177+
"markdownDescription": "Print trailing commas wherever possible. (Default: `\"all\"`)"
162178
},
163179
"useTabs": {
164180
"description": "Use tabs for indentation or spaces. (Default: `false`)",
165181
"type": [
166182
"boolean",
167183
"null"
168-
]
184+
],
185+
"markdownDescription": "Use tabs for indentation or spaces. (Default: `false`)"
169186
}
170187
},
171188
"allowComments": true,
@@ -222,7 +239,8 @@ expression: json
222239
"items": {
223240
"type": "string"
224241
}
225-
}
242+
},
243+
"markdownDescription": "Custom groups configuration for organizing imports.\nEach array element represents a group, and multiple group names in the same array are treated as one.\nAccepts both `string` and `string[]` as group elements."
226244
},
227245
"ignoreCase": {
228246
"default": true,
@@ -280,5 +298,6 @@ expression: json
280298
"none"
281299
]
282300
}
283-
}
301+
},
302+
"markdownDescription": "Configuration options for the formatter.\nMost options are the same as Prettier's options.\nSee also <https://prettier.io/docs/options>"
284303
}

0 commit comments

Comments
 (0)