diff --git a/README.md b/README.md index ba33429d..eff6ab8c 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ mdsf init | Elixir | `mix_format` | | Gleam | `gleam_format` | | Go | `gofmt`, `gofumpt` | +| GraphQL | `prettier` | | HTML | `prettier` | | Java | `clang-format` | | JavaScript | `prettier`, `biome`, `clang-format`, `deno_fmt` | diff --git a/schemas/v0.0.1/mdsf.schema.json b/schemas/v0.0.1/mdsf.schema.json index c7fb36f7..a9b8321b 100644 --- a/schemas/v0.0.1/mdsf.schema.json +++ b/schemas/v0.0.1/mdsf.schema.json @@ -102,6 +102,17 @@ } ] }, + "graphql": { + "default": { + "enabled": true, + "formatter": "prettier" + }, + "allOf": [ + { + "$ref": "#/definitions/Lang_for_GraphQL" + } + ] + }, "html": { "default": { "enabled": true, @@ -374,6 +385,10 @@ "type": "string", "enum": ["gofmt", "gofumpt"] }, + "GraphQL": { + "type": "string", + "enum": ["prettier"] + }, "Html": { "type": "string", "enum": ["prettier"] @@ -502,6 +517,18 @@ } } }, + "Lang_for_GraphQL": { + "type": "object", + "required": ["enabled", "formatter"], + "properties": { + "enabled": { + "type": "boolean" + }, + "formatter": { + "$ref": "#/definitions/MdsfFormatter_for_GraphQL" + } + } + }, "Lang_for_Html": { "type": "object", "required": ["enabled", "formatter"], @@ -879,6 +906,19 @@ } ] }, + "MdsfFormatter_for_GraphQL": { + "anyOf": [ + { + "$ref": "#/definitions/GraphQL" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/MdsfFormatter_for_GraphQL" + } + } + ] + }, "MdsfFormatter_for_Html": { "anyOf": [ { diff --git a/src/config.rs b/src/config.rs index 3c986d43..60991a8b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,10 +2,10 @@ use schemars::JsonSchema; use crate::languages::{ c::C, cpp::Cpp, crystal::Crystal, csharp::CSharp, css::Css, dart::Dart, elixir::Elixir, - gleam::Gleam, go::Go, html::Html, java::Java, javascript::JavaScript, json::Json, just::Just, - lua::Lua, markdown::Markdown, nim::Nim, objective_c::ObjectiveC, protobuf::Protobuf, - python::Python, roc::Roc, ruby::Ruby, rust::Rust, shell::Shell, sql::Sql, toml::Toml, - typescript::TypeScript, vue::Vue, yaml::Yaml, zig::Zig, Lang, + gleam::Gleam, go::Go, graphql::GraphQL, html::Html, java::Java, javascript::JavaScript, + json::Json, just::Just, lua::Lua, markdown::Markdown, nim::Nim, objective_c::ObjectiveC, + protobuf::Protobuf, python::Python, roc::Roc, ruby::Ruby, rust::Rust, shell::Shell, sql::Sql, + toml::Toml, typescript::TypeScript, vue::Vue, yaml::Yaml, zig::Zig, Lang, }; #[derive(Debug, serde::Serialize, serde::Deserialize, JsonSchema)] @@ -42,6 +42,9 @@ pub struct MdsfConfig { #[serde(default)] pub go: Lang, + #[serde(default)] + pub graphql: Lang, + #[serde(default)] pub html: Lang, @@ -121,6 +124,7 @@ impl Default for MdsfConfig { elixir: Lang::::default(), gleam: Lang::::default(), go: Lang::::default(), + graphql: Lang::::default(), html: Lang::::default(), java: Lang::::default(), javascript: Lang::::default(), diff --git a/src/formatters/mod.rs b/src/formatters/mod.rs index d6a3e18a..553f2937 100644 --- a/src/formatters/mod.rs +++ b/src/formatters/mod.rs @@ -104,6 +104,7 @@ pub fn format_snippet(config: &MdsfConfig, language: &Language, code: &str) -> S Language::Elixir => config.elixir.format(snippet_path), Language::Gleam => config.gleam.format(snippet_path), Language::Go => config.go.format(snippet_path), + Language::GraphQL => config.graphql.format(snippet_path), Language::Html => config.html.format(snippet_path), Language::Java => config.java.format(snippet_path), Language::JavaScript => config.javascript.format(snippet_path), diff --git a/src/formatters/prettier.rs b/src/formatters/prettier.rs index 85badbcf..a20cb0ae 100644 --- a/src/formatters/prettier.rs +++ b/src/formatters/prettier.rs @@ -359,4 +359,32 @@ function add(a: number, b: number): number { assert_eq!(expected_output, output); } + + #[test] + fn it_should_format_graphql() { + let input = "{ hero { name + # Queries can have comments! + friends { name } } }"; + + let expected_output = "{ + hero { + name + # Queries can have comments! + friends { + name + } + } +} +"; + + let snippet = setup_snippet(input, Language::GraphQL.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_prettier(snippet.path(), true) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } } diff --git a/src/languages/graphql.rs b/src/languages/graphql.rs new file mode 100644 index 00000000..3ee42f48 --- /dev/null +++ b/src/languages/graphql.rs @@ -0,0 +1,106 @@ +use schemars::JsonSchema; + +use crate::formatters::{prettier::format_using_prettier, MdsfFormatter}; + +use super::{Lang, LanguageFormatter}; + +#[derive(Debug, Default, serde::Serialize, serde::Deserialize, JsonSchema)] +#[cfg_attr(test, derive(PartialEq, Eq))] +pub enum GraphQL { + #[default] + #[serde(rename = "prettier")] + Prettier, +} + +impl Default for Lang { + #[inline] + fn default() -> Self { + Self { + enabled: true, + formatter: MdsfFormatter::::default(), + } + } +} + +impl Default for MdsfFormatter { + #[inline] + fn default() -> Self { + Self::Single(GraphQL::Prettier) + } +} + +impl LanguageFormatter for GraphQL { + #[inline] + fn format_snippet( + &self, + snippet_path: &std::path::Path, + ) -> std::io::Result<(bool, Option)> { + match self { + Self::Prettier => format_using_prettier(snippet_path, true), + } + } +} + +#[cfg(test)] +mod test_grapql { + use crate::{ + formatters::{setup_snippet, MdsfFormatter}, + languages::Lang, + }; + + use super::GraphQL; + + const INPUT: &str = "{ hero { name + # Queries can have comments! + friends { name } } }"; + + const EXTENSION: &str = crate::languages::Language::GraphQL.to_file_ext(); + + #[test] + fn it_should_be_enabled_by_default() { + assert!(Lang::::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:: { + enabled: false, + formatter: MdsfFormatter::Single(GraphQL::default()), + } + .format(snippet_path) + .expect("it to not fail") + .is_none()); + } + + #[test] + fn test_prettier() { + let expected_output = "{ + hero { + name + # Queries can have comments! + friends { + name + } + } +} +"; + + let l = Lang:: { + enabled: true, + formatter: MdsfFormatter::Single(GraphQL::Prettier), + }; + + 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); + } +} diff --git a/src/languages/mod.rs b/src/languages/mod.rs index 28fbbf9c..d2c262eb 100644 --- a/src/languages/mod.rs +++ b/src/languages/mod.rs @@ -11,6 +11,7 @@ pub enum Language { Dart, Elixir, Gleam, + GraphQL, Go, Html, Java, @@ -48,7 +49,6 @@ pub enum Language { // TODO: Elm, // TODO: Scala, // TODO: R, - // TODO: GraphQL, } pub mod c; @@ -60,6 +60,7 @@ pub mod dart; pub mod elixir; pub mod gleam; pub mod go; +pub mod graphql; pub mod html; pub mod java; pub mod javascript; @@ -125,6 +126,7 @@ impl Language { "vue" => Some(Self::Vue), "yml" | "yaml" => Some(Self::Yaml), "zig" => Some(Self::Zig), + "graphql" | "gql" => Some(Self::GraphQL), _ => None, } } @@ -164,6 +166,7 @@ impl Language { Self::Vue => ".vue", Self::Yaml => ".yml", Self::Zig => ".zig", + Self::GraphQL => ".gql", } } } @@ -248,8 +251,7 @@ mod test_lang { Self::A => (false, file.write(b"a")), Self::B => (false, file.write(b"b")), Self::C => (false, file.write(b"c")), - Self::D => (true, Ok(0)), - Self::E => (true, Ok(0)), + Self::D | Self::E => (true, Ok(0)), }; Ok((should_fail, std::fs::read_to_string(snippet_path).ok()))