diff --git a/Cargo.lock b/Cargo.lock index 4185f15bf4..e26dd67b1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -887,6 +887,12 @@ dependencies = [ "libc", ] +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -1183,6 +1189,7 @@ dependencies = [ "percent-encoding", "phf 0.11.2", "pretty_assertions", + "pretty_yaml", "quick-junit", "rand", "regex", @@ -5074,6 +5081,17 @@ dependencies = [ "yansi", ] +[[package]] +name = "pretty_yaml" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ba50511591c8e1d84125f7e2e6d17ccb06865c484b812f5ee3af61f42a66be" +dependencies = [ + "rowan", + "tiny_pretty", + "yaml_parser", +] + [[package]] name = "prettyplease" version = "0.1.25" @@ -5615,6 +5633,19 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rowan" +version = "0.15.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49" +dependencies = [ + "countme", + "hashbrown", + "memoffset 0.9.1", + "rustc-hash", + "text-size", +] + [[package]] name = "rsa" version = "0.9.6" @@ -7105,6 +7136,12 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny_pretty" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b3f46f0549180b9c6f7f76270903f1a06867c43a03998b99dce81aa1760c3b2" + [[package]] name = "tinyvec" version = "1.6.0" @@ -7254,7 +7291,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -8218,6 +8255,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -8314,6 +8360,16 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +[[package]] +name = "yaml_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a6a39b6b5ba0d02c910d05d7fbc366a4befb8901ea107dcde9c1c97acb8a366" +dependencies = [ + "rowan", + "winnow 0.6.15", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index e06cf77263..510c10ea9c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -132,6 +132,7 @@ p256.workspace = true pathdiff = "0.2.1" percent-encoding.workspace = true phf.workspace = true +pretty_yaml = "=0.4.0" quick-junit = "^0.3.5" rand = { workspace = true, features = ["small_rng"] } regex.workspace = true diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 59e535ee0f..75987e9d08 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -2002,7 +2002,8 @@ Ignore formatting a file by adding an ignore comment at the top of the file: // prefer using ts for formatting instead of js because ts works in more scenarios .default_value("ts") .value_parser([ - "ts", "tsx", "js", "jsx", "md", "json", "jsonc", "ipynb", + "ts", "tsx", "js", "jsx", "md", "json", "jsonc", "yml", "yaml", + "ipynb", ]), ) .arg( diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs index baecb482fe..43a97a72ed 100644 --- a/cli/tools/fmt.rs +++ b/cli/tools/fmt.rs @@ -233,6 +233,8 @@ fn format_markdown( | "typescript" | "json" | "jsonc" + | "yml" + | "yaml" ) { // It's important to tell dprint proper file extension, otherwise // it might parse the file twice. @@ -244,19 +246,28 @@ fn format_markdown( let fake_filename = PathBuf::from(format!("deno_fmt_stdin.{extension}")); - if matches!(extension, "json" | "jsonc") { - let mut json_config = get_resolved_json_config(fmt_options); - json_config.line_width = line_width; - dprint_plugin_json::format_text(&fake_filename, text, &json_config) - } else { - let mut codeblock_config = - get_resolved_typescript_config(fmt_options); - codeblock_config.line_width = line_width; - dprint_plugin_typescript::format_text( - &fake_filename, - text.to_string(), - &codeblock_config, + match extension { + "json" | "jsonc" => { + let mut json_config = get_resolved_json_config(fmt_options); + json_config.line_width = line_width; + dprint_plugin_json::format_text(&fake_filename, text, &json_config) + } + "yml" | "yaml" => pretty_yaml::format_text( + text, + &get_resolved_yaml_config(fmt_options), ) + .map(Some) + .map_err(AnyError::from), + _ => { + let mut codeblock_config = + get_resolved_typescript_config(fmt_options); + codeblock_config.line_width = line_width; + dprint_plugin_typescript::format_text( + &fake_filename, + text.to_string(), + &codeblock_config, + ) + } } } else { Ok(None) @@ -290,6 +301,12 @@ pub fn format_file( format_markdown(file_text, fmt_options) } "json" | "jsonc" => format_json(file_path, file_text, fmt_options), + "yml" | "yaml" => pretty_yaml::format_text( + file_text, + &get_resolved_yaml_config(fmt_options), + ) + .map(Some) + .map_err(AnyError::from), "ipynb" => dprint_plugin_jupyter::format_text( file_text, |file_path: &Path, file_text: String| { @@ -687,6 +704,41 @@ fn get_resolved_json_config( builder.build() } +fn get_resolved_yaml_config( + options: &FmtOptionsConfig, +) -> pretty_yaml::config::FormatOptions { + use pretty_yaml::config::*; + + let layout_options = LayoutOptions { + print_width: options.line_width.unwrap_or(80) as usize, + use_tabs: options.use_tabs.unwrap_or_default(), + indent_width: options.indent_width.unwrap_or(2) as usize, + line_break: LineBreak::Lf, + }; + + let language_options = LanguageOptions { + quotes: if let Some(true) = options.single_quote { + Quotes::PreferSingle + } else { + Quotes::PreferDouble + }, + trailing_comma: true, + format_comments: false, + indent_block_sequence_in_map: true, + brace_spacing: true, + bracket_spacing: false, + dash_spacing: DashSpacing::OneSpace, + trim_trailing_whitespaces: true, + trim_trailing_zero: false, + ignore_comment_directive: "deno-fmt-ignore".into(), + }; + + FormatOptions { + layout: layout_options, + language: language_options, + } +} + struct FileContents { text: String, had_bom: bool, @@ -785,6 +837,8 @@ fn is_supported_ext_fmt(path: &Path) -> bool { | "mdwn" | "mdown" | "markdown" + | "yml" + | "yaml" | "ipynb" ) }) @@ -819,6 +873,10 @@ mod test { assert!(is_supported_ext_fmt(Path::new("foo.JSONC"))); assert!(is_supported_ext_fmt(Path::new("foo.json"))); assert!(is_supported_ext_fmt(Path::new("foo.JsON"))); + assert!(is_supported_ext_fmt(Path::new("foo.yml"))); + assert!(is_supported_ext_fmt(Path::new("foo.Yml"))); + assert!(is_supported_ext_fmt(Path::new("foo.yaml"))); + assert!(is_supported_ext_fmt(Path::new("foo.YaML"))); assert!(is_supported_ext_fmt(Path::new("foo.ipynb"))); } diff --git a/tests/integration/fmt_tests.rs b/tests/integration/fmt_tests.rs index 4174548887..17adef6f84 100644 --- a/tests/integration/fmt_tests.rs +++ b/tests/integration/fmt_tests.rs @@ -37,6 +37,12 @@ fn fmt_test() { let badly_formatted_ipynb = t.path().join("badly_formatted.ipynb"); badly_formatted_original_ipynb.copy(&badly_formatted_ipynb); + let fixed_yaml = testdata_fmt_dir.join("badly_formatted_fixed.yaml"); + let badly_formatted_original_yaml = + testdata_fmt_dir.join("badly_formatted.yaml"); + let badly_formatted_yaml = t.path().join("badly_formatted.yaml"); + badly_formatted_original_yaml.copy(&badly_formatted_yaml); + // First, check formatting by ignoring the badly formatted file. let output = context .new_command() @@ -44,10 +50,10 @@ fn fmt_test() { .args_vec(vec![ "fmt".to_string(), format!( - "--ignore={badly_formatted_js},{badly_formatted_md},{badly_formatted_json},{badly_formatted_ipynb}", + "--ignore={badly_formatted_js},{badly_formatted_md},{badly_formatted_json},{badly_formatted_yaml},{badly_formatted_ipynb}", ), format!( - "--check {badly_formatted_js} {badly_formatted_md} {badly_formatted_json} {badly_formatted_ipynb}", + "--check {badly_formatted_js} {badly_formatted_md} {badly_formatted_json} {badly_formatted_yaml} {badly_formatted_ipynb}", ), ]) .run(); @@ -66,6 +72,7 @@ fn fmt_test() { badly_formatted_js.to_string(), badly_formatted_md.to_string(), badly_formatted_json.to_string(), + badly_formatted_yaml.to_string(), badly_formatted_ipynb.to_string(), ]) .run(); @@ -82,6 +89,7 @@ fn fmt_test() { badly_formatted_js.to_string(), badly_formatted_md.to_string(), badly_formatted_json.to_string(), + badly_formatted_yaml.to_string(), badly_formatted_ipynb.to_string(), ]) .run(); @@ -92,14 +100,17 @@ fn fmt_test() { let expected_js = fixed_js.read_to_string(); let expected_md = fixed_md.read_to_string(); let expected_json = fixed_json.read_to_string(); + let expected_yaml = fixed_yaml.read_to_string(); let expected_ipynb = fixed_ipynb.read_to_string(); let actual_js = badly_formatted_js.read_to_string(); let actual_md = badly_formatted_md.read_to_string(); let actual_json = badly_formatted_json.read_to_string(); + let actual_yaml = badly_formatted_yaml.read_to_string(); let actual_ipynb = badly_formatted_ipynb.read_to_string(); assert_eq!(expected_js, actual_js); assert_eq!(expected_md, actual_md); assert_eq!(expected_json, actual_json); + assert_eq!(expected_yaml, actual_yaml); assert_eq!(expected_ipynb, actual_ipynb); } diff --git a/tests/testdata/fmt/badly_formatted.md b/tests/testdata/fmt/badly_formatted.md index 26afe483b1..05a4b2f97c 100644 --- a/tests/testdata/fmt/badly_formatted.md +++ b/tests/testdata/fmt/badly_formatted.md @@ -43,4 +43,9 @@ function foo(): number { "numbers": ["1", "2"] } -``` \ No newline at end of file +``` + +```yaml +- item1 +- item2 +``` diff --git a/tests/testdata/fmt/badly_formatted.yaml b/tests/testdata/fmt/badly_formatted.yaml new file mode 100644 index 0000000000..69c89f377e --- /dev/null +++ b/tests/testdata/fmt/badly_formatted.yaml @@ -0,0 +1,6 @@ +key1 : value1 +key2 : value2 +key3: + - item1 + - item2 + - item3 diff --git a/tests/testdata/fmt/badly_formatted_fixed.md b/tests/testdata/fmt/badly_formatted_fixed.md index 8ba74cac3b..7a7d1913b7 100644 --- a/tests/testdata/fmt/badly_formatted_fixed.md +++ b/tests/testdata/fmt/badly_formatted_fixed.md @@ -35,3 +35,8 @@ function foo(): number { "numbers": ["1", "2"] } ``` + +```yaml +- item1 +- item2 +``` diff --git a/tests/testdata/fmt/badly_formatted_fixed.yaml b/tests/testdata/fmt/badly_formatted_fixed.yaml new file mode 100644 index 0000000000..e167d34c2f --- /dev/null +++ b/tests/testdata/fmt/badly_formatted_fixed.yaml @@ -0,0 +1,6 @@ +key1: value1 +key2: value2 +key3: + - item1 + - item2 + - item3