From 2a151d8930a49229a614ebc29fcc48abdc39456f Mon Sep 17 00:00:00 2001 From: Tim van Elsloo Date: Wed, 28 Dec 2022 01:23:03 +0100 Subject: [PATCH] Improved support for built-in types and directives. --- litho-cli/Cargo.toml | 7 +- litho-cli/build.rs | 10 ++ litho-cli/src/bin/litho.rs | 43 +++++---- litho-cli/std/introspection.graphql | 90 ----------------- litho-compiler/src/builtins.rs | 20 ++++ litho-compiler/src/lib.rs | 2 + litho-compiler/std/directives.graphql | 44 +++++++++ litho-compiler/std/introspection.graphql | 96 +++++++++++++++++++ litho-compiler/std/litho.graphql | 3 + .../std/scalars.graphql | 2 - litho-language/src/fmt/schema.rs | 4 +- litho-language/src/fmt/types.rs | 1 - litho-language/src/syn/schema.rs | 1 + litho-lsp/src/server.rs | 3 +- litho-lsp/src/workspace.rs | 22 +---- litho-lsp/std/introspection.graphql | 90 ----------------- litho-lsp/std/scalars.graphql | 44 --------- 17 files changed, 212 insertions(+), 270 deletions(-) create mode 100644 litho-cli/build.rs delete mode 100644 litho-cli/std/introspection.graphql create mode 100644 litho-compiler/src/builtins.rs create mode 100644 litho-compiler/std/directives.graphql create mode 100644 litho-compiler/std/introspection.graphql create mode 100644 litho-compiler/std/litho.graphql rename {litho-cli => litho-compiler}/std/scalars.graphql (97%) delete mode 100644 litho-lsp/std/introspection.graphql delete mode 100644 litho-lsp/std/scalars.graphql diff --git a/litho-cli/Cargo.toml b/litho-cli/Cargo.toml index 245a6c9..38dfc80 100644 --- a/litho-cli/Cargo.toml +++ b/litho-cli/Cargo.toml @@ -8,9 +8,12 @@ edition = "2021" name = "litho" [dependencies] -smol_str = "0.1.23" - litho-compiler = { path = "../litho-compiler" } litho-language = { path = "../litho-language" } + ariadne = "0.1.5" glob = "0.3.0" +smol_str = "0.1.23" + +[build-dependencies] +vergen = "7.4.4" diff --git a/litho-cli/build.rs b/litho-cli/build.rs new file mode 100644 index 0000000..51635ed --- /dev/null +++ b/litho-cli/build.rs @@ -0,0 +1,10 @@ +use vergen::vergen; +use vergen::{Config, ShaKind, TimestampKind}; + +pub fn main() { + let mut config = Config::default(); + *config.git_mut().sha_kind_mut() = ShaKind::Short; + *config.git_mut().commit_timestamp_kind_mut() = TimestampKind::DateOnly; + + vergen(config).unwrap(); +} diff --git a/litho-cli/src/bin/litho.rs b/litho-cli/src/bin/litho.rs index 2d4fd36..9b758dd 100644 --- a/litho-cli/src/bin/litho.rs +++ b/litho-cli/src/bin/litho.rs @@ -6,7 +6,7 @@ use std::process::ExitCode; use ariadne::{Cache, Label, Report, ReportKind, Source}; use glob::glob; -use litho_compiler::Compiler; +use litho_compiler::{builtins, Compiler}; use litho_language::lex::{SourceId, SourceMap, Span}; use smol_str::SmolStr; @@ -36,32 +36,33 @@ pub fn main() -> ExitCode { let mut args = args().skip(1); while let Some(arg) = args.next() { - inputs.extend( - glob(&arg) - .into_iter() - .flatten() - .map(IntoIterator::into_iter) - .flatten() - .map(|path| path.to_string_lossy().into_owned()), - ); + match arg.as_str() { + "--version" | "-v" | "version" => { + println!( + "litho {} ({} {})", + env!("CARGO_PKG_VERSION"), + env!("VERGEN_GIT_SHA_SHORT"), + env!("VERGEN_GIT_COMMIT_DATE") + ); + + return ExitCode::SUCCESS; + } + arg => inputs.extend( + glob(&arg) + .into_iter() + .flatten() + .map(IntoIterator::into_iter) + .flatten() + .map(|path| path.to_string_lossy().into_owned()), + ), + } } let mut compiler = Compiler::::new(); let mut source_map = SourceMap::new(); let mut sources = Sources::default(); - let std = vec![ - ( - "litho://std.litho.dev/inflection.graphql", - include_str!("../../std/introspection.graphql").to_owned(), - ), - ( - "litho://std.litho.dev/scalars.graphql", - include_str!("../../std/scalars.graphql").to_owned(), - ), - ]; - - for (path, text) in std.into_iter() { + for (path, text) in builtins().into_iter().copied() { let source_id = source_map.get_or_insert(path.to_owned()); sources.insert(source_id, path.to_owned(), Source::from(&text)); compiler.add_document(source_id, &text, true); diff --git a/litho-cli/std/introspection.graphql b/litho-cli/std/introspection.graphql deleted file mode 100644 index df2fb4b..0000000 --- a/litho-cli/std/introspection.graphql +++ /dev/null @@ -1,90 +0,0 @@ -extend type Query { - __schema: __Schema! - __type(name: String!): __Type -} - -type __Schema { - description: String - types: [__Type!]! - queryType: __Type! - mutationType: __Type - subscriptionType: __Type - directives: [__Directive!]! -} - -type __Type { - kind: __TypeKind - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - specifiedByURL: String -} - -enum __TypeKind { - SCALAR - OBJECT - INTERFACE - UNION - ENUM - INPUT_OBJECT - LIST - NON_NULL -} - -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -type __InputValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! -} - -enum __DirectiveLocation { - QUERY - MUTATION - SUBSCRIPTION - FIELD - FRAGMENT_DEFINITION - FRAGMENT_SPREAD - INLINE_FRAGMENT - VARIABLE_DEFINITION - SCHEMA - SCALAR - OBJECT - FIELD_DEFINITION - ARGUMENT_DEFINITION - INTERFACE - UNION - ENUM - ENUM_VALUE - INPUT_OBJECT - INPUT_FIELD_DEFINITION -} diff --git a/litho-compiler/src/builtins.rs b/litho-compiler/src/builtins.rs new file mode 100644 index 0000000..592958d --- /dev/null +++ b/litho-compiler/src/builtins.rs @@ -0,0 +1,20 @@ +pub const fn builtins() -> &'static [(&'static str, &'static str)] { + &[ + ( + "litho://std.litho.dev/directives.graphql", + include_str!("../std/directives.graphql"), + ), + ( + "litho://std.litho.dev/introspection.graphql", + include_str!("../std/introspection.graphql"), + ), + ( + "litho://std.litho.dev/litho.graphql", + include_str!("../std/litho.graphql"), + ), + ( + "litho://std.litho.dev/scalars.graphql", + include_str!("../std/scalars.graphql"), + ), + ] +} diff --git a/litho-compiler/src/lib.rs b/litho-compiler/src/lib.rs index 15ca14c..ef18114 100644 --- a/litho-compiler/src/lib.rs +++ b/litho-compiler/src/lib.rs @@ -1,7 +1,9 @@ +mod builtins; mod compiler; mod dependency; mod depgraph; +pub use builtins::builtins; pub use compiler::Compiler; pub use dependency::{Consumer, Dependency, Producer}; pub use depgraph::DepGraph; diff --git a/litho-compiler/std/directives.graphql b/litho-compiler/std/directives.graphql new file mode 100644 index 0000000..f68af46 --- /dev/null +++ b/litho-compiler/std/directives.graphql @@ -0,0 +1,44 @@ +""" +The `@skip` built-in directive may be provided for fields, fragment spreads, and +inline fragments, and allows for conditional exclusion as described by the `if` +argument. +""" +directive @skip( + if: Boolean!, +) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +""" +The `@include` built-in directive may be provided for fields, fragment spreads, +and inline fragments, and allows for conditional inclusion during execution as +described by the `if` argument. +""" +directive @include( + if: Boolean!, +) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +""" +The `@deprecated` built-in directive is used within the type system definition +language to indicate deprecated portions of a GraphQL service's schema, such as +deprecated fields on a type or deprecated enum values. + +Deprecations include a reason for why it is deprecated, which is formatted using +Markdown syntax (as specified by CommonMark). +""" +directive @deprecated( + reason: String = "No longer supported", +) on + | FIELD_DEFINITION + | ARGUMENT_DEFINITION + | INPUT_FIELD_DEFINITION + | ENUM_VALUE + +""" +The `@specifiedBy` built-in directive is used within the type system definition +language to provide a scalar specification URL for specifying the behavior of +custom scalar types. The URL should point to a human-readable specification of +the data format, serialization, and coercion rules. It must not appear on +built-in scalar types. +""" +directive @specifiedBy( + url: String!, +) on SCALAR diff --git a/litho-compiler/std/introspection.graphql b/litho-compiler/std/introspection.graphql new file mode 100644 index 0000000..b2563a3 --- /dev/null +++ b/litho-compiler/std/introspection.graphql @@ -0,0 +1,96 @@ +extend type Query { + __schema: __Schema! + __type( + name: String!, + ): __Type +} + +type __Schema { + description: String + types: [__Type!]! + queryType: __Type! + mutationType: __Type + subscriptionType: __Type + directives: [__Directive!]! +} + +type __Type { + kind: __TypeKind + name: String + description: String + fields( + includeDeprecated: Boolean = false, + ): [__Field!] + interfaces: [__Type!] + possibleTypes: [__Type!] + enumValues( + includeDeprecated: Boolean = false, + ): [__EnumValue!] + inputFields: [__InputValue!] + ofType: __Type + specifiedByURL: String +} + +enum __TypeKind { + SCALAR + OBJECT + INTERFACE + UNION + ENUM + INPUT_OBJECT + LIST + NON_NULL +} + +type __Field { + name: String! + description: String + args: [__InputValue!]! + type: __Type! + isDeprecated: Boolean! + deprecationReason: String +} + +type __InputValue { + name: String! + description: String + type: __Type! + defaultValue: String +} + +type __EnumValue { + name: String! + description: String + isDeprecated: Boolean! + deprecationReason: String +} + +type __Directive { + name: String! + description: String + locations: [__DirectiveLocation!]! + args: [__InputValue!]! + isRepeatable: Boolean! +} + +enum __DirectiveLocation { + QUERY + MUTATION + SUBSCRIPTION + FIELD + FRAGMENT_DEFINITION + FRAGMENT_SPREAD + INLINE_FRAGMENT + VARIABLE_DEFINITION + SCHEMA + SCALAR + OBJECT + FIELD_DEFINITION + ARGUMENT_DEFINITION + INTERFACE + UNION + ENUM + ENUM_VALUE + INPUT_OBJECT + INPUT_FIELD_DEFINITION +} diff --git a/litho-compiler/std/litho.graphql b/litho-compiler/std/litho.graphql new file mode 100644 index 0000000..4bc371b --- /dev/null +++ b/litho-compiler/std/litho.graphql @@ -0,0 +1,3 @@ +directive @litho( + url: String!, +) on SCHEMA diff --git a/litho-cli/std/scalars.graphql b/litho-compiler/std/scalars.graphql similarity index 97% rename from litho-cli/std/scalars.graphql rename to litho-compiler/std/scalars.graphql index 6796e44..b4a254a 100644 --- a/litho-cli/std/scalars.graphql +++ b/litho-compiler/std/scalars.graphql @@ -1,5 +1,3 @@ -directive @litho(url: String!) on SCHEMA - """ The Int scalar type represents a signed 32-bit numeric non-fractional value. Response formats that support a 32-bit integer or a number type should use that diff --git a/litho-language/src/fmt/schema.rs b/litho-language/src/fmt/schema.rs index f512824..4077188 100644 --- a/litho-language/src/fmt/schema.rs +++ b/litho-language/src/fmt/schema.rs @@ -569,6 +569,7 @@ where formatter.line()?; self.directive.format(formatter)?; + self.at.format(formatter)?; formatter.squeeze(|formatter| self.name.format(formatter))?; formatter.squeeze(|formatter| self.arguments_definition.format(formatter))?; self.repeatable.format(formatter)?; @@ -591,6 +592,7 @@ where if self.expands() { formatter.indent(|formatter| { for location in self.locations() { + formatter.line()?; formatter.push("|")?; location.format(formatter)?; } @@ -601,8 +603,8 @@ where for (i, location) in self.locations().enumerate() { if i != 0 { formatter.push("|")?; - location.format(formatter)?; } + location.format(formatter)?; } } diff --git a/litho-language/src/fmt/types.rs b/litho-language/src/fmt/types.rs index 0ecec43..2143c82 100644 --- a/litho-language/src/fmt/types.rs +++ b/litho-language/src/fmt/types.rs @@ -58,7 +58,6 @@ where let result = closure(self); self.line()?; self.shape.indent -= 4; - self.shape.blank_lines = 0; result } diff --git a/litho-language/src/syn/schema.rs b/litho-language/src/syn/schema.rs index 26f0ec8..06d8883 100644 --- a/litho-language/src/syn/schema.rs +++ b/litho-language/src/syn/schema.rs @@ -878,6 +878,7 @@ where keyword("FIELD").map(ExecutableDirectiveLocation::Field), keyword("FRAGMENT_DEFINITION").map(ExecutableDirectiveLocation::FragmentDefinition), keyword("FRAGMENT_SPREAD").map(ExecutableDirectiveLocation::FragmentSpread), + keyword("INLINE_FRAGMENT").map(ExecutableDirectiveLocation::InlineFragment), keyword("VARIABLE_DEFINITION").map(ExecutableDirectiveLocation::VariableDefinition), )) }) diff --git a/litho-lsp/src/server.rs b/litho-lsp/src/server.rs index 73585f0..1f0cdf6 100644 --- a/litho-lsp/src/server.rs +++ b/litho-lsp/src/server.rs @@ -50,8 +50,7 @@ where let mut workspace = self.workspace.lock().await; workspace .mutate(|workspace| { - workspace.populate_inflection(); - workspace.populate_scalars(); + workspace.populate_builtins(); if let Some(root_uri) = params.root_uri { let _ = self.populate_root(workspace, root_uri); diff --git a/litho-lsp/src/workspace.rs b/litho-lsp/src/workspace.rs index 424c8e9..df6c0bb 100644 --- a/litho-lsp/src/workspace.rs +++ b/litho-lsp/src/workspace.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use futures::channel::mpsc::Sender; use futures::lock::Mutex; use futures::SinkExt; -use litho_compiler::Compiler; +use litho_compiler::{builtins, Compiler}; use litho_language::lex::{SourceId, SourceMap, Span}; use litho_types::Database; use lsp_types::*; @@ -125,22 +125,10 @@ impl Workspace { result } - pub fn populate_inflection(&mut self) { - self.populate_file_contents( - Url::parse("litho://std.litho.dev/inflection.graphql").unwrap(), - None, - true, - include_str!("../std/introspection.graphql").to_owned(), - ) - } - - pub fn populate_scalars(&mut self) { - self.populate_file_contents( - Url::parse("litho://std.litho.dev/scalars.graphql").unwrap(), - None, - true, - include_str!("../std/scalars.graphql").to_owned(), - ); + pub fn populate_builtins(&mut self) { + for (path, source) in builtins().into_iter().copied() { + self.populate_file_contents(Url::parse(path).unwrap(), None, true, source.to_owned()) + } } pub fn populate_file_contents( diff --git a/litho-lsp/std/introspection.graphql b/litho-lsp/std/introspection.graphql deleted file mode 100644 index df2fb4b..0000000 --- a/litho-lsp/std/introspection.graphql +++ /dev/null @@ -1,90 +0,0 @@ -extend type Query { - __schema: __Schema! - __type(name: String!): __Type -} - -type __Schema { - description: String - types: [__Type!]! - queryType: __Type! - mutationType: __Type - subscriptionType: __Type - directives: [__Directive!]! -} - -type __Type { - kind: __TypeKind - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - specifiedByURL: String -} - -enum __TypeKind { - SCALAR - OBJECT - INTERFACE - UNION - ENUM - INPUT_OBJECT - LIST - NON_NULL -} - -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -type __InputValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! -} - -enum __DirectiveLocation { - QUERY - MUTATION - SUBSCRIPTION - FIELD - FRAGMENT_DEFINITION - FRAGMENT_SPREAD - INLINE_FRAGMENT - VARIABLE_DEFINITION - SCHEMA - SCALAR - OBJECT - FIELD_DEFINITION - ARGUMENT_DEFINITION - INTERFACE - UNION - ENUM - ENUM_VALUE - INPUT_OBJECT - INPUT_FIELD_DEFINITION -} diff --git a/litho-lsp/std/scalars.graphql b/litho-lsp/std/scalars.graphql deleted file mode 100644 index 6796e44..0000000 --- a/litho-lsp/std/scalars.graphql +++ /dev/null @@ -1,44 +0,0 @@ -directive @litho(url: String!) on SCHEMA - -""" -The Int scalar type represents a signed 32-bit numeric non-fractional value. -Response formats that support a 32-bit integer or a number type should use that -type to represent this scalar. -""" -scalar Int - -""" -The Float scalar type represents signed double-precision finite values as -specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point). -Response formats that support an appropriate double-precision number type should -use that type to represent this scalar. -""" -scalar Float - -""" -The String scalar type represents textual data, represented as a sequence of -Unicode code points. The String type is most often used by GraphQL to represent -free-form human-readable text. How the String is encoded internally (for example -UTF-8) is left to the service implementation. All response serialization formats -must support a string representation (for example, JSON Unicode strings), and -that representation must be used to serialize this type. -""" -scalar String - -""" -The Boolean scalar type represents `true` or `false`. Response formats should -use a built-in boolean type if supported; otherwise, they should use their -representation of the integers `1` and `0`. -""" -enum Boolean { - false - true -} - -""" -The ID scalar type represents a unique identifier, often used to refetch an -object or as the key for a cache. The ID type is serialized in the same way as a -`String`; however, it is not intended to be human-readable. While it is often -numeric, it should always serialize as a `String`. -""" -scalar ID