Skip to content

Commit b77f254

Browse files
committed
feat(oxfmt,formatter): Support embeddedLanguageFormatting option (#15216)
Fixes #13427 I will add tests for this later(another day, another PR), with refactoring all tests...
1 parent 898d6fe commit b77f254

File tree

5 files changed

+116
-12
lines changed

5 files changed

+116
-12
lines changed

apps/oxfmt/src/service.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,25 @@ impl FormatService {
8888
return;
8989
}
9090

91-
let embedded_formatter = {
91+
let base_formatter = Formatter::new(&allocator, self.format_options.clone());
92+
let formatter = if self.format_options.embedded_language_formatting.is_off() {
93+
base_formatter
94+
} else {
9295
#[cfg(feature = "napi")]
9396
{
94-
self.external_formatter
97+
let external_formatter = self
98+
.external_formatter
9599
.as_ref()
96-
.map(crate::prettier_plugins::ExternalFormatter::to_embedded_formatter)
100+
.map(crate::prettier_plugins::ExternalFormatter::to_embedded_formatter);
101+
base_formatter.with_embedded_formatter(external_formatter)
97102
}
98103
#[cfg(not(feature = "napi"))]
99104
{
100-
None
105+
base_formatter
101106
}
102107
};
103108

104-
let code = Formatter::new(&allocator, self.format_options.clone())
105-
.with_embedded_formatter(embedded_formatter)
106-
.build(&ret.program);
109+
let code = formatter.build(&ret.program);
107110

108111
let elapsed = start_time.elapsed();
109112
let is_changed = source_text != code;

crates/oxc_formatter/src/options.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::{
1212
write,
1313
};
1414

15-
// TODO: rename these to align with prettier
1615
#[derive(Debug, Default, Clone)]
1716
pub struct FormatOptions {
1817
/// The indent style.
@@ -63,6 +62,9 @@ pub struct FormatOptions {
6362
/// - `"end"`: Places the operator at the end of the current line (default).
6463
pub experimental_operator_position: OperatorPosition,
6564

65+
/// Enable formatting for embedded languages (e.g., CSS, SQL, GraphQL) within template literals. Defaults to "auto".
66+
pub embedded_language_formatting: EmbeddedLanguageFormatting,
67+
6668
// TODO: `FormatOptions`? Split out as `TransformOptions`?
6769
/// Sort import statements. By default disabled.
6870
pub experimental_sort_imports: Option<SortImports>,
@@ -86,6 +88,7 @@ impl FormatOptions {
8688
attribute_position: AttributePosition::default(),
8789
expand: Expand::default(),
8890
experimental_operator_position: OperatorPosition::default(),
91+
embedded_language_formatting: EmbeddedLanguageFormatting::default(),
8992
experimental_sort_imports: None,
9093
}
9194
}
@@ -112,6 +115,7 @@ impl fmt::Display for FormatOptions {
112115
writeln!(f, "Attribute Position: {}", self.attribute_position)?;
113116
writeln!(f, "Expand lists: {}", self.expand)?;
114117
writeln!(f, "Experimental operator position: {}", self.experimental_operator_position)?;
118+
writeln!(f, "Embedded language formatting: {}", self.embedded_language_formatting)?;
115119
writeln!(f, "Experimental sort imports: {:?}", self.experimental_sort_imports)
116120
}
117121
}
@@ -914,6 +918,47 @@ impl fmt::Display for OperatorPosition {
914918
}
915919
}
916920

921+
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
922+
pub enum EmbeddedLanguageFormatting {
923+
/// Enable formatting for embedded languages.
924+
#[default]
925+
Auto,
926+
/// Disable formatting for embedded languages.
927+
Off,
928+
}
929+
930+
impl EmbeddedLanguageFormatting {
931+
pub const fn is_auto(self) -> bool {
932+
matches!(self, Self::Auto)
933+
}
934+
935+
pub const fn is_off(self) -> bool {
936+
matches!(self, Self::Off)
937+
}
938+
}
939+
940+
impl FromStr for EmbeddedLanguageFormatting {
941+
type Err = &'static str;
942+
943+
fn from_str(s: &str) -> Result<Self, Self::Err> {
944+
match s {
945+
"auto" => Ok(Self::Auto),
946+
"off" => Ok(Self::Off),
947+
_ => Err("Value not supported for EmbeddedLanguageFormatting"),
948+
}
949+
}
950+
}
951+
952+
impl fmt::Display for EmbeddedLanguageFormatting {
953+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
954+
let s = match self {
955+
EmbeddedLanguageFormatting::Auto => "Auto",
956+
EmbeddedLanguageFormatting::Off => "Off",
957+
};
958+
f.write_str(s)
959+
}
960+
}
961+
917962
// ---
918963

919964
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]

crates/oxc_formatter/src/service/oxfmtrc.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use schemars::JsonSchema;
44
use serde::{Deserialize, Serialize};
55

66
use crate::{
7-
ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing, Expand, FormatOptions,
8-
IndentStyle, IndentWidth, LineEnding, LineWidth, OperatorPosition, QuoteProperties, QuoteStyle,
9-
Semicolons, SortImports, SortOrder, TrailingCommas,
7+
ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing,
8+
EmbeddedLanguageFormatting, Expand, FormatOptions, IndentStyle, IndentWidth, LineEnding,
9+
LineWidth, OperatorPosition, QuoteProperties, QuoteStyle, Semicolons, SortImports, SortOrder,
10+
TrailingCommas,
1011
};
1112

1213
/// Configuration options for the formatter.
@@ -64,6 +65,10 @@ pub struct Oxfmtrc {
6465
// TODO: Experimental: Use curious ternaries which move `?` after the condition. (Default: false)
6566
// #[serde(skip_serializing_if = "Option::is_none")]
6667
// pub experimental_ternaries: Option<bool>,
68+
/// Control whether formats quoted code embedded in the file. (Default: "auto")
69+
#[serde(skip_serializing_if = "Option::is_none")]
70+
pub embedded_language_formatting: Option<EmbeddedLanguageFormattingConfig>,
71+
6772
/// Experimental: Sort import statements. Disabled by default.
6873
#[serde(skip_serializing_if = "Option::is_none")]
6974
pub experimental_sort_imports: Option<SortImportsConfig>,
@@ -126,6 +131,14 @@ pub enum OperatorPositionConfig {
126131
End,
127132
}
128133

134+
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema)]
135+
#[serde(rename_all = "lowercase")]
136+
pub enum EmbeddedLanguageFormattingConfig {
137+
#[default]
138+
Auto,
139+
Off,
140+
}
141+
129142
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
130143
#[serde(rename_all = "camelCase", default)]
131144
pub struct SortImportsConfig {
@@ -291,6 +304,13 @@ impl Oxfmtrc {
291304
};
292305
}
293306

307+
if let Some(embedded_language_formatting) = self.embedded_language_formatting {
308+
options.embedded_language_formatting = match embedded_language_formatting {
309+
EmbeddedLanguageFormattingConfig::Auto => EmbeddedLanguageFormatting::Auto,
310+
EmbeddedLanguageFormattingConfig::Off => EmbeddedLanguageFormatting::Off,
311+
};
312+
}
313+
294314
// Below are our own extensions
295315

296316
if let Some(sort_imports_config) = self.experimental_sort_imports {

crates/oxc_formatter/tests/snapshots/schema_json.snap

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ expression: json
3333
"null"
3434
]
3535
},
36+
"embeddedLanguageFormatting": {
37+
"description": "Control whether formats quoted code embedded in the file. (Default: \"auto\")",
38+
"anyOf": [
39+
{
40+
"$ref": "#/definitions/EmbeddedLanguageFormattingConfig"
41+
},
42+
{
43+
"type": "null"
44+
}
45+
]
46+
},
3647
"endOfLine": {
3748
"description": "Which end of line characters to apply. (Default: \"lf\")",
3849
"anyOf": [
@@ -171,6 +182,13 @@ expression: json
171182
"avoid"
172183
]
173184
},
185+
"EmbeddedLanguageFormattingConfig": {
186+
"type": "string",
187+
"enum": [
188+
"auto",
189+
"off"
190+
]
191+
},
174192
"EndOfLineConfig": {
175193
"type": "string",
176194
"enum": [

npm/oxfmt/configuration_schema.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@
2929
"null"
3030
]
3131
},
32+
"embeddedLanguageFormatting": {
33+
"description": "Control whether formats quoted code embedded in the file. (Default: \"auto\")",
34+
"anyOf": [
35+
{
36+
"$ref": "#/definitions/EmbeddedLanguageFormattingConfig"
37+
},
38+
{
39+
"type": "null"
40+
}
41+
]
42+
},
3243
"endOfLine": {
3344
"description": "Which end of line characters to apply. (Default: \"lf\")",
3445
"anyOf": [
@@ -167,6 +178,13 @@
167178
"avoid"
168179
]
169180
},
181+
"EmbeddedLanguageFormattingConfig": {
182+
"type": "string",
183+
"enum": [
184+
"auto",
185+
"off"
186+
]
187+
},
170188
"EndOfLineConfig": {
171189
"type": "string",
172190
"enum": [
@@ -244,4 +262,4 @@
244262
]
245263
}
246264
}
247-
}
265+
}

0 commit comments

Comments
 (0)