From 4bce853233c04718f23c4d8aecd5ca0022d6a12d Mon Sep 17 00:00:00 2001 From: uhyo Date: Sun, 31 Dec 2023 18:37:44 +0900 Subject: [PATCH] feat: implement infrastructure for separation of scalar types (#40) * chore: define ScalarTypeConfig * chore: pass ScalarTypeConfig * refactor: introduce TypeTarget * test: fix ScalarTypeConfig related test * refactor: remove impl TypePrinter for TypeSystemDocument * refactor: introduce TypeTarget in SchemaTypePrinterContext * feat: output four namespaces * feat: do not emit unneeded types * feat: use OperationOutput / OperationInput from operation_type_printer * feat: implement server-side separation --- Cargo.lock | 1 + crates/config-file/src/config.rs | 4 +- crates/config-file/src/lib.rs | 4 + crates/config-file/src/scalar_type.rs | 60 +++++ crates/config-file/src/tests/mod.rs | 32 ++- crates/config-file/src/tests/type.rs | 12 +- crates/config-file/src/type_target.rs | 40 +++ crates/plugin/Cargo.toml | 1 + crates/plugin/src/model_plugin/mod.rs | 4 +- ...in__tests__resolvers__model_on_fields.snap | 14 +- ...e_printer__tests__basic_type_printing.snap | 12 +- ...__tests__export_input_and_result_type.snap | 12 +- ...rinter__tests__fragment_inline_spread.snap | 24 +- ..._type_printer__tests__fragment_spread.snap | 42 +-- ..._printer__tests__fragment_spread_cond.snap | 52 ++-- ...ts__import_fragments__import_fragment.snap | 16 +- ...ion_type_printer__tests__print_values.snap | 8 +- ..._type_printer__tests__query_variables.snap | 16 +- ...kip_include__emit_only_possible_cases.snap | 12 +- ...skip_include__include_fragment_spread.snap | 16 +- ...ude__include_fragment_spread_variable.snap | 26 +- ...skip_include__include_inline_fragment.snap | 12 +- ...ude__include_inline_fragment_variable.snap | 22 +- ...tests__skip_include__include_variable.snap | 22 +- ...p_include__included_field_is_included.snap | 12 +- ...e__not_included_field_is_not_included.snap | 10 +- ...nclude__not_skipped_field_is_included.snap | 12 +- ...tests__skip_include__skip_and_include.snap | 6 +- ...ude__skip_and_include_fragment_spread.snap | 14 +- ..._and_include_fragment_spread_variable.snap | 24 +- ...ude__skip_and_include_inline_fragment.snap | 10 +- ...s__skip_include__skip_fragment_spread.snap | 14 +- ...nclude__skip_fragment_spread_variable.snap | 26 +- ...s__skip_include__skip_inline_fragment.snap | 10 +- ...nclude__skip_inline_fragment_variable.snap | 22 +- ...r__tests__skip_include__skip_variable.snap | 22 +- ...nclude__skipped_field_is_not_included.snap | 10 +- ...r__tests__variable_disallow_undefined.snap | 16 +- .../operation_type_printer/type_printer.rs | 12 +- .../src/resolver_type_printer/printer.rs | 38 ++- ...ype_printer__tests__resolver_printing.snap | 14 +- .../src/resolver_type_printer/visitor.rs | 27 +- crates/printer/src/schema.rs | 14 +- .../src/schema_type_printer/context.rs | 21 +- .../src/schema_type_printer/printer.rs | 106 +++++++- .../src/schema_type_printer/tests/mod.rs | 41 ++- ...er__tests__avoid_circular_reference_1.snap | 59 +++- ...er__tests__avoid_circular_reference_2.snap | 59 +++- ...er__tests__avoid_circular_reference_3.snap | 65 ++++- ...type_printer__tests__deprecated_items.snap | 139 +++++++--- ...ema_type_printer__tests__enum_runtime.snap | 29 +- ..._type_printer__tests__scalar_printing.snap | 33 ++- ...ma_type_printer__tests__type_printing.snap | 170 +++++++++--- ...inter__tests__type_printing_with_desc.snap | 203 +++++++++++--- .../src/schema_type_printer/type_printer.rs | 252 +++++++++++++----- crates/printer/src/ts_types/mod.rs | 10 +- 56 files changed, 1419 insertions(+), 545 deletions(-) create mode 100644 crates/config-file/src/scalar_type.rs create mode 100644 crates/config-file/src/type_target.rs diff --git a/Cargo.lock b/Cargo.lock index 9e38b71d..6a5625be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,6 +535,7 @@ dependencies = [ "insta", "nitrogql-ast", "nitrogql-checker", + "nitrogql-config-file", "nitrogql-error", "nitrogql-parser", "nitrogql-printer", diff --git a/crates/config-file/src/config.rs b/crates/config-file/src/config.rs index 56225d9d..7167bd90 100644 --- a/crates/config-file/src/config.rs +++ b/crates/config-file/src/config.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf, str::FromStr}; use serde::Deserialize; -use crate::parsing_utils::deserialize_fromstr; +use crate::{parsing_utils::deserialize_fromstr, scalar_type::ScalarTypeConfig}; #[derive(Debug, Default)] pub struct Config { @@ -73,7 +73,7 @@ impl FromStr for GenerateMode { #[serde(default, rename_all = "camelCase")] pub struct GenerateTypeConfig { /// Type of scalars. - pub scalar_types: HashMap, + pub scalar_types: HashMap, /// Whether to allow undefined as input value /// for nullable input fields. pub allow_undefined_as_optional_input: bool, diff --git a/crates/config-file/src/lib.rs b/crates/config-file/src/lib.rs index ecf783f8..b04d2322 100644 --- a/crates/config-file/src/lib.rs +++ b/crates/config-file/src/lib.rs @@ -8,8 +8,10 @@ mod load_config; mod node; mod parse_config; mod parsing_utils; +mod scalar_type; #[cfg(test)] mod tests; +mod type_target; pub use config::{Config, GenerateConfig, GenerateMode}; #[cfg(feature = "execute_js")] @@ -19,3 +21,5 @@ pub use load_config::load_config; #[cfg(feature = "execute_js")] pub use node::{load_default_from_js_file, run_node}; pub use parse_config::parse_config; +pub use scalar_type::ScalarTypeConfig; +pub use type_target::TypeTarget; diff --git a/crates/config-file/src/scalar_type.rs b/crates/config-file/src/scalar_type.rs new file mode 100644 index 00000000..c8109b15 --- /dev/null +++ b/crates/config-file/src/scalar_type.rs @@ -0,0 +1,60 @@ +use serde::Deserialize; + +use crate::TypeTarget; + +/// Representation of a scalar type's TypeScript type +/// as defined in the config file. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ScalarTypeConfig { + /// Single specification for use in all situations. + Single(String), +} + +impl ScalarTypeConfig { + /// Get the TypeScript type for given target. + pub fn get_type(&self, _target: TypeTarget) -> &str { + match self { + ScalarTypeConfig::Single(type_name) => type_name, + } + } + /// Get the TypeScript type as a resolver output type. + pub fn as_resolver_output_type(&self) -> &str { + match self { + ScalarTypeConfig::Single(type_name) => type_name, + } + } + /// Get the TypeScript type as a resolver input type. + pub fn as_resolver_input_type(&self) -> &str { + match self { + ScalarTypeConfig::Single(type_name) => type_name, + } + } + /// Get the TypeScript type as an operation output type. + pub fn as_operation_output_type(&self) -> &str { + match self { + ScalarTypeConfig::Single(type_name) => type_name, + } + } + /// Get the TypeScript type as an operation input type. + pub fn as_operation_input_type(&self) -> &str { + match self { + ScalarTypeConfig::Single(type_name) => type_name, + } + } + /// Returns an Iterator over all type names used in this config. + pub fn type_names(&self) -> impl Iterator { + match self { + ScalarTypeConfig::Single(type_name) => std::iter::once(type_name.as_str()), + } + } +} + +impl<'de> Deserialize<'de> for ScalarTypeConfig { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(ScalarTypeConfig::Single(s)) + } +} diff --git a/crates/config-file/src/tests/mod.rs b/crates/config-file/src/tests/mod.rs index 7121e577..fff3e1b9 100644 --- a/crates/config-file/src/tests/mod.rs +++ b/crates/config-file/src/tests/mod.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::{parse_config, GenerateMode}; +use crate::{parse_config, GenerateMode, ScalarTypeConfig}; mod export; mod name; @@ -81,12 +81,30 @@ extensions: assert_eq!( config.generate.r#type.scalar_types, vec![ - ("Date".to_owned(), "Date".to_owned()), - ("BigInt".to_owned(), "bigint".to_owned()), - ("Int".to_owned(), "number".to_owned()), - ("Float".to_owned(), "number".to_owned()), - ("ID".to_owned(), "string".to_owned()), - ("String".to_owned(), "string".to_owned()), + ( + "Date".to_owned(), + ScalarTypeConfig::Single("Date".to_owned()) + ), + ( + "BigInt".to_owned(), + ScalarTypeConfig::Single("bigint".to_owned()) + ), + ( + "Int".to_owned(), + ScalarTypeConfig::Single("number".to_owned()) + ), + ( + "Float".to_owned(), + ScalarTypeConfig::Single("number".to_owned()) + ), + ( + "ID".to_owned(), + ScalarTypeConfig::Single("string".to_owned()) + ), + ( + "String".to_owned(), + ScalarTypeConfig::Single("string".to_owned()) + ), ] .into_iter() .collect() diff --git a/crates/config-file/src/tests/type.rs b/crates/config-file/src/tests/type.rs index 4d20c5fd..4cde7581 100644 --- a/crates/config-file/src/tests/type.rs +++ b/crates/config-file/src/tests/type.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::parse_config; +use crate::{parse_config, ScalarTypeConfig}; #[test] fn default_config() { @@ -47,8 +47,14 @@ extensions: let config = parse_config(config).unwrap(); let ty = config.generate.r#type; let mut expected = HashMap::new(); - expected.insert("DateTime".to_string(), "Date".to_string()); - expected.insert("JSON".to_string(), "any".to_string()); + expected.insert( + "DateTime".to_string(), + ScalarTypeConfig::Single("Date".to_string()), + ); + expected.insert( + "JSON".to_string(), + ScalarTypeConfig::Single("any".to_string()), + ); assert_eq!(ty.scalar_types, expected); assert!(!ty.allow_undefined_as_optional_input); } diff --git a/crates/config-file/src/type_target.rs b/crates/config-file/src/type_target.rs new file mode 100644 index 00000000..2d79c95a --- /dev/null +++ b/crates/config-file/src/type_target.rs @@ -0,0 +1,40 @@ +use std::fmt::Display; + +#[derive(Copy, Clone)] +pub enum TypeTarget { + OperationInput, + OperationOutput, + ResolverInput, + ResolverOutput, +} + +impl TypeTarget { + /// Returns the string representation of self. + /// String representation is prefixed with `__` for use in type definitions. + pub fn as_str(&self) -> &'static str { + match self { + TypeTarget::OperationInput => "__OperationInput", + TypeTarget::OperationOutput => "__OperationOutput", + TypeTarget::ResolverInput => "__ResolverInput", + TypeTarget::ResolverOutput => "__ResolverOutput", + } + } + + /// Returns whether self is an output target. + pub fn is_output(&self) -> bool { + matches!( + self, + TypeTarget::OperationOutput | TypeTarget::ResolverOutput + ) + } + /// Returns whether self is an input target. + pub fn is_input(&self) -> bool { + !self.is_output() + } +} + +impl Display for TypeTarget { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } +} diff --git a/crates/plugin/Cargo.toml b/crates/plugin/Cargo.toml index a19015fe..4ced19c9 100644 --- a/crates/plugin/Cargo.toml +++ b/crates/plugin/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" nitrogql-ast = { path = "../ast" } graphql-builtins = { path = "../builtins" } nitrogql-checker = { path = "../checker" } +nitrogql-config-file = { path = "../config-file" } nitrogql-error = { path = "../error" } nitrogql-parser = { path = "../parser" } nitrogql-printer = { path = "../printer" } diff --git a/crates/plugin/src/model_plugin/mod.rs b/crates/plugin/src/model_plugin/mod.rs index 54642cd8..797d128c 100644 --- a/crates/plugin/src/model_plugin/mod.rs +++ b/crates/plugin/src/model_plugin/mod.rs @@ -5,6 +5,7 @@ use nitrogql_ast::{ value::Value, TypeSystemDocument, }; +use nitrogql_config_file::TypeTarget; use nitrogql_printer::{ ts_types::{ts_types_util::ts_union, TSType}, ResolverTypePrinterOptions, @@ -167,8 +168,9 @@ directive @model( let obj_type = TSType::TypeFunc( Box::new(TSType::TypeVariable("Pick".into())), vec![ - TSType::NamespaceMember( + TSType::NamespaceMember3( options.schema_root_namespace.clone(), + TypeTarget::ResolverOutput.to_string(), def.name.name.into(), ), ts_union(model_field_names.map(|n| TSType::StringLiteral(n.into()))), diff --git a/crates/plugin/src/model_plugin/tests/snapshots/nitrogql_plugin__model_plugin__tests__resolvers__model_on_fields.snap b/crates/plugin/src/model_plugin/tests/snapshots/nitrogql_plugin__model_plugin__tests__resolvers__model_on_fields.snap index ecc56e17..33dcc1ad 100644 --- a/crates/plugin/src/model_plugin/tests/snapshots/nitrogql_plugin__model_plugin__tests__resolvers__model_on_fields.snap +++ b/crates/plugin/src/model_plugin/tests/snapshots/nitrogql_plugin__model_plugin__tests__resolvers__model_on_fields.snap @@ -6,13 +6,13 @@ import type { GraphQLResolveInfo } from "graphql"; import type * as Schema from ""; type __Resolver = (parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => Result | Promise; type __TypeResolver = (object: Obj, context: Context, info: GraphQLResolveInfo) => Result | Promise; -type Int = Schema.Int; -type Float = Schema.Float; -type String = Schema.String; -type Boolean = Schema.Boolean; -type ID = Schema.ID; -type User = Pick; -type Post = Pick; +type Int = Schema.__ResolverOutput.Int; +type Float = Schema.__ResolverOutput.Float; +type String = Schema.__ResolverOutput.String; +type Boolean = Schema.__ResolverOutput.Boolean; +type ID = Schema.__ResolverOutput.ID; +type User = Pick; +type Post = Pick; export type Resolvers = { User: { age: __Resolver; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__basic_type_printing.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__basic_type_printing.snap index 72eb5935..f45ec2e7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__basic_type_printing.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__basic_type_printing.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__export_input_and_result_type.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__export_input_and_result_type.snap index 68e92969..3068e7ce 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__export_input_and_result_type.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__export_input_and_result_type.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -export type SampleQueryResult = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_inline_spread.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_inline_spread.snap index 8bd0ca83..f938be9e 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_inline_spread.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_inline_spread.snap @@ -5,18 +5,18 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet)[]; }, {}>; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread.snap index bf2ab9a3..c982a2b9 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread.snap @@ -5,21 +5,21 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type TestResult = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet)[]; }, {}>; }, {}>; @@ -30,12 +30,12 @@ declare const TestQuery: TypedDocumentNode; export { TestQuery as default }; -export type F = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread_cond.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread_cond.snap index 582dffad..43f6327c 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread_cond.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__fragment_spread_cond.snap @@ -5,23 +5,23 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type FooBar123Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet)[]; }, {}>; }, {}>; @@ -32,19 +32,19 @@ declare const FooBar123Query: TypedDocumentNode | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; export const F: TypedDocumentNode; -export type P = Schema.__SelectionSet; export const P: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__import_fragments__import_fragment.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__import_fragments__import_fragment.snap index b17e7657..fe4d1af0 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__import_fragments__import_fragment.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__import_fragments__import_fragment.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type MyQueryResult = Schema.__SelectionSet; }, {}>; @@ -19,9 +19,9 @@ declare const MyQueryQuery: TypedDocumentNode; export { MyQueryQuery as default }; -type UserProfile = Schema.__SelectionSet; declare const UserProfile: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__print_values.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__print_values.snap index 3c644f31..4d10c6a7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__print_values.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__print_values.snap @@ -5,10 +5,10 @@ expression: result import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__query_variables.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__query_variables.snap index 216386b2..efc5632e 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__query_variables.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__query_variables.snap @@ -5,18 +5,18 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type TestQueryResult = Schema.__SelectionSet; }, {}>; type TestQueryVariables = { - readonly foo: Schema.Int; - readonly bar?: Schema.String | null | undefined; + readonly foo: Schema.__OperationInput.Int; + readonly bar?: Schema.__OperationInput.String | null | undefined; }; declare const TestQueryQuery: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__emit_only_possible_cases.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__emit_only_possible_cases.snap index 595fa2cd..ae130586 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__emit_only_possible_cases.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__emit_only_possible_cases.snap @@ -5,18 +5,18 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly flag: Schema.Boolean; + readonly flag: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread.snap index 04e9e6e6..b332d28b 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; @@ -20,8 +20,8 @@ declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread_variable.snap index 2d238576..95d1de5c 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_fragment_spread_variable.snap @@ -5,30 +5,30 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly include: Schema.Boolean; + readonly include: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment.snap index 72eb5935..f45ec2e7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment_variable.snap index 8b9cac74..69df64c8 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_inline_fragment_variable.snap @@ -5,22 +5,22 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly include: Schema.Boolean; + readonly include: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_variable.snap index 8b9cac74..69df64c8 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__include_variable.snap @@ -5,22 +5,22 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly include: Schema.Boolean; + readonly include: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__included_field_is_included.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__included_field_is_included.snap index 72eb5935..f45ec2e7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__included_field_is_included.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__included_field_is_included.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_included_field_is_not_included.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_included_field_is_not_included.snap index 190c0e97..e6cf67e6 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_included_field_is_not_included.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_included_field_is_not_included.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_skipped_field_is_included.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_skipped_field_is_included.snap index 72eb5935..f45ec2e7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_skipped_field_is_included.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__not_skipped_field_is_included.snap @@ -5,12 +5,12 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include.snap index e69950be..1242f90a 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread.snap index 86de3a16..a7646cd9 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; @@ -20,8 +20,8 @@ declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread_variable.snap index 67f80eb4..07b1e1dd 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_fragment_spread_variable.snap @@ -5,30 +5,30 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly flag: Schema.Boolean; + readonly flag: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_inline_fragment.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_inline_fragment.snap index 190c0e97..e6cf67e6 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_inline_fragment.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_and_include_inline_fragment.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread.snap index 86de3a16..a7646cd9 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; @@ -20,8 +20,8 @@ declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread_variable.snap index e5f6924c..da0a69d7 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_fragment_spread_variable.snap @@ -5,30 +5,30 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly skip: Schema.Boolean; + readonly skip: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; export { Query as default }; -export type F = Schema.__SelectionSet; export const F: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment.snap index 190c0e97..e6cf67e6 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment_variable.snap index ffb756d7..d0091374 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_inline_fragment_variable.snap @@ -5,22 +5,22 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly skip: Schema.Boolean; + readonly skip: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_variable.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_variable.snap index ffb756d7..d0091374 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_variable.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skip_variable.snap @@ -5,22 +5,22 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet | Schema.__SelectionSet | Schema.__SelectionSet; }, {}>; type Variables = { - readonly skip: Schema.Boolean; + readonly skip: Schema.__OperationInput.Boolean; }; declare const Query: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skipped_field_is_not_included.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skipped_field_is_not_included.snap index 190c0e97..e6cf67e6 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skipped_field_is_not_included.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__skip_include__skipped_field_is_not_included.snap @@ -5,11 +5,11 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type Result = Schema.__SelectionSet; }, {}>; diff --git a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__variable_disallow_undefined.snap b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__variable_disallow_undefined.snap index a6f48df0..d2820a1a 100644 --- a/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__variable_disallow_undefined.snap +++ b/crates/printer/src/operation_type_printer/tests/snapshots/nitrogql_printer__operation_type_printer__tests__variable_disallow_undefined.snap @@ -5,18 +5,18 @@ expression: printed import type { TypedDocumentNode } from "@graphql-typed-document-node/core"; import type * as Schema from ""; -type TestQueryResult = Schema.__SelectionSet; }, {}>; type TestQueryVariables = { - readonly foo: Schema.Int; - readonly bar: Schema.String | null; + readonly foo: Schema.__OperationInput.Int; + readonly bar: Schema.__OperationInput.String | null; }; declare const TestQueryQuery: TypedDocumentNode; diff --git a/crates/printer/src/operation_type_printer/type_printer.rs b/crates/printer/src/operation_type_printer/type_printer.rs index 8c41ffdb..52369ff4 100644 --- a/crates/printer/src/operation_type_printer/type_printer.rs +++ b/crates/printer/src/operation_type_printer/type_printer.rs @@ -14,6 +14,7 @@ use nitrogql_ast::{ value::Value, variable::VariablesDefinition, }; +use nitrogql_config_file::TypeTarget; use nitrogql_semantics::direct_fields_of_output_type; use sourcemap_writer::SourceMapWriter; @@ -152,8 +153,9 @@ fn get_object_type_for_selection_set<'src, S: Text<'src>>( .partition_map(identity); let unaliased = TSType::Object(unaliased); let aliased = TSType::Object(aliased); - let schema_type = TSType::NamespaceMember( + let schema_type = TSType::NamespaceMember3( context.options.schema_root_namespace.clone(), + TypeTarget::OperationOutput.to_string(), branch.parent_obj.name.to_string(), ); TSType::TypeFunc( @@ -201,8 +203,9 @@ fn get_fields_for_selection_set<'a, 'src, S: Text<'src>>( .expect("Type system error"); map_to_tstype(&field_def.r#type, |ty| match field.selection_set { - None => TSType::NamespaceMember( + None => TSType::NamespaceMember3( context.options.schema_root_namespace.clone(), + TypeTarget::OperationOutput.to_string(), ty.to_string(), ), Some(ref set) => get_type_for_selection_set(context, set, ty), @@ -410,8 +413,9 @@ pub fn get_type_for_variable_definitions<'src, S: Text<'src>>( .map(|def| { let property_name = def.name.name; let field_type = get_ts_type_of_type(&def.r#type, |name| { - TSType::NamespaceMember( - context.options.schema_root_namespace.clone(), + TSType::NamespaceMember3( + context.options.schema_root_namespace.as_str().into(), + TypeTarget::OperationInput.to_string(), name.name.to_string(), ) }); diff --git a/crates/printer/src/resolver_type_printer/printer.rs b/crates/printer/src/resolver_type_printer/printer.rs index 997eeddd..4b50bd8e 100644 --- a/crates/printer/src/resolver_type_printer/printer.rs +++ b/crates/printer/src/resolver_type_printer/printer.rs @@ -1,12 +1,16 @@ use std::{borrow::Cow, collections::HashMap}; use graphql_type_system::Schema; -use nitrogql_ast::{base::Pos, type_system::TypeSystemDefinition, TypeSystemDocument}; +use nitrogql_ast::{ + base::Pos, + type_system::{TypeDefinition, TypeSystemDefinition}, + TypeSystemDocument, +}; use nitrogql_semantics::ast_to_type_system; use sourcemap_writer::SourceMapWriter; use crate::{ - resolver_type_printer::visitor::{get_resolver_type, get_ts_type_for_resolver}, + resolver_type_printer::visitor::{get_resolver_type, get_ts_type_for_resolver_output}, ts_types::{ts_types_util::ts_union, ObjectField, ObjectKey, TSType}, }; @@ -69,7 +73,7 @@ where .iter() .filter_map(|type_definition| match type_definition { TypeSystemDefinition::TypeDefinition(type_definition) => { - let resolver_type = get_ts_type_for_resolver(type_definition, &context); + let resolver_type = get_ts_type_for_resolver_output(type_definition, &context); Some((type_definition.name().name, resolver_type)) } _ => None, @@ -86,8 +90,14 @@ where } }); + // Emit each schema type (resolver output variant) as a local type alias. + // This helps users to read generated types. for type_definition in &document_for_resolvers.definitions { if let TypeSystemDefinition::TypeDefinition(def) = type_definition { + if matches!(def, TypeDefinition::InputObject(_)) { + // input types can never be resolver outputs. + continue; + } let ts_type = ts_types.get(def.name().name).unwrap(); self.writer.write("type "); @@ -121,7 +131,9 @@ where let type_names_type = ts_union(document_for_resolvers.definitions.iter().filter_map( |type_definition| match type_definition { - TypeSystemDefinition::TypeDefinition(type_definition) => { + TypeSystemDefinition::TypeDefinition(type_definition) + if !matches!(type_definition, TypeDefinition::InputObject(_)) => + { Some(TSType::StringLiteral(type_definition.name().to_string())) } _ => None, @@ -132,13 +144,17 @@ where .definitions .iter() .filter_map(|type_definition| match type_definition { - TypeSystemDefinition::TypeDefinition(type_definition) => Some(ObjectField { - key: ObjectKey::from(type_definition.name()), - r#type: TSType::TypeVariable(type_definition.name().into()), - description: None, - readonly: false, - optional: false, - }), + TypeSystemDefinition::TypeDefinition(type_definition) + if !matches!(type_definition, TypeDefinition::InputObject(_)) => + { + Some(ObjectField { + key: ObjectKey::from(type_definition.name()), + r#type: TSType::TypeVariable(type_definition.name().into()), + description: None, + readonly: false, + optional: false, + }) + } _ => None, }) .collect(), diff --git a/crates/printer/src/resolver_type_printer/tests/snapshots/nitrogql_printer__resolver_type_printer__tests__resolver_printing.snap b/crates/printer/src/resolver_type_printer/tests/snapshots/nitrogql_printer__resolver_type_printer__tests__resolver_printing.snap index 3a799faa..a8b6f1cd 100644 --- a/crates/printer/src/resolver_type_printer/tests/snapshots/nitrogql_printer__resolver_type_printer__tests__resolver_printing.snap +++ b/crates/printer/src/resolver_type_printer/tests/snapshots/nitrogql_printer__resolver_type_printer__tests__resolver_printing.snap @@ -6,14 +6,13 @@ import type { GraphQLResolveInfo } from "graphql"; import type * as Schema from "schema"; type __Resolver = (parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => Result | Promise; type __TypeResolver = (object: Obj, context: Context, info: GraphQLResolveInfo) => Result | Promise; -type User = Omit; -type Bot = Omit; -type Post = Omit; -type Query = Omit; +type User = Omit; +type Bot = Omit; +type Post = Omit; +type Query = Omit; type HasID = User | Bot; type UserOrBot = User | Bot; -type UserType = Schema.UserType; -type UserSearchQuery = Schema.UserSearchQuery; +type UserType = Schema.__ResolverOutput.UserType; export type Resolvers = { User: { id: __Resolver; @@ -41,7 +40,7 @@ export type Resolvers = { __resolveType: __TypeResolver; }; }; -export type ResolverOutput = +export type ResolverOutput = { User: User; Bot: Bot; @@ -50,6 +49,5 @@ export type ResolverOutput, context: &ResolverTypePrinterContext, ) -> TSType { - let base_type = TSType::NamespaceMember( + let base_type = TSType::NamespaceMember3( context.options.schema_root_namespace.clone(), + TypeTarget::ResolverOutput.to_string(), def.name().name.to_string(), ); match def { @@ -57,17 +59,17 @@ pub fn get_resolver_type( fn get_object_resolver_type( def: &ObjectTypeDefinition<'_>, - _context: &ResolverTypePrinterContext, + context: &ResolverTypePrinterContext, ) -> Option { let parent_type = TSType::TypeVariable((&def.name).into()); let fields = def .fields .iter() .map(|field| { - let arguments_type = field - .arguments - .as_ref() - .map_or_else(|| TSType::Object(vec![]), arguments_definition_to_ts); + let arguments_type = field.arguments.as_ref().map_or_else( + || TSType::Object(vec![]), + |arguments| arguments_definition_to_ts(context, arguments), + ); let result_type = get_ts_type_of_type(&field.r#type, |name| { TSType::TypeVariable((&name.name).into()) }); @@ -162,12 +164,19 @@ fn get_union_resolver_type( Some(TSType::object(vec![("__resolveType", resolver_type, None)])) } -fn arguments_definition_to_ts(arguments: &ArgumentsDefinition) -> TSType { +fn arguments_definition_to_ts( + context: &ResolverTypePrinterContext, + arguments: &ArgumentsDefinition, +) -> TSType { TSType::object(arguments.input_values.iter().map(|argument| { ( ObjectKey::from(&argument.name), get_ts_type_of_type(&argument.r#type, |name| { - TSType::TypeVariable((&name.name).into()) + TSType::NamespaceMember3( + context.options.schema_root_namespace.clone(), + TypeTarget::ResolverInput.to_string(), + name.name.to_string(), + ) }), argument.description.as_ref().map(|s| s.to_string()), ) diff --git a/crates/printer/src/schema.rs b/crates/printer/src/schema.rs index 3e913f22..167cab16 100644 --- a/crates/printer/src/schema.rs +++ b/crates/printer/src/schema.rs @@ -1,13 +1,15 @@ use std::collections::HashMap; +use nitrogql_config_file::ScalarTypeConfig; + /// Generates scalar definitions for built-in scalars. -pub fn get_builtin_scalar_types() -> HashMap { +pub fn get_builtin_scalar_types() -> HashMap { vec![ - ("ID".into(), "string".into()), - ("String".into(), "string".into()), - ("Int".into(), "number".into()), - ("Float".into(), "number".into()), - ("Boolean".into(), "boolean".into()), + ("ID".into(), ScalarTypeConfig::Single("string".into())), + ("String".into(), ScalarTypeConfig::Single("string".into())), + ("Int".into(), ScalarTypeConfig::Single("number".into())), + ("Float".into(), ScalarTypeConfig::Single("number".into())), + ("Boolean".into(), ScalarTypeConfig::Single("boolean".into())), ] .into_iter() .collect() diff --git a/crates/printer/src/schema_type_printer/context.rs b/crates/printer/src/schema_type_printer/context.rs index a4ac6415..ef09eab2 100644 --- a/crates/printer/src/schema_type_printer/context.rs +++ b/crates/printer/src/schema_type_printer/context.rs @@ -9,6 +9,7 @@ use nitrogql_ast::{ type_system::{TypeDefinition, TypeSystemDefinition}, TypeSystemDocument, }; +use nitrogql_config_file::{ScalarTypeConfig, TypeTarget}; use crate::SchemaTypePrinterOptions; @@ -17,9 +18,11 @@ pub struct SchemaTypePrinterContext<'src> { pub document: &'src TypeSystemDocument<'src>, pub schema: &'src Schema, Pos>, // Mapping from Scalar name to TypeScript types. - pub scalar_types: HashMap, + pub scalar_types: HashMap, /// Mapping from schema type name to local type name. pub local_type_names: HashMap, + /// Current output type target. + pub type_target: TypeTarget, } impl SchemaTypePrinterContext<'_> { @@ -27,6 +30,7 @@ impl SchemaTypePrinterContext<'_> { options: &'src SchemaTypePrinterOptions, document: &'src TypeSystemDocument<'src>, schema: &'src Schema, Pos>, + type_target: TypeTarget, ) -> SchemaTypePrinterContext<'src> { let scalar_types = get_scalar_types(document, options); let local_type_names = make_local_type_names(document, &scalar_types); @@ -36,6 +40,7 @@ impl SchemaTypePrinterContext<'_> { schema, scalar_types, local_type_names, + type_target, } } } @@ -44,7 +49,7 @@ impl SchemaTypePrinterContext<'_> { fn get_scalar_types( document: &TypeSystemDocument, options: &SchemaTypePrinterOptions, -) -> HashMap { +) -> HashMap { document .definitions .iter() @@ -71,16 +76,16 @@ fn get_scalar_types( .and_then(|v| v.as_string()) }) }) - .map(|v| &v.value); - let scalar_ts_type = scalar_type_from_config.or(directive_ts_type); - scalar_ts_type.map(|ty| (definition.name.name.to_owned(), ty.to_owned())) + .map(|v| ScalarTypeConfig::Single(v.value.clone())); + let scalar_ts_type = scalar_type_from_config.cloned().or(directive_ts_type); + scalar_ts_type.map(|ty| (definition.name.name.to_owned(), ty)) }) .collect() } -fn get_bag_of_identifiers(scalar_types: &HashMap) -> HashSet<&str> { +fn get_bag_of_identifiers(scalar_types: &HashMap) -> HashSet<&str> { let mut result = vec![]; - for value in scalar_types.values() { + for value in scalar_types.values().flat_map(|v| v.type_names()) { let mut start_index = 0; let mut in_identifier = false; for (index, c) in value.char_indices() { @@ -104,7 +109,7 @@ fn get_bag_of_identifiers(scalar_types: &HashMap) -> HashSet<&st fn make_local_type_names( document: &TypeSystemDocument, - scalar_types: &HashMap, + scalar_types: &HashMap, ) -> HashMap { // The bag is the set of identifiers that appear in TypeScript types of scalars. // We will use this to avoid name collisions. diff --git a/crates/printer/src/schema_type_printer/printer.rs b/crates/printer/src/schema_type_printer/printer.rs index e0986709..1a7cbdc6 100644 --- a/crates/printer/src/schema_type_printer/printer.rs +++ b/crates/printer/src/schema_type_printer/printer.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; -use nitrogql_ast::type_system::TypeSystemDocument; -use nitrogql_config_file::Config; +use nitrogql_ast::type_system::{TypeDefinition, TypeSystemDefinition, TypeSystemDocument}; +use nitrogql_config_file::{Config, ScalarTypeConfig, TypeTarget}; use nitrogql_semantics::ast_to_type_system; use sourcemap_writer::SourceMapWriter; -use crate::schema::get_builtin_scalar_types; +use crate::{schema::get_builtin_scalar_types, ts_types::TSType}; use super::{ context::SchemaTypePrinterContext, error::SchemaTypePrinterResult, type_printer::TypePrinter, @@ -13,7 +13,7 @@ use super::{ pub struct SchemaTypePrinterOptions { /// Type of each scalar. Provided as raw TypeScript code. - pub scalar_types: HashMap, + pub scalar_types: HashMap, /// Special type name for types that includes schema metadata pub schema_metadata_type: String, /// Whether to make input nullable fields optional. @@ -50,7 +50,7 @@ impl SchemaTypePrinterOptions { .r#type .scalar_types .iter() - .map(|(key, value)| (key.to_owned(), value.to_owned())), + .map(|(key, value)| (key.to_owned(), value.clone())), ); result } @@ -71,8 +71,100 @@ where pub fn print_document(&mut self, document: &TypeSystemDocument) -> SchemaTypePrinterResult<()> { let schema = ast_to_type_system(document); - let context = SchemaTypePrinterContext::new(&self.options, document, &schema); - document.print_type(&context, self.writer)?; + self.print_prelude(document); + + for target in [ + TypeTarget::OperationInput, + TypeTarget::OperationOutput, + TypeTarget::ResolverInput, + TypeTarget::ResolverOutput, + ] { + writeln!(self.writer, "export declare namespace {target} {{"); + self.writer.indent(); + let context = SchemaTypePrinterContext::new(&self.options, document, &schema, target); + for def in document.definitions.iter() { + def.print_type(&context, self.writer)?; + self.writer.write("\n"); + } + self.writer.dedent(); + writeln!(self.writer, "}}\n"); + } + + let context = SchemaTypePrinterContext::new( + &self.options, + document, + &schema, + // target is dummy + TypeTarget::OperationOutput, + ); + for def in document.definitions.iter() { + def.print_representative(&context, self.writer)?; + self.writer.write("\n"); + } + Ok(()) } + + fn print_prelude(&mut self, document: &TypeSystemDocument) { + self.writer.write("export type "); + self.writer.write(&self.options.schema_metadata_type); + self.writer.write(" = "); + let schema_metadata_type = get_schema_metadata_type(document); + schema_metadata_type.print_type(self.writer); + self.writer.write(";\n\n"); + // Print utility types + self.writer.write( + "type __Beautify = { [K in keyof Obj]: Obj[K] } & {}; +export type __SelectionSet = + __Beautify> & Others>; + +", + ); + } +} +fn get_schema_metadata_type(document: &TypeSystemDocument) -> TSType { + let schema_definition = document.definitions.iter().find_map(|def| match def { + TypeSystemDefinition::SchemaDefinition(def) => Some(def), + _ => None, + }); + if let Some(schema_def) = schema_definition { + return TSType::object(schema_def.definitions.iter().map(|(op, ty)| { + ( + op.as_str(), + TSType::TypeVariable(ty.into()), + schema_def.description.as_ref().map(|d| d.value.clone()), + ) + })); + } + // If there is no schema definition, use default root type names. + let mut operations = vec![]; + for d in document.definitions.iter() { + let TypeSystemDefinition::TypeDefinition(ref def) = d else { + continue; + }; + let TypeDefinition::Object(ref def) = def else { + continue; + }; + + match def.name.name { + "Query" => { + operations.push(("query", (&def.name).into())); + } + "Mutation" => { + operations.push(("mutation", (&def.name).into())); + } + "Subscription" => { + operations.push(("subscription", (&def.name).into())); + } + _ => {} + } + } + + TSType::object( + operations + .into_iter() + .map(|(op, ty)| (op, TSType::TypeVariable(ty), None)), + ) } diff --git a/crates/printer/src/schema_type_printer/tests/mod.rs b/crates/printer/src/schema_type_printer/tests/mod.rs index b60d8b2b..12af3f7f 100644 --- a/crates/printer/src/schema_type_printer/tests/mod.rs +++ b/crates/printer/src/schema_type_printer/tests/mod.rs @@ -2,6 +2,7 @@ use insta::assert_snapshot; use nitrogql_ast::type_system::TypeSystemDocument; +use nitrogql_config_file::ScalarTypeConfig; use crate::schema_type_printer::{ error::SchemaTypePrinterResult, @@ -135,8 +136,14 @@ fn scalar_printing() { let doc = resolve_schema_extensions(doc).unwrap(); let mut options = SchemaTypePrinterOptions::default(); options.scalar_types.extend(vec![ - ("BigInt".to_owned(), "bigint".to_owned()), - ("URL".to_owned(), "string".to_owned()), + ( + "BigInt".to_owned(), + ScalarTypeConfig::Single("bigint".to_owned()), + ), + ( + "URL".to_owned(), + ScalarTypeConfig::Single("string".to_owned()), + ), ]); let printed = print_document(&doc, options).unwrap(); assert_snapshot!(printed); @@ -158,8 +165,14 @@ fn avoid_circular_reference_1() { let doc = resolve_schema_extensions(doc).unwrap(); let mut options = SchemaTypePrinterOptions::default(); options.scalar_types.extend(vec![ - ("BigInt".to_owned(), "bigint".to_owned()), - ("Date".to_owned(), "Date".to_owned()), + ( + "BigInt".to_owned(), + ScalarTypeConfig::Single("bigint".to_owned()), + ), + ( + "Date".to_owned(), + ScalarTypeConfig::Single("Date".to_owned()), + ), ]); let printed = print_document(&doc, options).unwrap(); // Date should be emitted as __tmp_Date @@ -182,8 +195,14 @@ fn avoid_circular_reference_2() { let doc = resolve_schema_extensions(doc).unwrap(); let mut options = SchemaTypePrinterOptions::default(); options.scalar_types.extend(vec![ - ("BigInt".to_owned(), "bigint".to_owned()), - ("Date".to_owned(), "Date | string".to_owned()), + ( + "BigInt".to_owned(), + ScalarTypeConfig::Single("bigint".to_owned()), + ), + ( + "Date".to_owned(), + ScalarTypeConfig::Single("Date | string".to_owned()), + ), ]); let printed = print_document(&doc, options).unwrap(); // Date should be emitted as __tmp_Date @@ -206,8 +225,14 @@ fn avoid_circular_reference_3() { let doc = resolve_schema_extensions(doc).unwrap(); let mut options = SchemaTypePrinterOptions::default(); options.scalar_types.extend(vec![ - ("Rec1".to_owned(), "string | Rec2".to_owned()), - ("Rec2".to_owned(), "Rec1 | number".to_owned()), + ( + "Rec1".to_owned(), + ScalarTypeConfig::Single("string | Rec2".to_owned()), + ), + ( + "Rec2".to_owned(), + ScalarTypeConfig::Single("Rec1 | number".to_owned()), + ), ]); let printed = print_document(&doc, options).unwrap(); assert_snapshot!(printed); diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_1.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_1.snap index 593bf296..a5b5b0e4 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_1.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_1.snap @@ -9,15 +9,58 @@ export type __SelectionSet = __Beautify> & Others>; -export type BigInt = bigint; -type __tmp_Date = Date; -export type { __tmp_Date as Date}; +export declare namespace __OperationInput { + export type BigInt = bigint; -export type Obj = { - __typename: "Obj"; - bigint: BigInt | null; - date: __tmp_Date; -}; + type __tmp_Date = Date; + export type { __tmp_Date as Date}; + + +} + +export declare namespace __OperationOutput { + export type BigInt = bigint; + + type __tmp_Date = Date; + export type { __tmp_Date as Date}; + + export type Obj = { + __typename: "Obj"; + bigint: BigInt | null; + date: __tmp_Date; + }; + +} + +export declare namespace __ResolverInput { + export type BigInt = bigint; + + type __tmp_Date = Date; + export type { __tmp_Date as Date}; + + +} + +export declare namespace __ResolverOutput { + export type BigInt = bigint; + + type __tmp_Date = Date; + export type { __tmp_Date as Date}; + + export type Obj = { + __typename: "Obj"; + bigint: BigInt | null; + date: __tmp_Date; + }; + +} + +export type BigInt = __OperationOutput.BigInt; + +type __tmp_Date = __OperationOutput.Date; +export type { __tmp_Date as Date }; + +export type Obj = __OperationOutput.Obj; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_2.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_2.snap index 46e57257..89090a41 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_2.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_2.snap @@ -9,15 +9,58 @@ export type __SelectionSet = __Beautify> & Others>; -export type BigInt = bigint; -type __tmp_Date = Date | string; -export type { __tmp_Date as Date}; +export declare namespace __OperationInput { + export type BigInt = bigint; -export type Obj = { - __typename: "Obj"; - bigint: BigInt | null; - date: __tmp_Date; -}; + type __tmp_Date = Date | string; + export type { __tmp_Date as Date}; + + +} + +export declare namespace __OperationOutput { + export type BigInt = bigint; + + type __tmp_Date = Date | string; + export type { __tmp_Date as Date}; + + export type Obj = { + __typename: "Obj"; + bigint: BigInt | null; + date: __tmp_Date; + }; + +} + +export declare namespace __ResolverInput { + export type BigInt = bigint; + + type __tmp_Date = Date | string; + export type { __tmp_Date as Date}; + + +} + +export declare namespace __ResolverOutput { + export type BigInt = bigint; + + type __tmp_Date = Date | string; + export type { __tmp_Date as Date}; + + export type Obj = { + __typename: "Obj"; + bigint: BigInt | null; + date: __tmp_Date; + }; + +} + +export type BigInt = __OperationOutput.BigInt; + +type __tmp_Date = __OperationOutput.Date; +export type { __tmp_Date as Date }; + +export type Obj = __OperationOutput.Obj; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_3.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_3.snap index f92def12..c0da8fc1 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_3.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__avoid_circular_reference_3.snap @@ -9,16 +9,63 @@ export type __SelectionSet = __Beautify> & Others>; -type __tmp_Rec1 = string | Rec2; -export type { __tmp_Rec1 as Rec1}; -type __tmp_Rec2 = Rec1 | number; -export type { __tmp_Rec2 as Rec2}; +export declare namespace __OperationInput { + type __tmp_Rec1 = string | Rec2; + export type { __tmp_Rec1 as Rec1}; -export type Obj = { - __typename: "Obj"; - rec1: __tmp_Rec1; - rec2: __tmp_Rec2; -}; + type __tmp_Rec2 = Rec1 | number; + export type { __tmp_Rec2 as Rec2}; + + +} + +export declare namespace __OperationOutput { + type __tmp_Rec1 = string | Rec2; + export type { __tmp_Rec1 as Rec1}; + + type __tmp_Rec2 = Rec1 | number; + export type { __tmp_Rec2 as Rec2}; + + export type Obj = { + __typename: "Obj"; + rec1: __tmp_Rec1; + rec2: __tmp_Rec2; + }; + +} + +export declare namespace __ResolverInput { + type __tmp_Rec1 = string | Rec2; + export type { __tmp_Rec1 as Rec1}; + + type __tmp_Rec2 = Rec1 | number; + export type { __tmp_Rec2 as Rec2}; + + +} + +export declare namespace __ResolverOutput { + type __tmp_Rec1 = string | Rec2; + export type { __tmp_Rec1 as Rec1}; + + type __tmp_Rec2 = Rec1 | number; + export type { __tmp_Rec2 as Rec2}; + + export type Obj = { + __typename: "Obj"; + rec1: __tmp_Rec1; + rec2: __tmp_Rec2; + }; + +} + +type __tmp_Rec1 = __OperationOutput.Rec1; +export type { __tmp_Rec1 as Rec1 }; + +type __tmp_Rec2 = __OperationOutput.Rec2; +export type { __tmp_Rec2 as Rec2 }; + +export type Obj = __OperationOutput.Obj; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__deprecated_items.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__deprecated_items.snap index 8fd7bfe7..608682ff 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__deprecated_items.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__deprecated_items.snap @@ -11,38 +11,115 @@ export type __SelectionSet = __Beautify> & Others>; -export type ID = string; - -export type String = string; - -export type Int = number; - -export type User = { - __typename: "User"; - id: ID; - name: String; - /** - * Age of user. - * @deprecated No longer supported - */ - age: Int | null; - /** - * @deprecated Deprecated for political reasons - */ - gender: String | null; -}; -export type Query = { - __typename: "Query"; - me: User; -}; +export declare namespace __OperationInput { + export type ID = string; -export type UserSearchQuery = { - /** - * @deprecated No longer supported - */ - readonly age?: Int | null | undefined; - readonly name?: String | null | undefined; -}; + export type String = string; + + export type Int = number; + + + + export type UserSearchQuery = { + /** + * @deprecated No longer supported + */ + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + }; + +} + +export declare namespace __OperationOutput { + export type ID = string; + + export type String = string; + + export type Int = number; + + export type User = { + __typename: "User"; + id: ID; + name: String; + /** + * Age of user. + * @deprecated No longer supported + */ + age: Int | null; + /** + * @deprecated Deprecated for political reasons + */ + gender: String | null; + }; + + export type Query = { + __typename: "Query"; + me: User; + }; + + +} + +export declare namespace __ResolverInput { + export type ID = string; + + export type String = string; + + export type Int = number; + + + + export type UserSearchQuery = { + /** + * @deprecated No longer supported + */ + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + }; + +} + +export declare namespace __ResolverOutput { + export type ID = string; + + export type String = string; + + export type Int = number; + + export type User = { + __typename: "User"; + id: ID; + name: String; + /** + * Age of user. + * @deprecated No longer supported + */ + age: Int | null; + /** + * @deprecated Deprecated for political reasons + */ + gender: String | null; + }; + + export type Query = { + __typename: "Query"; + me: User; + }; + + +} + +export type ID = __OperationOutput.ID; + +export type String = __OperationOutput.String; + +export type Int = __OperationOutput.Int; + +export type User = __OperationOutput.User; + +export type Query = __OperationOutput.Query; + +export type UserSearchQuery = __ResolverInput.UserSearchQuery; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__enum_runtime.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__enum_runtime.snap index d68c7734..7b24efc7 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__enum_runtime.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__enum_runtime.snap @@ -9,11 +9,32 @@ export type __SelectionSet = __Beautify> & Others>; -export type UserType = "NormalUser" | "PremiumUser" | "AdminUser"; + +export declare namespace __OperationInput { + export type UserType = "NormalUser" | "PremiumUser" | "AdminUser"; + +} + +export declare namespace __OperationOutput { + export type UserType = "NormalUser" | "PremiumUser" | "AdminUser"; + +} + +export declare namespace __ResolverInput { + export type UserType = "NormalUser" | "PremiumUser" | "AdminUser"; + +} + +export declare namespace __ResolverOutput { + export type UserType = "NormalUser" | "PremiumUser" | "AdminUser"; + +} + +export type UserType = __OperationOutput.UserType; export const UserType = { -NormalUser: "NormalUser", -PremiumUser: "PremiumUser", -AdminUser: "AdminUser", + NormalUser: "NormalUser", + PremiumUser: "PremiumUser", + AdminUser: "AdminUser", } as const; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__scalar_printing.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__scalar_printing.snap index 297edb50..2e0da739 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__scalar_printing.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__scalar_printing.snap @@ -9,8 +9,37 @@ export type __SelectionSet = __Beautify> & Others>; -export type BigInt = bigint; -export type URL = string; +export declare namespace __OperationInput { + export type BigInt = bigint; + + export type URL = string; + +} + +export declare namespace __OperationOutput { + export type BigInt = bigint; + + export type URL = string; + +} + +export declare namespace __ResolverInput { + export type BigInt = bigint; + + export type URL = string; + +} + +export declare namespace __ResolverOutput { + export type BigInt = bigint; + + export type URL = string; + +} + +export type BigInt = __OperationOutput.BigInt; + +export type URL = __OperationOutput.URL; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing.snap index 77d1a6c7..3e908575 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing.snap @@ -11,47 +11,151 @@ export type __SelectionSet = __Beautify> & Others>; -export type ID = string; -export type String = string; +export declare namespace __OperationInput { + export type ID = string; -export type Int = number; + export type String = string; -export type User = { - __typename: "User"; - id: ID; - name: String; - type: UserType; - age: Int | null; - posts: (Post)[]; -}; + export type Int = number; -export type Bot = { - __typename: "Bot"; - id: ID; -}; -export type Post = { - __typename: "Post"; - id: ID; - title: String; - tags: (String)[] | null; - body: String; -}; -export type Query = { - __typename: "Query"; - me: User; -}; -export type HasID = User | Bot; -export type UserType = "NormalUser" | "PremiumUser"; -export type UserSearchQuery = { - readonly age?: Int | null | undefined; - readonly name?: String | null | undefined; - readonly keywords?: readonly (String)[] | null | undefined; -}; + export type UserType = "NormalUser" | "PremiumUser"; + + export type UserSearchQuery = { + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + readonly keywords?: readonly (String)[] | null | undefined; + }; + +} + +export declare namespace __OperationOutput { + export type ID = string; + + export type String = string; + + export type Int = number; + + export type User = { + __typename: "User"; + id: ID; + name: String; + type: UserType; + age: Int | null; + posts: (Post)[]; + }; + + export type Bot = { + __typename: "Bot"; + id: ID; + }; + + export type Post = { + __typename: "Post"; + id: ID; + title: String; + tags: (String)[] | null; + body: String; + }; + + export type Query = { + __typename: "Query"; + me: User; + }; + + export type HasID = User | Bot; + + export type UserType = "NormalUser" | "PremiumUser"; + + +} + +export declare namespace __ResolverInput { + export type ID = string; + + export type String = string; + + export type Int = number; + + + + + + + export type UserType = "NormalUser" | "PremiumUser"; + + export type UserSearchQuery = { + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + readonly keywords?: readonly (String)[] | null | undefined; + }; + +} + +export declare namespace __ResolverOutput { + export type ID = string; + + export type String = string; + + export type Int = number; + + export type User = { + __typename: "User"; + id: ID; + name: String; + type: UserType; + age: Int | null; + posts: (Post)[]; + }; + + export type Bot = { + __typename: "Bot"; + id: ID; + }; + + export type Post = { + __typename: "Post"; + id: ID; + title: String; + tags: (String)[] | null; + body: String; + }; + + export type Query = { + __typename: "Query"; + me: User; + }; + + export type HasID = User | Bot; + + export type UserType = "NormalUser" | "PremiumUser"; + + +} + +export type ID = __OperationOutput.ID; + +export type String = __OperationOutput.String; + +export type Int = __OperationOutput.Int; + +export type User = __OperationOutput.User; + +export type Bot = __OperationOutput.Bot; + +export type Post = __OperationOutput.Post; + +export type Query = __OperationOutput.Query; + +export type HasID = __OperationOutput.HasID; + +export type UserType = __OperationOutput.UserType; + +export type UserSearchQuery = __ResolverInput.UserSearchQuery; diff --git a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing_with_desc.snap b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing_with_desc.snap index 3bb8d947..843a812c 100644 --- a/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing_with_desc.snap +++ b/crates/printer/src/schema_type_printer/tests/snapshots/nitrogql_printer__schema_type_printer__tests__type_printing_with_desc.snap @@ -11,62 +11,181 @@ export type __SelectionSet = __Beautify> & Others>; -export type ID = string; -export type String = string; +export declare namespace __OperationInput { + export type ID = string; -export type Int = number; + export type String = string; + + export type Int = number; + + + + + + + export type UserType = "NormalUser" | "PremiumUser"; + + export type UserSearchQuery = { + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + }; + +} + +export declare namespace __OperationOutput { + export type ID = string; + + export type String = string; + + export type Int = number; -/** - * This is User. - */ -export type User = { - __typename: "User"; - id: ID; /** - * Name of user. + * This is User. */ - name: String; - type: UserType; + export type User = { + __typename: "User"; + id: ID; + /** + * Name of user. + */ + name: String; + type: UserType; + /** + * Age of user. User may choose to not register their age. + */ + age: Int | null; + posts: (Post)[]; + }; + + export type Bot = { + __typename: "Bot"; + id: ID; + }; + + export type Post = { + __typename: "Post"; + id: ID; + title: String; + tags: (String)[] | null; + body: String; + }; + + export type Query = { + __typename: "Query"; + /** + * Returns my account. + * Note that query without authorization header results in a error. + */ + me: User; + }; + /** - * Age of user. User may choose to not register their age. + * Node that has an id field. */ - age: Int | null; - posts: (Post)[]; -}; + export type HasID = User | Bot; + + export type UserType = "NormalUser" | "PremiumUser"; + + +} + +export declare namespace __ResolverInput { + export type ID = string; + + export type String = string; + + export type Int = number; + -export type Bot = { - __typename: "Bot"; - id: ID; -}; -export type Post = { - __typename: "Post"; - id: ID; - title: String; - tags: (String)[] | null; - body: String; -}; -export type Query = { - __typename: "Query"; + + + export type UserType = "NormalUser" | "PremiumUser"; + + export type UserSearchQuery = { + readonly age?: Int | null | undefined; + readonly name?: String | null | undefined; + }; + +} + +export declare namespace __ResolverOutput { + export type ID = string; + + export type String = string; + + export type Int = number; + /** - * Returns my account. - * Note that query without authorization header results in a error. + * This is User. */ - me: User; -}; + export type User = { + __typename: "User"; + id: ID; + /** + * Name of user. + */ + name: String; + type: UserType; + /** + * Age of user. User may choose to not register their age. + */ + age: Int | null; + posts: (Post)[]; + }; -/** - * Node that has an id field. - */ -export type HasID = User | Bot; + export type Bot = { + __typename: "Bot"; + id: ID; + }; -export type UserType = "NormalUser" | "PremiumUser"; + export type Post = { + __typename: "Post"; + id: ID; + title: String; + tags: (String)[] | null; + body: String; + }; -export type UserSearchQuery = { - readonly age?: Int | null | undefined; - readonly name?: String | null | undefined; -}; + export type Query = { + __typename: "Query"; + /** + * Returns my account. + * Note that query without authorization header results in a error. + */ + me: User; + }; + + /** + * Node that has an id field. + */ + export type HasID = User | Bot; + + export type UserType = "NormalUser" | "PremiumUser"; + + +} + +export type ID = __OperationOutput.ID; + +export type String = __OperationOutput.String; + +export type Int = __OperationOutput.Int; + +export type User = __OperationOutput.User; + +export type Bot = __OperationOutput.Bot; + +export type Post = __OperationOutput.Post; + +export type Query = __OperationOutput.Query; + +export type HasID = __OperationOutput.HasID; + +export type UserType = __OperationOutput.UserType; + +export type UserSearchQuery = __ResolverInput.UserSearchQuery; diff --git a/crates/printer/src/schema_type_printer/type_printer.rs b/crates/printer/src/schema_type_printer/type_printer.rs index d874ebe1..502dc758 100644 --- a/crates/printer/src/schema_type_printer/type_printer.rs +++ b/crates/printer/src/schema_type_printer/type_printer.rs @@ -11,10 +11,11 @@ use nitrogql_ast::{ type_system::{ EnumTypeDefinition, InputObjectTypeDefinition, InterfaceTypeDefinition, ObjectTypeDefinition, ScalarTypeDefinition, TypeDefinition, TypeSystemDefinition, - TypeSystemDocument, UnionTypeDefinition, + UnionTypeDefinition, }, value::StringValue, }; +use nitrogql_config_file::TypeTarget; use sourcemap_writer::SourceMapWriter; use crate::jsdoc::print_description as jsdoc_print_description; @@ -30,92 +31,33 @@ pub trait TypePrinter { context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()>; + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()>; } -impl TypePrinter for TypeSystemDocument<'_> { +impl TypePrinter for TypeSystemDefinition<'_> { fn print_type( &self, context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { - let schema_metadata_type = get_schema_metadata_type(self); - writer.write("export type "); - writer.write(&context.options.schema_metadata_type); - writer.write(" = "); - schema_metadata_type.print_type(writer); - writer.write(";\n\n"); - // Print utility types - writer.write( - "type __Beautify = { [K in keyof Obj]: Obj[K] } & {}; -export type __SelectionSet = - __Beautify> & Others>; -", - ); - - for def in self.definitions.iter() { - def.print_type(context, writer)?; - writer.write("\n"); - } - Ok(()) - } -} - -fn get_schema_metadata_type(document: &TypeSystemDocument) -> TSType { - let schema_definition = document.definitions.iter().find_map(|def| match def { - TypeSystemDefinition::SchemaDefinition(def) => Some(def), - _ => None, - }); - if let Some(schema_def) = schema_definition { - return TSType::object(schema_def.definitions.iter().map(|(op, ty)| { - ( - op.as_str(), - TSType::TypeVariable(ty.into()), - schema_def.description.as_ref().map(|d| d.value.clone()), - ) - })); - } - // If there is no schema definition, use default root type names. - let mut operations = vec![]; - for d in document.definitions.iter() { - let TypeSystemDefinition::TypeDefinition(ref def) = d else { - continue; - }; - let TypeDefinition::Object(ref def) = def else { - continue; - }; - - match def.name.name { - "Query" => { - operations.push(("query", (&def.name).into())); - } - "Mutation" => { - operations.push(("mutation", (&def.name).into())); - } - "Subscription" => { - operations.push(("subscription", (&def.name).into())); - } - _ => {} + match self { + TypeSystemDefinition::SchemaDefinition(_) => Ok(()), + TypeSystemDefinition::TypeDefinition(def) => def.print_type(context, writer), + TypeSystemDefinition::DirectiveDefinition(_) => Ok(()), } } - - TSType::object( - operations - .into_iter() - .map(|(op, ty)| (op, TSType::TypeVariable(ty), None)), - ) -} - -impl TypePrinter for TypeSystemDefinition<'_> { - fn print_type( + fn print_representative( &self, context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { match self { TypeSystemDefinition::SchemaDefinition(_) => Ok(()), - TypeSystemDefinition::TypeDefinition(def) => def.print_type(context, writer), + TypeSystemDefinition::TypeDefinition(def) => def.print_representative(context, writer), TypeSystemDefinition::DirectiveDefinition(_) => Ok(()), } } @@ -136,6 +78,20 @@ impl TypePrinter for TypeDefinition<'_> { TypeDefinition::InputObject(def) => def.print_type(context, writer), } } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + match self { + TypeDefinition::Scalar(def) => def.print_representative(context, writer), + TypeDefinition::Object(def) => def.print_representative(context, writer), + TypeDefinition::Interface(def) => def.print_representative(context, writer), + TypeDefinition::Union(def) => def.print_representative(context, writer), + TypeDefinition::Enum(def) => def.print_representative(context, writer), + TypeDefinition::InputObject(def) => def.print_representative(context, writer), + } + } } impl TypePrinter for ScalarTypeDefinition<'_> { @@ -164,11 +120,29 @@ impl TypePrinter for ScalarTypeDefinition<'_> { &self.name, local_name, |writer| { - writer.write(scalar_type_str); + writer.write(scalar_type_str.get_type(context.type_target)); }, ); Ok(()) } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.scalar_keyword, + &self.name, + local_name, + TypeTarget::OperationOutput, + ); + Ok(()) + } } impl TypePrinter for ObjectTypeDefinition<'_> { @@ -177,6 +151,10 @@ impl TypePrinter for ObjectTypeDefinition<'_> { context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { + if context.type_target.is_input() { + // Object type is not used as input type. + return Ok(()); + } let type_name_ident = Ident { name: "__typename", position: Pos::builtin(), @@ -227,6 +205,24 @@ impl TypePrinter for ObjectTypeDefinition<'_> { ); Ok(()) } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.type_keyword, + &self.name, + local_name, + TypeTarget::OperationOutput, + ); + Ok(()) + } } impl TypePrinter for InterfaceTypeDefinition<'_> { @@ -235,6 +231,10 @@ impl TypePrinter for InterfaceTypeDefinition<'_> { context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { + if context.type_target.is_input() { + // Interface is not used as input type. + return Ok(()); + } // In generated type definitions, an interface is expressed as a union of all possible concrete types. let union_constituents = interface_implementers(context.schema, self.name.name).map(|obj| { @@ -261,6 +261,24 @@ impl TypePrinter for InterfaceTypeDefinition<'_> { ); Ok(()) } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.interface_keyword, + &self.name, + local_name, + TypeTarget::OperationOutput, + ); + Ok(()) + } } impl TypePrinter for UnionTypeDefinition<'_> { @@ -269,6 +287,10 @@ impl TypePrinter for UnionTypeDefinition<'_> { context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { + if context.type_target.is_input() { + // Union is not used as input type. + return Ok(()); + } let union_type = ts_union( self.members .iter() @@ -291,6 +313,24 @@ impl TypePrinter for UnionTypeDefinition<'_> { ); Ok(()) } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.union_keyword, + &self.name, + local_name, + TypeTarget::OperationOutput, + ); + Ok(()) + } } impl TypePrinter for EnumTypeDefinition<'_> { @@ -320,17 +360,36 @@ impl TypePrinter for EnumTypeDefinition<'_> { enum_type.print_type(writer); }, ); - + Ok(()) + } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.enum_keyword, + &self.name, + local_name, + TypeTarget::OperationOutput, + ); if context.options.emit_schema_runtime { writer.write_for("export const ", &self.enum_keyword); writer.write_for(self.name.name, &self.name); writer.write(" = {\n"); + writer.indent(); for value in &self.values { writer.write_for(value.name.name, &value.name); writer.write(": \""); writer.write_for(value.name.name, &value.name); writer.write("\",\n"); } + writer.dedent(); writer.write("} as const;\n") } Ok(()) @@ -343,6 +402,10 @@ impl TypePrinter for InputObjectTypeDefinition<'_> { context: &SchemaTypePrinterContext, writer: &mut impl SourceMapWriter, ) -> SchemaTypePrinterResult<()> { + if context.type_target.is_output() { + // Input object is not used as output type. + return Ok(()); + } let schema_type = context.schema.get_type(self.name.name); let obj_type = TSType::Object( self.fields @@ -398,6 +461,24 @@ impl TypePrinter for InputObjectTypeDefinition<'_> { ); Ok(()) } + fn print_representative( + &self, + context: &SchemaTypePrinterContext, + writer: &mut impl SourceMapWriter, + ) -> SchemaTypePrinterResult<()> { + let local_name = context + .local_type_names + .get(self.name.name) + .expect("Local type name not generated"); + export_representative( + writer, + &self.input_keyword, + &self.name, + local_name, + TypeTarget::ResolverInput, + ); + Ok(()) + } } fn export_type( @@ -426,6 +507,29 @@ fn export_type( } } +fn export_representative( + writer: &mut impl SourceMapWriter, + type_keyword: &impl HasPos, + schema_name: &Ident, + local_name: &str, + target: TypeTarget, +) { + if schema_name.name == local_name { + writer.write_for("export type ", type_keyword); + writer.write_for(local_name, schema_name); + writeln!(writer, " = {target}.{local_name};"); + } else { + writer.write_for("type ", type_keyword); + writer.write_for(local_name, schema_name); + writeln!(writer, " = {target}.{schema_name};"); + writeln!( + writer, + "export type {{ {local_name} as {} }};", + schema_name.name + ); + } +} + fn print_description(description: &Option, writer: &mut impl SourceMapWriter) { if let Some(description) = description { jsdoc_print_description(description, writer); diff --git a/crates/printer/src/ts_types/mod.rs b/crates/printer/src/ts_types/mod.rs index 9f0d12ed..ee636a3f 100644 --- a/crates/printer/src/ts_types/mod.rs +++ b/crates/printer/src/ts_types/mod.rs @@ -17,6 +17,8 @@ pub enum TSType { StringLiteral(String), /// Namespace member access N.K NamespaceMember(String, String), + /// Namespace member access N.K1.K2 + NamespaceMember3(String, String, String), /// Object type (key, value, readonly) Object(Vec), /// Array Type @@ -168,9 +170,10 @@ impl TSType { writer.write("\""); } TSType::NamespaceMember(ref ns, ref key) => { - writer.write(ns); - writer.write("."); - writer.write(key); + write!(writer, "{ns}.{key}"); + } + TSType::NamespaceMember3(ref ns, ref key1, ref key2) => { + write!(writer, "{ns}.{key1}.{key2}"); } TSType::Object(ref properties) => { if properties.is_empty() { @@ -287,6 +290,7 @@ impl TSType { t @ TSType::TypeVariable(_) | t @ TSType::StringLiteral(_) | t @ TSType::NamespaceMember(_, _) + | t @ TSType::NamespaceMember3(_, _, _) | t @ TSType::Never | t @ TSType::Null | t @ TSType::Undefined