diff --git a/crates/printer/src/operation_js_printer/mod.rs b/crates/printer/src/operation_js_printer/mod.rs index 04ecf90..c895d21 100644 --- a/crates/printer/src/operation_js_printer/mod.rs +++ b/crates/printer/src/operation_js_printer/mod.rs @@ -6,9 +6,12 @@ use crate::{operation_base_printer::OperationPrinter, OperationJSPrinterOptions} use self::visitor::OperationJSPrinterVisitor; pub mod options; +mod printers; mod tests; pub mod visitor; +pub use printers::{print_fragment_runtime, print_operation_runtime}; + /// Print a JavaScript module for given operation document. pub fn print_js_for_operation_document( options: OperationJSPrinterOptions, diff --git a/crates/printer/src/operation_js_printer/printers.rs b/crates/printer/src/operation_js_printer/printers.rs new file mode 100644 index 0000000..6ad519e --- /dev/null +++ b/crates/printer/src/operation_js_printer/printers.rs @@ -0,0 +1,59 @@ +use std::collections::HashMap; + +use crate::{ + json_printer::{print_to_json_string, ExecutableDefinitionRef}, + utils::fragment_names_in_selection_set, +}; +use nitrogql_ast::operation::{FragmentDefinition, OperationDefinition}; +use sourcemap_writer::SourceMapWriter; + +/// Print the runtime value of given operation. +pub fn print_operation_runtime( + writer: &mut impl SourceMapWriter, + operation: &OperationDefinition, + fragments: &HashMap<&str, &FragmentDefinition>, +) { + let fragments_to_include = fragment_names_in_selection_set(&operation.selection_set, |name| { + fragments.get(name).copied() + }) + .into_iter() + .map(|name| { + ExecutableDefinitionRef::FragmentDefinition( + fragments.get(name).expect("fragment not found"), + ) + }); + let this_document = vec![ExecutableDefinitionRef::OperationDefinition(operation)] + .into_iter() + .chain(fragments_to_include) + .collect::>(); + writer.write(&print_to_json_string(&this_document[..])); +} + +/// Print the runtime value of given fragment. +pub fn print_fragment_runtime( + writer: &mut impl SourceMapWriter, + fragment: &FragmentDefinition, + fragments: &HashMap<&str, &FragmentDefinition>, +) { + let fragments_to_include = fragment_names_in_selection_set(&fragment.selection_set, |name| { + fragments.get(name).copied() + }) + .into_iter() + .filter(|f| { + // Filter out the fragment we are currently processing + *f != fragment.name.name + }) + .map(|name| { + ExecutableDefinitionRef::FragmentDefinition( + fragments.get(name).expect("fragment not found"), + ) + }); + // Generated document is the collection of all relevant fragments, + // and the fragment we are currently processing + // comes first in the list + let this_document = vec![ExecutableDefinitionRef::FragmentDefinition(fragment)] + .into_iter() + .chain(fragments_to_include) + .collect::>(); + writer.write(&print_to_json_string(&this_document[..])); +} diff --git a/crates/printer/src/operation_js_printer/visitor.rs b/crates/printer/src/operation_js_printer/visitor.rs index 63cfddc..30259aa 100644 --- a/crates/printer/src/operation_js_printer/visitor.rs +++ b/crates/printer/src/operation_js_printer/visitor.rs @@ -1,13 +1,11 @@ use sourcemap_writer::SourceMapWriter; -use crate::{ - json_printer::{print_to_json_string, ExecutableDefinitionRef}, - operation_base_printer::{ - OperationPrinterVisitor, PrintFragmentContext, PrintOperationContext, - }, - utils::fragment_names_in_selection_set, +use crate::operation_base_printer::{ + OperationPrinterVisitor, PrintFragmentContext, PrintOperationContext, }; +use super::printers::{print_fragment_runtime, print_operation_runtime}; + pub struct OperationJSPrinterVisitor {} impl OperationJSPrinterVisitor { @@ -34,24 +32,7 @@ impl OperationPrinterVisitor for OperationJSPrinterVisitor { &operation.name_pos(), ); writer.write(" = "); - let fragments_to_include = - fragment_names_in_selection_set(&operation.selection_set, |name| { - context.fragments.get(name).copied() - }) - .into_iter() - .map(|name| { - ExecutableDefinitionRef::FragmentDefinition( - context.fragments.get(name).expect("fragment not found"), - ) - }); - // To follow the community conventions, generated JSON has only one operation in it - let this_document = vec![ExecutableDefinitionRef::OperationDefinition( - context.operation, - )] - .into_iter() - .chain(fragments_to_include) - .collect::>(); - writer.write(&print_to_json_string(&this_document[..])); + print_operation_runtime(writer, operation, context.fragments); writer.write(";\n\n"); } @@ -69,30 +50,7 @@ impl OperationPrinterVisitor for OperationJSPrinterVisitor { writer.write_for(context.var_name, fragment); writer.write(" = "); - - let fragments_to_include = - fragment_names_in_selection_set(&fragment.selection_set, |name| { - context.fragments.get(name).copied() - }) - .into_iter() - .filter(|f| { - // Filter out the fragment we are currently processing - *f != fragment.name.name - }) - .map(|name| { - ExecutableDefinitionRef::FragmentDefinition( - context.fragments.get(name).expect("fragment not found"), - ) - }); - - // Generated document is the collection of all relevant fragments, - // and the fragment we are currently processing - // comes first in the list - let this_document = vec![ExecutableDefinitionRef::FragmentDefinition(fragment)] - .into_iter() - .chain(fragments_to_include) - .collect::>(); - writer.write(&print_to_json_string(&this_document[..])); + print_fragment_runtime(writer, fragment, context.fragments); writer.write(";\n\n"); } fn print_default_exported_operation_definition( diff --git a/crates/printer/src/operation_type_printer/visitor.rs b/crates/printer/src/operation_type_printer/visitor.rs index 4bdb97a..07e5882 100644 --- a/crates/printer/src/operation_type_printer/visitor.rs +++ b/crates/printer/src/operation_type_printer/visitor.rs @@ -11,13 +11,12 @@ use nitrogql_utils::clone_into; use sourcemap_writer::SourceMapWriter; use crate::{ - json_printer::{print_to_json_string, ExecutableDefinitionRef}, operation_base_printer::{ options::OperationBasePrinterOptions, OperationPrinterVisitor, PrintFragmentContext, PrintOperationContext, }, + operation_js_printer::{print_fragment_runtime, print_operation_runtime}, ts_types::TSType, - utils::fragment_names_in_selection_set, }; use super::type_printer::{ @@ -215,24 +214,7 @@ impl<'a, 'src> OperationPrinterVisitor for OperationTypePrinterVisitor<'a, 'src> return; } writer.write("> = "); - let fragments_to_include = - fragment_names_in_selection_set(&operation.selection_set, |name| { - context.fragments.get(name).copied() - }) - .into_iter() - .map(|name| { - ExecutableDefinitionRef::FragmentDefinition( - context.fragments.get(name).expect("fragment not found"), - ) - }); - // To follow the community conventions, generated JSON has only one operation in it - let this_document = vec![ExecutableDefinitionRef::OperationDefinition( - context.operation, - )] - .into_iter() - .chain(fragments_to_include) - .collect::>(); - writer.write(&print_to_json_string(&this_document[..])); + print_operation_runtime(writer, operation, context.fragments); // Use the `as unknown as` technique to avoid the type system complaining about // the type of the JSON object not matching the type of the TypedDocumentNode // (because of the use of enums in the TypedDocumentNode type) @@ -306,30 +288,7 @@ impl<'a, 'src> OperationPrinterVisitor for OperationTypePrinterVisitor<'a, 'src> return; } writer.write(" = "); - - let fragments_to_include = - fragment_names_in_selection_set(&fragment.selection_set, |name| { - context.fragments.get(name).copied() - }) - .into_iter() - .filter(|f| { - // Filter out the fragment we are currently processing - *f != fragment.name.name - }) - .map(|name| { - ExecutableDefinitionRef::FragmentDefinition( - context.fragments.get(name).expect("fragment not found"), - ) - }); - - // Generated document is the collection of all relevant fragments, - // and the fragment we are currently processing - // comes first in the list - let this_document = vec![ExecutableDefinitionRef::FragmentDefinition(fragment)] - .into_iter() - .chain(fragments_to_include) - .collect::>(); - writer.write(&print_to_json_string(&this_document[..])); + print_fragment_runtime(writer, fragment, context.fragments); writer.write(" as unknown as TypedDocumentNode<"); writer.write_for(&fragment_type_name, fragment); writer.write(", never>;\n\n");