Skip to content

Commit

Permalink
feat(scala): support scalafmt (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
hougesen committed Mar 20, 2024
1 parent a252f4b commit e73c0ac
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/validate.yml
Expand Up @@ -91,6 +91,11 @@ jobs:
#- uses: ocaml/setup-ocaml@v2
# with:
# ocaml-compiler: "5.1"
# scalafmt
- uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"

- run: rustup toolchain install stable --profile minimal
- run: rustup component add rustfmt clippy
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -94,6 +94,7 @@ mdsf init
| Roc | `roc_format` |
| Ruby | `rubocop` |
| Rust | `rustfmt` |
| Scala | `scalafmt` |
| Shell | `beautysh`, `shfmt` |
| Sql | `sql-formatter`, `sqlfluff` |
| Toml | `taplo` |
Expand Down
42 changes: 41 additions & 1 deletion schemas/v0.0.2/mdsf.schema.json
Expand Up @@ -358,10 +358,21 @@
}
]
},
"scala": {
"default": {
"enabled": true,
"formatter": "scalafmt"
},
"allOf": [
{
"$ref": "#/definitions/Lang_for_Scala"
}
]
},
"shell": {
"default": {
"enabled": true,
"formatter": ["shfmt", "beautysh"]
"formatter": [["shfmt", "beautysh"]]
},
"allOf": [
{
Expand Down Expand Up @@ -908,6 +919,18 @@
}
}
},
"Lang_for_Scala": {
"type": "object",
"required": ["enabled", "formatter"],
"properties": {
"enabled": {
"type": "boolean"
},
"formatter": {
"$ref": "#/definitions/MdsfFormatter_for_Scala"
}
}
},
"Lang_for_Shell": {
"type": "object",
"required": ["enabled", "formatter"],
Expand Down Expand Up @@ -1428,6 +1451,19 @@
}
]
},
"MdsfFormatter_for_Scala": {
"anyOf": [
{
"$ref": "#/definitions/Scala"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/MdsfFormatter_for_Scala"
}
}
]
},
"MdsfFormatter_for_Shell": {
"anyOf": [
{
Expand Down Expand Up @@ -1576,6 +1612,10 @@
"type": "string",
"enum": ["rustfmt"]
},
"Scala": {
"type": "string",
"enum": ["scalafmt"]
},
"Shell": {
"type": "string",
"enum": ["shfmt", "beautysh"]
Expand Down
8 changes: 6 additions & 2 deletions src/config.rs
Expand Up @@ -6,8 +6,8 @@ use crate::languages::{
html::Html, java::Java, javascript::JavaScript, json::Json, just::Just, lua::Lua,
markdown::Markdown, nim::Nim, objective_c::ObjectiveC, ocaml::OCaml, perl::Perl,
protobuf::Protobuf, purescript::PureScript, python::Python, rescript::ReScript, roc::Roc,
ruby::Ruby, rust::Rust, shell::Shell, sql::Sql, toml::Toml, typescript::TypeScript, vue::Vue,
xml::Xml, yaml::Yaml, zig::Zig, Lang,
ruby::Ruby, rust::Rust, scala::Scala, shell::Shell, sql::Sql, toml::Toml,
typescript::TypeScript, vue::Vue, xml::Xml, yaml::Yaml, zig::Zig, Lang,
};

#[derive(Debug, serde::Serialize, serde::Deserialize, JsonSchema)]
Expand Down Expand Up @@ -113,6 +113,9 @@ pub struct MdsfConfig {
#[serde(default)]
pub rust: Lang<Rust>,

#[serde(default)]
pub scala: Lang<Scala>,

#[serde(default)]
pub shell: Lang<Shell>,

Expand Down Expand Up @@ -176,6 +179,7 @@ impl Default for MdsfConfig {
roc: Lang::<Roc>::default(),
ruby: Lang::<Ruby>::default(),
rust: Lang::<Rust>::default(),
scala: Lang::<Scala>::default(),
shell: Lang::<Shell>::default(),
sql: Lang::<Sql>::default(),
toml: Lang::<Toml>::default(),
Expand Down
2 changes: 2 additions & 0 deletions src/formatters/mod.rs
Expand Up @@ -36,6 +36,7 @@ pub mod roc_format;
pub mod rubocop;
pub mod ruff;
pub mod rustfmt;
pub mod scalafmt;
pub mod shfmt;
pub mod sql_formatter;
pub mod sqlfluff;
Expand Down Expand Up @@ -139,6 +140,7 @@ pub fn format_snippet(config: &MdsfConfig, language: &Language, code: &str) -> S
Language::Roc => config.roc.format(snippet_path),
Language::Ruby => config.ruby.format(snippet_path),
Language::Rust => config.rust.format(snippet_path),
Language::Scala => config.scala.format(snippet_path),
Language::Shell => config.shell.format(snippet_path),
Language::Sql => config.sql.format(snippet_path),
Language::Toml => config.toml.format(snippet_path),
Expand Down
55 changes: 55 additions & 0 deletions src/formatters/scalafmt.rs
@@ -0,0 +1,55 @@
use super::execute_command;

#[inline]
pub fn format_using_scalafmt(
snippet_path: &std::path::Path,
) -> std::io::Result<(bool, Option<String>)> {
let mut cmd = std::process::Command::new("scalafmt");

#[cfg(test)]
{
cmd.arg("--config-str").arg("\"version=3.8.0\"");

cmd.arg("--debug");
};

cmd.arg("--quiet")
.arg("--mode")
.arg("any")
.arg(snippet_path);

execute_command(&mut cmd, snippet_path)
}

#[cfg(test)]
mod test_scalafmt {
use crate::{formatters::setup_snippet, languages::Language};

use super::format_using_scalafmt;

#[test_with::executable(scalafmt)]
#[test]
fn it_should_format_scala() {
let input = "object Addition {
def main() = {
println(1 + 3)
}
}";
let expected_output = "object Addition {
def main() = {
println(1 + 3)
}
}
";

let snippet = setup_snippet(input, Language::Scala.to_file_ext())
.expect("it to create a snippet file");

let output = format_using_scalafmt(snippet.path())
.expect("it to be successful")
.1
.expect("it to be some");

assert_eq!(output, expected_output);
}
}
5 changes: 4 additions & 1 deletion src/languages/mod.rs
Expand Up @@ -35,6 +35,7 @@ pub enum Language {
Roc,
Ruby,
Rust,
Scala,
Shell,
Sql,
Toml,
Expand All @@ -54,7 +55,6 @@ pub enum Language {
// TODO: XML,
// TODO: D,
// TODO: Erlang,
// TODO: Scala,
// TODO: R,
}

Expand Down Expand Up @@ -90,6 +90,7 @@ pub mod rescript;
pub mod roc;
pub mod ruby;
pub mod rust;
pub mod scala;
pub mod shell;
pub mod sql;
pub mod toml;
Expand Down Expand Up @@ -141,6 +142,7 @@ impl Language {
"roc" => Some(Self::Roc),
"ruby" | "rb" => Some(Self::Ruby),
"rust" | "rs" => Some(Self::Rust),
"scala" => Some(Self::Scala),
"shell" | "sh" | "bash" | "zsh" => Some(Self::Shell),
"sql" | "bigquery" | "db2" | "db2i" | "hive" | "mariadb" | "mysql" | "n1ql"
| "plsql" | "postgresql" | "redshift" | "singlestoredb" | "snowflake" | "spark"
Expand Down Expand Up @@ -191,6 +193,7 @@ impl Language {
Self::Ruby => ".rb",
Self::Rust => ".rs",
Self::Shell => ".sh",
Self::Scala => ".scala",
Self::Sql => ".sql",
Self::Toml => ".toml",
Self::TypeScript => ".ts",
Expand Down
104 changes: 104 additions & 0 deletions src/languages/scala.rs
@@ -0,0 +1,104 @@
use schemars::JsonSchema;

use crate::formatters::{scalafmt::format_using_scalafmt, MdsfFormatter};

use super::{Lang, LanguageFormatter};

#[derive(Debug, Default, serde::Serialize, serde::Deserialize, JsonSchema)]
#[cfg_attr(test, derive(PartialEq, Eq))]
pub enum Scala {
#[default]
#[serde(rename = "scalafmt")]
Scalafmt,
}

impl Default for Lang<Scala> {
#[inline]
fn default() -> Self {
Self {
enabled: true,
formatter: MdsfFormatter::<Scala>::default(),
}
}
}

impl Default for MdsfFormatter<Scala> {
#[inline]
fn default() -> Self {
Self::Single(Scala::Scalafmt)
}
}

impl LanguageFormatter for Scala {
#[inline]
fn format_snippet(
&self,
snippet_path: &std::path::Path,
) -> std::io::Result<(bool, Option<String>)> {
match self {
Self::Scalafmt => format_using_scalafmt(snippet_path),
}
}
}

#[cfg(test)]
mod test_blade {
use crate::{
formatters::{setup_snippet, MdsfFormatter},
languages::Lang,
};

use super::Scala;

const INPUT: &str = r#"
object A { println ("HELLO!" ) }
// comment
"#;

const EXTENSION: &str = crate::languages::Language::Blade.to_file_ext();

#[test]
fn it_should_be_enabled_by_default() {
assert!(Lang::<Scala>::default().enabled);
}

#[test]
fn it_should_not_format_when_enabled_is_false() {
let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file");
let snippet_path = snippet.path();

assert!(Lang::<Scala> {
enabled: false,
formatter: MdsfFormatter::Single(Scala::Scalafmt),
}
.format(snippet_path)
.expect("it to not fail")
.is_none());
}

#[test_with::executable(scalafmt)]
#[test]
fn test_scalafmt() {
let expected_output = r#"object A{ println("HELLO!") }
// comment
"#;

let l = Lang::<Scala> {
enabled: true,
formatter: MdsfFormatter::Single(Scala::Scalafmt),
};

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!(output, expected_output);
}
}
4 changes: 2 additions & 2 deletions src/languages/shell.rs
Expand Up @@ -29,10 +29,10 @@ impl Default for Lang<Shell> {
impl Default for MdsfFormatter<Shell> {
#[inline]
fn default() -> Self {
Self::Multiple(vec![
Self::Multiple(vec![Self::Multiple(vec![
Self::Single(Shell::Shfmt),
Self::Single(Shell::Beautysh),
])
])])
}
}

Expand Down

0 comments on commit e73c0ac

Please sign in to comment.