From 81d7fa923d61f6eb162469dd78adc0cacc3287b8 Mon Sep 17 00:00:00 2001 From: Mads Hougesen Date: Tue, 12 Mar 2024 17:00:27 +0100 Subject: [PATCH] feat: add support for deno fmt --- .github/workflows/validate.yml | 4 ++ README.md | 58 ++++++++--------- schemas/v0.0.1/mdsf.schema.json | 6 +- src/formatters/deno_format.rs | 109 ++++++++++++++++++++++++++++++++ src/formatters/mod.rs | 1 + src/languages/javascript.rs | 42 +++++++++--- src/languages/json.rs | 41 ++++++++++-- src/languages/typescript.rs | 43 +++++++++++-- 8 files changed, 255 insertions(+), 49 deletions(-) create mode 100644 src/formatters/deno_format.rs diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 487fd027..ec7f9539 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -78,6 +78,10 @@ jobs: - uses: crystal-lang/install-crystal@v1 # roc_format - uses: hasnep/setup-roc@v0.1.1 + # deno_fmt + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x - run: rustup toolchain install stable --profile minimal - run: rustup component add rustfmt clippy diff --git a/README.md b/README.md index 48a1d41f..4c78660c 100644 --- a/README.md +++ b/README.md @@ -45,32 +45,32 @@ mdsf init > > Only formatters that are already installed will be used. -| Language | Formatters | -| ----------- | ------------------------------------------- | -| C | `clang-format` | -| CSS | `prettier` | -| Cpp | `clang-format` | -| Crystal | `crystal_format` | -| Dart | `dart_format` | -| Elixir | `mix_format` | -| Gleam | `gleam_format` | -| Go | `gofmt`, `gofumpt` | -| HTML | `prettier` | -| JSON | `prettier`, `biome`, `clang-format` | -| Java | `clang-format` | -| JavaScript | `prettier`, `biome`, `clang-format` | -| Lua | `stylua` | -| Nim | `nimpretty` | -| Objective C | `clang-format` | -| Protobuf | `clang-format` | -| Python | `ruff`, `black`, `blue`, `yapf`, `autopep8` | -| Roc | `roc_format` | -| Ruby | `rubocop` | -| Rust | `rustfmt` | -| SQL | `sqlfluff`, `sql-formatter` | -| Shell | `shfmt` | -| TOML | `taplo` | -| TypeScript | `prettier`, `biome` | -| Vue | `prettier` | -| YAML | `prettier` | -| Zig | `zigfmt` | +| Language | Formatters | +| ----------- | ----------------------------------------------- | +| C | `clang-format` | +| CSS | `prettier` | +| Cpp | `clang-format` | +| Crystal | `crystal_format` | +| Dart | `dart_format` | +| Elixir | `mix_format` | +| Gleam | `gleam_format` | +| Go | `gofmt`, `gofumpt` | +| HTML | `prettier` | +| JSON | `prettier`, `biome`, `clang-format`, `deno_fmt` | +| Java | `clang-format` | +| JavaScript | `prettier`, `biome`, `clang-format`, `deno_fmt` | +| Lua | `stylua` | +| Nim | `nimpretty` | +| Objective C | `clang-format` | +| Protobuf | `clang-format` | +| Python | `ruff`, `black`, `blue`, `yapf`, `autopep8` | +| Roc | `roc_format` | +| Ruby | `rubocop` | +| Rust | `rustfmt` | +| SQL | `sqlfluff`, `sql-formatter` | +| Shell | `shfmt` | +| TOML | `taplo` | +| TypeScript | `prettier`, `biome`, `deno_fmt` | +| Vue | `prettier` | +| YAML | `prettier` | +| Zig | `zigfmt` | diff --git a/schemas/v0.0.1/mdsf.schema.json b/schemas/v0.0.1/mdsf.schema.json index e650e020..7856e07d 100644 --- a/schemas/v0.0.1/mdsf.schema.json +++ b/schemas/v0.0.1/mdsf.schema.json @@ -574,7 +574,7 @@ }, "JavaScriptFormatter": { "type": "string", - "enum": ["prettier", "biome", "clang-format"] + "enum": ["prettier", "biome", "deno_fmt", "clang-format"] }, "Json": { "type": "object", @@ -595,7 +595,7 @@ }, "JsonFormatter": { "type": "string", - "enum": ["prettier", "biome", "clang-format"] + "enum": ["prettier", "biome", "deno_fmt", "clang-format"] }, "Lua": { "type": "object", @@ -868,7 +868,7 @@ }, "TypeScriptFormatter": { "type": "string", - "enum": ["prettier", "biome"] + "enum": ["prettier", "biome", "deno_fmt"] }, "Vue": { "type": "object", diff --git a/src/formatters/deno_format.rs b/src/formatters/deno_format.rs new file mode 100644 index 00000000..da5c4d64 --- /dev/null +++ b/src/formatters/deno_format.rs @@ -0,0 +1,109 @@ +use super::execute_command; + +#[inline] +pub fn format_using_deno_fmt( + snippet_path: &std::path::Path, +) -> std::io::Result<(bool, Option)> { + // NOTE: the biome docs recommend running biome using npx, and not directly + let mut cmd = std::process::Command::new("deno"); + + cmd.arg("fmt").arg("--quiet").arg(snippet_path); + + execute_command(&mut cmd, snippet_path) +} + +#[cfg(test)] +mod test_deno_fmt { + use crate::{formatters::setup_snippet, languages::Language}; + + use super::format_using_deno_fmt; + + #[test] + fn it_should_format_json() { + let input = " + { + // comments are allowed + \"key\": \"value\", + \"key2\": [ + \"value2\", + \"value3\", + 1 + , null] + } + "; + + let expected_output = "{ + // comments are allowed + \"key\": \"value\", + \"key2\": [ + \"value2\", + \"value3\", + 1, + null + ] +} +"; + + let snippet = setup_snippet(input, Language::Json.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_deno_fmt(snippet.path()) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } + + #[test] + fn it_should_format_javascript() { + let input = " + async function asyncAddition(a,b){ + return a+b + } + + "; + + let expected_output = "async function asyncAddition(a, b) { + return a + b; +} +"; + + let snippet = setup_snippet(input, Language::JavaScript.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_deno_fmt(snippet.path()) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } + + #[test] + fn it_should_format_typescript() { + let input = " + async function asyncAddition( a: \tnumber,b:number ) :Promise< number> + { + return a+b + } + + "; + + let expected_output = + "async function asyncAddition(a: number, b: number): Promise { + return a + b; +} +"; + + let snippet = setup_snippet(input, Language::TypeScript.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_deno_fmt(snippet.path()) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } +} diff --git a/src/formatters/mod.rs b/src/formatters/mod.rs index f5a7e7f2..f08f9b06 100644 --- a/src/formatters/mod.rs +++ b/src/formatters/mod.rs @@ -14,6 +14,7 @@ pub mod blue; pub mod clang_format; pub mod crystal_format; pub mod dart_format; +pub mod deno_format; pub mod gleam_format; pub mod gofmt; pub mod gofumpt; diff --git a/src/languages/javascript.rs b/src/languages/javascript.rs index 18249f5f..cb89fac9 100644 --- a/src/languages/javascript.rs +++ b/src/languages/javascript.rs @@ -4,7 +4,7 @@ use crate::{ config::default_enabled, formatters::{ biome::format_using_biome, clang_format::format_using_clang_format, - prettier::format_using_prettier, + deno_format::format_using_deno_fmt, prettier::format_using_prettier, }, }; @@ -18,6 +18,8 @@ pub enum JavaScriptFormatter { Prettier, #[serde(rename = "biome")] Biome, + #[serde(rename = "deno_fmt")] + DenoFmt, #[serde(rename = "clang-format")] ClangFormat, } @@ -49,14 +51,12 @@ impl LanguageFormatter for JavaScript { } match self.formatter { - JavaScriptFormatter::Biome => format_using_biome(snippet_path).map(|res| res.1), - JavaScriptFormatter::Prettier => { - format_using_prettier(snippet_path, true).map(|res| res.1) - } - JavaScriptFormatter::ClangFormat => { - format_using_clang_format(snippet_path).map(|res| res.1) - } + JavaScriptFormatter::Biome => format_using_biome(snippet_path), + JavaScriptFormatter::Prettier => format_using_prettier(snippet_path, true), + JavaScriptFormatter::ClangFormat => format_using_clang_format(snippet_path), + JavaScriptFormatter::DenoFmt => format_using_deno_fmt(snippet_path), } + .map(|res| res.1) } } @@ -179,4 +179,30 @@ mod test_javascript { assert_eq!(expected_output, output); } + + #[test] + fn test_deno_fmt() { + let input = " async function asyncAddition( a,b) { + a * b; + return a+b + } "; + + let expected_output = + "async function asyncAddition(a, b) {\n a * b;\n return a + b;\n}\n"; + + let l = JavaScript { + enabled: true, + formatter: JavaScriptFormatter::DenoFmt, + }; + + let snippet = setup_snippet(input, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + let output = l + .format(snippet_path) + .expect("it to not fail") + .expect("it to be a snippet"); + + assert_eq!(expected_output, output); + } } diff --git a/src/languages/json.rs b/src/languages/json.rs index 4afd4be8..2130cab0 100644 --- a/src/languages/json.rs +++ b/src/languages/json.rs @@ -4,7 +4,7 @@ use crate::{ config::default_enabled, formatters::{ biome::format_using_biome, clang_format::format_using_clang_format, - prettier::format_using_prettier, + deno_format::format_using_deno_fmt, prettier::format_using_prettier, }, }; @@ -18,6 +18,8 @@ pub enum JsonFormatter { Prettier, #[serde(rename = "biome")] Biome, + #[serde(rename = "deno_fmt")] + DenoFmt, #[serde(rename = "clang-format")] ClangFormat, } @@ -49,10 +51,12 @@ impl LanguageFormatter for Json { } match self.formatter { - JsonFormatter::Biome => format_using_biome(snippet_path).map(|res| res.1), - JsonFormatter::Prettier => format_using_prettier(snippet_path, true).map(|res| res.1), - JsonFormatter::ClangFormat => format_using_clang_format(snippet_path).map(|res| res.1), + JsonFormatter::Biome => format_using_biome(snippet_path), + JsonFormatter::Prettier => format_using_prettier(snippet_path, true), + JsonFormatter::ClangFormat => format_using_clang_format(snippet_path), + JsonFormatter::DenoFmt => format_using_deno_fmt(snippet_path), } + .map(|res| res.1) } } @@ -162,4 +166,33 @@ mod test_json { assert_eq!(output, expected_output); } + + #[test] + fn test_deno_fmt() { + let l = Json { + enabled: true, + formatter: JsonFormatter::DenoFmt, + }; + + let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + let output = l + .format(snippet_path) + .expect("it to not fail") + .expect("it to be a snippet"); + + let expected_output = "{ + \"key\": \"value\", + \"key2\": [ + \"value2\", + \"value3\", + 1, + null + ] +} +"; + + assert_eq!(output, expected_output); + } } diff --git a/src/languages/typescript.rs b/src/languages/typescript.rs index 86745f0f..05f9f345 100644 --- a/src/languages/typescript.rs +++ b/src/languages/typescript.rs @@ -2,7 +2,10 @@ use schemars::JsonSchema; use crate::{ config::default_enabled, - formatters::{biome::format_using_biome, prettier::format_using_prettier}, + formatters::{ + biome::format_using_biome, deno_format::format_using_deno_fmt, + prettier::format_using_prettier, + }, }; use super::LanguageFormatter; @@ -15,6 +18,8 @@ pub enum TypeScriptFormatter { Prettier, #[serde(rename = "biome")] Biome, + #[serde(rename = "deno_fmt")] + DenoFmt, } #[derive(Debug, serde::Serialize, serde::Deserialize, JsonSchema)] @@ -44,11 +49,11 @@ impl LanguageFormatter for TypeScript { } match self.formatter { - TypeScriptFormatter::Biome => format_using_biome(snippet_path).map(|res| res.1), - TypeScriptFormatter::Prettier => { - format_using_prettier(snippet_path, true).map(|res| res.1) - } + TypeScriptFormatter::Biome => format_using_biome(snippet_path), + TypeScriptFormatter::Prettier => format_using_prettier(snippet_path, true), + TypeScriptFormatter::DenoFmt => format_using_deno_fmt(snippet_path), } + .map(|res| res.1) } } @@ -145,6 +150,34 @@ number> "async function asyncAddition(a: number, b: number): Promise { \treturn a + b; } +"; + + assert_eq!(output, expected_output); + } + + #[test] + fn test_deno_fmt() { + let l = TypeScript { + enabled: true, + formatter: TypeScriptFormatter::DenoFmt, + }; + + let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + let output = l + .format(snippet_path) + .expect("it to not fail") + .expect("it to be a snippet"); + + let expected_output = "async function asyncAddition( + a: number, + b: number, +): Promise< + number +> { + return a + b; +} "; assert_eq!(output, expected_output);