diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock index 59f5e0e979517..e627138c0dedb 100644 --- a/compiler/Cargo.lock +++ b/compiler/Cargo.lock @@ -693,6 +693,7 @@ dependencies = [ "graphql-syntax", "intern", "relay-test-schema", + "relay-transforms", "schema", ] @@ -1144,9 +1145,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" diff --git a/compiler/crates/common/src/feature_flags.rs b/compiler/crates/common/src/feature_flags.rs index d036cf1d2a27a..ce9efef4512db 100644 --- a/compiler/crates/common/src/feature_flags.rs +++ b/compiler/crates/common/src/feature_flags.rs @@ -53,6 +53,10 @@ pub struct FeatureFlags { /// Enable support for the experimental `@alias` directive on fragment spreads. #[serde(default)] pub enable_fragment_aliases: FeatureFlag, + + /// Print queries in compact form + #[serde(default)] + pub compact_query_text: FeatureFlag, } #[derive(Debug, Deserialize, Clone, Serialize)] diff --git a/compiler/crates/graphql-ir/src/node_identifier.rs b/compiler/crates/graphql-ir/src/node_identifier.rs index ef216d295ab14..e00fd3c377de8 100644 --- a/compiler/crates/graphql-ir/src/node_identifier.rs +++ b/compiler/crates/graphql-ir/src/node_identifier.rs @@ -7,8 +7,9 @@ use crate::*; use common::WithLocation; +use graphql_syntax::OperationKind; use intern::string_key::StringKey; -use schema::SDLSchema; +use schema::{FieldID, SDLSchema, Type}; use std::{ fmt, hash::{Hash, Hasher}, @@ -275,7 +276,7 @@ impl LocationAgnosticPartialEq for WithLocation } } -impl LocationAgnosticPartialEq for Option<&T> { +impl LocationAgnosticPartialEq for Option { fn location_agnostic_eq(&self, other: &Self) -> bool { match (self, other) { (Some(l), Some(r)) => l.location_agnostic_eq::(r), @@ -302,6 +303,9 @@ pub trait DirectlyComparableIR {} impl DirectlyComparableIR for Value {} impl DirectlyComparableIR for ConstantArgument {} impl DirectlyComparableIR for ConstantValue {} +impl DirectlyComparableIR for Selection {} +impl DirectlyComparableIR for ExecutableDefinition {} +impl DirectlyComparableIR for VariableDefinition {} impl LocationAgnosticPartialEq for Vec { fn location_agnostic_eq(&self, other: &Self) -> bool { @@ -405,6 +409,16 @@ impl LocationAgnosticPartialEq for Argument { } } +impl LocationAgnosticPartialEq for Option<&Argument> { + fn location_agnostic_eq(&self, other: &Self) -> bool { + match (self, other) { + (Some(l), Some(r)) => l.location_agnostic_eq::(r), + (None, None) => true, + _ => false, + } + } +} + impl LocationAgnosticHash for Value { fn location_agnostic_hash(&self, state: &mut H) { match self { @@ -517,3 +531,141 @@ impl LocationAgnosticPartialEq for ConditionValue { } } } + +impl LocationAgnosticPartialEq for ExecutableDefinition { + fn location_agnostic_eq(&self, other: &Self) -> bool { + match (self, other) { + (ExecutableDefinition::Operation(left), ExecutableDefinition::Operation(right)) => { + left.location_agnostic_eq::(right) + } + (ExecutableDefinition::Fragment(left), ExecutableDefinition::Fragment(right)) => { + left.location_agnostic_eq::(right) + } + _ => false, + } + } +} + +impl LocationAgnosticPartialEq for VariableDefinition { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.name.location_agnostic_eq::(&other.name) + && self.type_ == other.type_ + && self + .default_value + .location_agnostic_eq::(&other.default_value) + && self.directives.location_agnostic_eq::(&other.directives) + } +} + +impl LocationAgnosticPartialEq for OperationDefinition { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.kind.location_agnostic_eq::(&other.kind) + && self.name.location_agnostic_eq::(&other.name) + && self.type_.location_agnostic_eq::(&other.type_) + && self.kind.location_agnostic_eq::(&other.kind) + && self + .variable_definitions + .location_agnostic_eq::(&other.variable_definitions) + && self.directives.location_agnostic_eq::(&other.directives) + && self.selections.location_agnostic_eq::(&other.selections) + } +} + +impl LocationAgnosticPartialEq for OperationKind { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self == other + } +} +impl LocationAgnosticPartialEq for Type { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self == other + } +} + +impl LocationAgnosticPartialEq for Selection { + fn location_agnostic_eq(&self, other: &Self) -> bool { + match (self, other) { + (Selection::FragmentSpread(l), Selection::FragmentSpread(r)) => { + l.location_agnostic_eq::(r) + } + (Selection::InlineFragment(l), Selection::InlineFragment(r)) => { + l.location_agnostic_eq::(r) + } + (Selection::LinkedField(l), Selection::LinkedField(r)) => { + l.location_agnostic_eq::(r) + } + (Selection::ScalarField(l), Selection::ScalarField(r)) => { + l.location_agnostic_eq::(r) + } + (Selection::Condition(l), Selection::Condition(r)) => l.location_agnostic_eq::(r), + _ => false, + } + } +} + +impl LocationAgnosticPartialEq for FragmentSpread { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.fragment.location_agnostic_eq::(&other.fragment) + && self.arguments.location_agnostic_eq::(&other.arguments) + && self.directives.location_agnostic_eq::(&other.directives) + } +} + +impl LocationAgnosticPartialEq for InlineFragment { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.type_condition + .location_agnostic_eq::(&other.type_condition) + && self.directives.location_agnostic_eq::(&other.directives) + && self.selections.location_agnostic_eq::(&other.selections) + } +} + +impl LocationAgnosticPartialEq for LinkedField { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.alias.location_agnostic_eq::(&other.alias) + && self.definition.location_agnostic_eq::(&other.definition) + && self.arguments.location_agnostic_eq::(&other.arguments) + && self.directives.location_agnostic_eq::(&other.directives) + && self.selections.location_agnostic_eq::(&other.selections) + } +} + +impl LocationAgnosticPartialEq for ScalarField { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.alias.location_agnostic_eq::(&other.alias) + && self.definition.location_agnostic_eq::(&other.definition) + && self.arguments.location_agnostic_eq::(&other.arguments) + && self.directives.location_agnostic_eq::(&other.directives) + } +} + +impl LocationAgnosticPartialEq for Condition { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.selections.location_agnostic_eq::(&other.selections) + && self.value.location_agnostic_eq::(&other.value) + && self.passing_value == other.passing_value + } +} + +impl LocationAgnosticPartialEq for FragmentDefinition { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self.name.location_agnostic_eq::(&other.name) + && self + .variable_definitions + .location_agnostic_eq::(&other.variable_definitions) + && self + .used_global_variables + .location_agnostic_eq::(&other.used_global_variables) + && self + .type_condition + .location_agnostic_eq::(&other.type_condition) + && self.directives.location_agnostic_eq::(&other.directives) + && self.selections.location_agnostic_eq::(&other.selections) + } +} + +impl LocationAgnosticPartialEq for FieldID { + fn location_agnostic_eq(&self, other: &Self) -> bool { + self == other + } +} diff --git a/compiler/crates/graphql-text-printer/Cargo.toml b/compiler/crates/graphql-text-printer/Cargo.toml index cfd28330dbbc3..a5c14c57abaa5 100644 --- a/compiler/crates/graphql-text-printer/Cargo.toml +++ b/compiler/crates/graphql-text-printer/Cargo.toml @@ -25,3 +25,4 @@ schema = { path = "../schema" } [dev-dependencies] fixture-tests = { path = "../fixture-tests" } relay-test-schema = { path = "../relay-test-schema" } +relay-transforms = { path = "../relay-transforms" } diff --git a/compiler/crates/graphql-text-printer/src/print_full_operation.rs b/compiler/crates/graphql-text-printer/src/print_full_operation.rs index 90c46ff6d373c..9cf673f5b6e74 100644 --- a/compiler/crates/graphql-text-printer/src/print_full_operation.rs +++ b/compiler/crates/graphql-text-printer/src/print_full_operation.rs @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -use crate::{print_fragment, print_operation}; +use crate::{print_fragment, print_operation, PrinterOptions}; use fnv::FnvHashMap; use graphql_ir::{ FragmentDefinition, FragmentSpread, OperationDefinition, Program, ScalarField, Visitor, @@ -13,8 +13,12 @@ use graphql_ir::{ use intern::string_key::StringKey; use std::sync::Arc; -pub fn print_full_operation(program: &Program, operation: &OperationDefinition) -> String { - let mut printer = OperationPrinter::new(program); +pub fn print_full_operation( + program: &Program, + operation: &OperationDefinition, + options: PrinterOptions, +) -> String { + let mut printer = OperationPrinter::new(program, options); printer.print(operation) } @@ -22,19 +26,21 @@ pub struct OperationPrinter<'s> { fragment_result: FnvHashMap, reachable_fragments: FnvHashMap>, program: &'s Program, + options: PrinterOptions, } impl<'s> OperationPrinter<'s> { - pub fn new(program: &'s Program) -> Self { + pub fn new(program: &'s Program, options: PrinterOptions) -> Self { Self { fragment_result: Default::default(), reachable_fragments: Default::default(), program, + options, } } pub fn print(&mut self, operation: &OperationDefinition) -> String { - let mut result = print_operation(&self.program.schema, operation, Default::default()); + let mut result = print_operation(&self.program.schema, operation, self.options); self.visit_operation(operation); let mut fragments: Vec<(StringKey, Arc)> = self.reachable_fragments.drain().collect(); @@ -51,7 +57,7 @@ impl<'s> OperationPrinter<'s> { let schema = &self.program.schema; self.fragment_result .entry(fragment.name.item) - .or_insert_with(|| print_fragment(schema, fragment, Default::default())) + .or_insert_with(|| print_fragment(schema, fragment, self.options)) } } diff --git a/compiler/crates/graphql-text-printer/src/print_to_text.rs b/compiler/crates/graphql-text-printer/src/print_to_text.rs index fa8cf592ee034..6f57b7dfcf8e6 100644 --- a/compiler/crates/graphql-text-printer/src/print_to_text.rs +++ b/compiler/crates/graphql-text-printer/src/print_to_text.rs @@ -7,13 +7,13 @@ use common::{Named, NamedItem, WithLocation}; use graphql_ir::{ - Argument, Condition, ConditionValue, ConstantValue, Directive, ExecutableDefinition, - FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, OperationDefinition, - ScalarField, Selection, Value, VariableDefinition, + Argument, Condition, ConditionValue, ConstantArgument, ConstantValue, Directive, + ExecutableDefinition, FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, + OperationDefinition, ScalarField, Selection, Value, VariableDefinition, }; use graphql_syntax::OperationKind; use intern::string_key::{Intern, StringKey}; -use schema::{SDLSchema, Schema}; +use schema::{SDLSchema, Schema, Type, TypeReference}; use std::fmt::{Result as FmtResult, Write}; pub fn print_ir(schema: &SDLSchema, definitions: &[ExecutableDefinition]) -> Vec { @@ -193,17 +193,19 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { OperationKind::Mutation => "mutation", OperationKind::Subscription => "subscription", }; - let operation_name = operation.name.item; - write!(self.writer, "{} {}", operation_kind, operation_name)?; + write!(self.writer, "{}", operation_kind)?; + self.space(false)?; + write!(self.writer, "{}", operation.name.item)?; self.print_variable_definitions(&operation.variable_definitions)?; self.print_directives(&operation.directives, None, None)?; self.print_selections(&operation.selections) } fn print_fragment(mut self, fragment: &FragmentDefinition) -> FmtResult { - let fragment_name = fragment.name.item; - let type_condition_name = self.schema.get_type_name(fragment.type_condition); - write!(self.writer, "fragment {}", fragment_name)?; + self.text("fragment")?; + self.space(false)?; + write!(self.writer, "{}", fragment.name.item)?; + if fragment .directives .named("argumentDefinitions".intern()) @@ -211,8 +213,9 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { { self.print_variable_definitions(&fragment.variable_definitions)?; } - write!(self.writer, " on {}", type_condition_name)?; + self.space(false)?; + self.print_type_condition(fragment.type_condition)?; self.print_directives( &fragment.directives, None, @@ -224,20 +227,21 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { fn print_selections(&mut self, selections: &[Selection]) -> FmtResult { let len = selections.len(); if len > 0 { - write!(self.writer, " {{")?; + self.space(true)?; + self.text("{")?; self.indentation += 1; - self.next_line()?; + self.next_line(true)?; for (i, selection) in selections.iter().enumerate() { self.print_selection(selection, None)?; if i != len - 1 { - self.next_line()?; + self.item_separator()?; } } self.indentation -= 1; - self.next_line()?; - write!(self.writer, "}}")?; + self.next_line(true)?; + self.text("}")?; } else { panic!( "Cannot print empty selections. Please, check transforms that may produce invalid selections." @@ -252,23 +256,12 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { conditions: Option>, ) -> FmtResult { match selection { - Selection::ScalarField(field) => { - self.print_scalar_field(field, conditions)?; - } - Selection::LinkedField(field) => { - self.print_linked_field(field, conditions)?; - } - Selection::FragmentSpread(field) => { - self.print_fragment_spread(field, conditions)?; - } - Selection::InlineFragment(field) => { - self.print_inline_fragment(field, conditions)?; - } - Selection::Condition(field) => { - self.print_condition(field)?; - } + Selection::ScalarField(field) => self.print_scalar_field(field, conditions), + Selection::LinkedField(field) => self.print_linked_field(field, conditions), + Selection::FragmentSpread(field) => self.print_fragment_spread(field, conditions), + Selection::InlineFragment(field) => self.print_inline_fragment(field, conditions), + Selection::Condition(field) => self.print_condition(field), } - Ok(()) } fn print_scalar_field( @@ -304,7 +297,8 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { write!(self.writer, "...{}", fragment_name)?; self.print_directives(&field.directives, conditions, None)?; if !field.arguments.is_empty() { - write!(self.writer, " @arguments")?; + self.space(true)?; + self.text("@arguments")?; self.print_arguments(&field.arguments) } else { Ok(()) @@ -316,13 +310,10 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { field: &InlineFragment, conditions: Option>, ) -> FmtResult { - write!(self.writer, "...")?; + self.text("...")?; if let Some(type_condition) = field.type_condition { - write!( - self.writer, - " on {}", - self.schema.get_type_name(type_condition).lookup(), - )?; + self.space(true)?; + self.print_type_condition(type_condition)?; }; self.print_directives(&field.directives, conditions, None)?; self.print_selections(&field.selections) @@ -342,7 +333,7 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if is_first_selection { is_first_selection = false; } else { - self.next_line()?; + self.next_line(false)?; } self.print_selection(selection, Some(accum_conditions.iter().rev().collect()))?; maybe_current_condition = None; @@ -372,16 +363,17 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { } fn print_directive(&mut self, directive: &Directive) -> FmtResult { - write!(self.writer, " @{}", directive.name.item)?; + self.space(true)?; + write!(self.writer, "@{}", directive.name.item)?; self.print_arguments(&directive.arguments)?; if self.options.debug_directive_data { if let Some(data) = &directive.data { for debug_line in format!("{:#?}", data).lines() { - self.next_line()?; + self.next_line(false)?; write!(self.writer, "# {}", debug_line)?; } - self.next_line()?; + self.next_line(false)?; } } @@ -390,23 +382,23 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { fn print_condition_directives(&mut self, conditions: Vec<&Condition>) -> FmtResult { for condition in conditions { + self.space(true)?; write!( self.writer, - " @{}", + "@{}", if condition.passing_value { "include" } else { "skip" } )?; + self.text("(if")?; + self.colon_separator()?; match &condition.value { - ConditionValue::Constant(value) => { - write!(self.writer, "(if: {})", value)?; - } - ConditionValue::Variable(variable) => { - write!(self.writer, "(if: ${})", variable.name.item)?; - } - } + ConditionValue::Constant(value) => write!(self.writer, "{}", value), + ConditionValue::Variable(variable) => self.print_variable(&variable.name.item), + }?; + self.text(")")?; } Ok(()) } @@ -416,25 +408,19 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { variable_definitions: &[VariableDefinition], ) -> FmtResult { if !variable_definitions.is_empty() { - write!(self.writer, "(")?; + self.text("(")?; self.indentation += 1; - for var_def in variable_definitions.iter() { - self.next_line()?; - let type_name = self.schema.get_type_string(&var_def.type_); - write!(self.writer, "${}: {}", var_def.name.item, type_name)?; - - match &var_def.default_value { - None => {} - Some(default_value) => { - write!(self.writer, " = ")?; - self.print_constant_value(&default_value.item)?; - } + for (i, var_def) in variable_definitions.iter().enumerate() { + if i == 0 { + self.next_line(true)?; + } else { + self.item_separator()?; } - - self.print_directives(&var_def.directives, None, None)?; + self.print_variable_definition(var_def)?; } self.indentation -= 1; - write!(self.writer, "\n)")?; + self.next_line(true)?; + self.text(")")?; } Ok(()) } @@ -444,25 +430,33 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { argument_definitions: &[VariableDefinition], ) -> FmtResult { if !argument_definitions.is_empty() { - write!(self.writer, " @argumentDefinitions(")?; + self.space(true)?; + self.text("@argumentDefinitions(")?; self.indentation += 1; - for arg_def in argument_definitions.iter() { - self.next_line()?; - let type_name = self.schema.get_type_string(&arg_def.type_); - write!( - self.writer, - "{}: {{type: \"{}\"", - arg_def.name.item, type_name - )?; - + for (i, arg_def) in argument_definitions.iter().enumerate() { + if i == 0 { + self.next_line(true)?; + } else { + self.item_separator()?; + } + write!(self.writer, "{}", arg_def.name.item)?; + self.colon_separator()?; + self.text("{type")?; + self.colon_separator()?; + self.text("\"")?; + self.print_type(&arg_def.type_)?; + self.text("\"")?; if let Some(default_value) = &arg_def.default_value { - write!(self.writer, ", defaultValue: ")?; + self.comma_separator()?; + self.text("defaultValue")?; + self.colon_separator()?; self.print_constant_value(&default_value.item)?; } - write!(self.writer, "}}")?; + self.text("}")?; } self.indentation -= 1; - write!(self.writer, "\n)")?; + self.next_line(true)?; + self.text(")")?; } Ok(()) } @@ -471,7 +465,6 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if arguments.is_empty() { Ok(()) } else { - write!(self.writer, "(")?; let sorted_arguments = if self.options.sort_keys { let mut sorted_arguments = arguments.to_vec(); sorted_arguments.sort_by_key(|arg| arg.name()); @@ -482,31 +475,24 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { let maybe_sorted_arguments = sorted_arguments .as_ref() .map_or(arguments, |v| v.as_slice()); - for (i, argument) in maybe_sorted_arguments.iter().enumerate() { - write!(self.writer, "{}:", argument.name.item)?; - if !self.options.compact { - write!(self.writer, " ")?; - } - self.print_value(&argument.value.item)?; + self.text("(")?; + for (i, argument) in maybe_sorted_arguments.iter().enumerate() { + self.print_argument(argument)?; if i != arguments.len() - 1 { - write!(self.writer, ",")?; - if !self.options.compact { - write!(self.writer, " ")?; - } + self.comma_separator()?; } } - write!(self.writer, ")")?; - Ok(()) + self.text(")") } } fn print_value(&mut self, val: &Value) -> FmtResult { match val { Value::Constant(constant_val) => self.print_constant_value(constant_val), - Value::Variable(variable_val) => write!(self.writer, "${}", variable_val.name.item), + Value::Variable(variable_val) => self.print_variable(&variable_val.name.item), Value::Object(object) => { - write!(self.writer, "{{")?; + self.text("{")?; let mut first = true; let sorted_object = if self.options.sort_keys { let mut maybe_sorted_object = object.clone(); @@ -525,19 +511,11 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if first { first = false; } else { - write!(self.writer, ",")?; - if !self.options.compact { - write!(self.writer, " ")?; - } + self.comma_separator()?; } - write!(self.writer, "{}:", arg.name.item)?; - if !self.options.compact { - write!(self.writer, " ")?; - } - self.print_value(&arg.value.item)?; + self.print_argument(arg)?; } - write!(self.writer, "}}")?; - Ok(()) + self.text("}") } Value::List(list) => { write!(self.writer, "[")?; @@ -549,15 +527,11 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if first { first = false; } else { - write!(self.writer, ",")?; - if !self.options.compact { - write!(self.writer, " ")?; - } + self.comma_separator()?; } self.print_value(value)?; } - write!(self.writer, "]")?; - Ok(()) + write!(self.writer, "]") } } } @@ -577,7 +551,7 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { } } ConstantValue::Object(object) => { - write!(self.writer, "{{")?; + self.text("{")?; let mut first = true; let sorted_object = if self.options.sort_keys { let mut maybe_sorted_object = object.clone(); @@ -593,23 +567,11 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if first { first = false; } else { - write!(self.writer, ",")?; - if !self.options.compact { - write!(self.writer, " ")?; - } - } - if self.options.json_format { - write!(self.writer, "\"{}\":", arg.name.item)?; - } else { - write!(self.writer, "{}:", arg.name.item)?; - } - if !self.options.compact { - write!(self.writer, " ")?; + self.comma_separator()?; } - self.print_constant_value(&arg.value.item)?; + self.print_object_field(arg)?; } - write!(self.writer, "}}")?; - Ok(()) + self.text("}") } ConstantValue::List(list) => { write!(self.writer, "[")?; @@ -618,15 +580,11 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { if first { first = false; } else { - write!(self.writer, ",")?; - if !self.options.compact { - write!(self.writer, " ")?; - } + self.comma_separator()?; } self.print_constant_value(value)?; } - write!(self.writer, "]")?; - Ok(()) + write!(self.writer, "]") } } } @@ -638,17 +596,99 @@ impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> { ) -> FmtResult { if let Some(alias) = alias { if alias.item != name { - write!(self.writer, "{}: ", alias.item)?; + write!(self.writer, "{}", alias.item)?; + self.colon_separator()?; } } write!(self.writer, "{}", name) } - fn next_line(&mut self) -> FmtResult { + fn print_argument(&mut self, argument: &Argument) -> FmtResult { + write!(self.writer, "{}", argument.name.item)?; + self.colon_separator()?; + self.print_value(&argument.value.item) + } + + fn print_type_condition(&mut self, type_condition: Type) -> FmtResult { + self.text("on")?; + self.space(false)?; + write!(self.writer, "{}", self.schema.get_type_name(type_condition)) + } + + fn print_variable_definition(&mut self, var_def: &VariableDefinition) -> FmtResult { + self.print_variable(&var_def.name.item)?; + self.colon_separator()?; + self.print_type(&var_def.type_)?; + + if let Some(default_value) = &var_def.default_value { + self.print_default_value(&default_value.item)?; + } + + self.print_directives(&var_def.directives, None, None) + } + + fn print_object_field(&mut self, arg: &ConstantArgument) -> FmtResult { + if self.options.json_format { + write!(self.writer, "\"{}\"", arg.name.item)?; + } else { + write!(self.writer, "{}", arg.name.item)?; + } + self.colon_separator()?; + self.print_constant_value(&arg.value.item) + } + + fn print_variable(&mut self, variable: &StringKey) -> FmtResult { + write!(self.writer, "${}", variable) + } + + fn print_default_value(&mut self, value: &ConstantValue) -> FmtResult { + self.space(true)?; + self.text("=")?; + self.space(true)?; + self.print_constant_value(&value) + } + + fn print_type(&mut self, type_: &TypeReference) -> FmtResult { + write!(self.writer, "{}", self.schema.get_type_string(&type_)) + } + + fn next_line(&mut self, can_collapse: bool) -> FmtResult { + if self.options.compact && can_collapse { + return Ok(()); + } writeln!(self.writer)?; for _ in 0..self.indentation { write!(self.writer, " ")?; } Ok(()) } + + fn text(&mut self, text: &str) -> FmtResult { + write!(self.writer, "{}", text) + } + + fn space(&mut self, can_collapse: bool) -> FmtResult { + if self.options.compact && can_collapse { + return Ok(()); + } + write!(self.writer, " ") + } + + fn comma_separator(&mut self) -> FmtResult { + self.text(",")?; + self.space(true) + } + + fn colon_separator(&mut self) -> FmtResult { + self.text(":")?; + self.space(true) + } + + fn item_separator(&mut self) -> FmtResult { + if self.options.compact { + write!(self.writer, ",") + } else { + self.next_line(false) + } + } } diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.expected new file mode 100644 index 0000000000000..ff25b51a9187c --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.expected @@ -0,0 +1,23 @@ +==================================== INPUT ==================================== +query MyQuery($id: ID, $cond: Boolean!) { + my_alias: node(id: $id) { + id + ... on User @include(if: $cond) { + name + } + ...UserFragment @include(if: $cond) + } +} + +fragment UserFragment on User { + id + name @include(if: $cond) + otherName: name @customDirective(level: 3) @skip(if: $cond) + address @skip(if: true) { + city + } +} +==================================== OUTPUT =================================== +query MyQuery($id:ID,$cond:Boolean!){my_alias:node(id:$id){id,...on User@include(if:$cond){name},...UserFragment@include(if:$cond)}} + +fragment UserFragment on User{id,name@include(if:$cond),otherName:name@skip(if:$cond)@customDirective(level:3),address@skip(if:true){city}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.graphql new file mode 100644 index 0000000000000..0cc0451e7b34f --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_directives.graphql @@ -0,0 +1,18 @@ +query MyQuery($id: ID, $cond: Boolean!) { + my_alias: node(id: $id) { + id + ... on User @include(if: $cond) { + name + } + ...UserFragment @include(if: $cond) + } +} + +fragment UserFragment on User { + id + name @include(if: $cond) + otherName: name @customDirective(level: 3) @skip(if: $cond) + address @skip(if: true) { + city + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.expected new file mode 100644 index 0000000000000..38254ef3e34a1 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.expected @@ -0,0 +1,14 @@ +==================================== INPUT ==================================== +query MyQuery($id: ID) { + my_alias: node(id: $id) { + id + ... on User { + name + likers(first: 5) { + count + } + } + } +} +==================================== OUTPUT =================================== +query MyQuery($id:ID){my_alias:node(id:$id){id,...on User{name,likers(first:5){count}}}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.graphql new file mode 100644 index 0000000000000..12f6b9f3b6d70 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_query.graphql @@ -0,0 +1,11 @@ +query MyQuery($id: ID) { + my_alias: node(id: $id) { + id + ... on User { + name + likers(first: 5) { + count + } + } + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.expected new file mode 100644 index 0000000000000..7b9c7d1286d6d --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.expected @@ -0,0 +1,17 @@ +==================================== INPUT ==================================== +query MyQuery($id: ID, $count: Int! = 5, $envs: [Environment!]! = [WEB]) { + my_alias: node(id: $id) { + id + ... on User { + name + likers(first: $count) { + count + } + checkins(environments: $envs) { + query + } + } + } +} +==================================== OUTPUT =================================== +query MyQuery($id:ID,$count:Int!=5,$envs:[Environment!]!=[WEB]){my_alias:node(id:$id){id,...on User{name,likers(first:$count){count},checkins(environments:$envs){query}}}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.graphql new file mode 100644 index 0000000000000..0e9dfbba909d1 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/basic_var_defs.graphql @@ -0,0 +1,14 @@ +query MyQuery($id: ID, $count: Int! = 5, $envs: [Environment!]! = [WEB]) { + my_alias: node(id: $id) { + id + ... on User { + name + likers(first: $count) { + count + } + checkins(environments: $envs) { + query + } + } + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.expected new file mode 100644 index 0000000000000..2fd2de38a17e4 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.expected @@ -0,0 +1,19 @@ +==================================== INPUT ==================================== +query Test { + #comments go away + aliasOfFoo : username(name : "val1" ) @customDirective(level: 2) { # and this comment as well + emailAddresses + firstName(if: false, unless: false) + } + ...FX +} + +fragment FX on Query { + aliased : username(name : "argVal") { + thin: emailAddresses + } +} +==================================== OUTPUT =================================== +query Test{aliasOfFoo:username(name:"val1")@customDirective(level:2){emailAddresses,firstName(if:false,unless:false)},...FX} + +fragment FX on Query{aliased:username(name:"argVal"){thin:emailAddresses}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.graphql new file mode 100644 index 0000000000000..92e893b7905ae --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/compact_test.graphql @@ -0,0 +1,14 @@ +query Test { + #comments go away + aliasOfFoo : username(name : "val1" ) @customDirective(level: 2) { # and this comment as well + emailAddresses + firstName(if: false, unless: false) + } + ...FX +} + +fragment FX on Query { + aliased : username(name : "argVal") { + thin: emailAddresses + } +} \ No newline at end of file diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.expected new file mode 100644 index 0000000000000..4fd4224e3eaa8 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.expected @@ -0,0 +1,11 @@ +==================================== INPUT ==================================== +query EmptyArgs { + route(waypoints: []) { + __typename + } + items(filter: {}) { + __typename + } +} +==================================== OUTPUT =================================== +query EmptyArgs{route(waypoints:[]){__typename},items(filter:{}){__typename}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.graphql new file mode 100644 index 0000000000000..9c92aec663e24 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/empty_args.graphql @@ -0,0 +1,8 @@ +query EmptyArgs { + route(waypoints: []) { + __typename + } + items(filter: {}) { + __typename + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.expected new file mode 100644 index 0000000000000..f2319d0bdee08 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.expected @@ -0,0 +1,81 @@ +==================================== INPUT ==================================== +query NodeQuery( + $cond: Boolean! = false + $id: ID! + $size: [Int] = [32] + $query: CheckinSearchInput! +) { + node(id: $id) { + id + ... on User @include(if: $cond) { + name + } + ...UserFragment @include(if: $cond) @arguments(size: $size) + } + checkinSearchQuery(query: $query) { + query + } +} + +fragment UserFragment on User + @argumentDefinitions( + after: {type: "ID"} + first: {type: "Int", defaultValue: 5} + size: {type: "[Int]"} + storyType: {type: "StoryType", defaultValue: DIRECTED} + # storyType_invalid_string: {type: "StoryType", defaultValue: "DIRECTED"} + # storyType_invalid_lowercase: {type: "StoryType", defaultValue: directed} + ) { + id + __typename + checkins(environments: [WEB]) { + __typename + } + nakedEnum: checkins(environments: WEB) { + __typename + } + friends(after: $after, first: $first, traits: [HELPFUL]) { + count + } + secondFriends: friends(first: 10) { + count + } + name @include(if: $cond) + otherName: name @customDirective(level: 3) + thumbnail: profilePicture2( + size: 32 + cropPosition: CENTER + fileExtension: PNG + # TODO add support for custom scalars + # additionalParameters: {filter: "Boston"} + options: {newName: null} + ) { + height + width + src: uri + } + profilePicture(size: $size) @include(if: $cond) @skip(if: $foo) { + height + width + src: uri + } + storySearch(query: {type: DIRECTED}) { + id + } + ... @include(if: $cond) @skip(if: $foo) { + address { + city + } + alternate_name + } + + ... @include(if: $cond) { + address { + city + } + } +} +==================================== OUTPUT =================================== +query NodeQuery($cond:Boolean!=false,$id:ID!,$size:[Int]=[32],$query:CheckinSearchInput!){node(id:$id){id,...on User@include(if:$cond){name},...UserFragment@include(if:$cond)@arguments(size:$size)},checkinSearchQuery(query:$query){query}} + +fragment UserFragment on User@argumentDefinitions(after:{type:"ID"},first:{type:"Int",defaultValue:5},size:{type:"[Int]"},storyType:{type:"StoryType",defaultValue:DIRECTED}){id,__typename,checkins(environments:[WEB]){__typename},nakedEnum:checkins(environments:WEB){__typename},friends(after:$after,first:$first,traits:[HELPFUL]){count},secondFriends:friends(first:10){count},name@include(if:$cond),otherName:name@customDirective(level:3),thumbnail:profilePicture2(size:32,cropPosition:CENTER,fileExtension:PNG,options:{newName:null}){height,width,src:uri},profilePicture(size:$size)@include(if:$cond)@skip(if:$foo){height,width,src:uri},storySearch(query:{type:DIRECTED}){id},...@include(if:$cond)@skip(if:$foo){address{city},alternate_name},...@include(if:$cond){address{city}}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.graphql new file mode 100644 index 0000000000000..3adfe1c5eabdb --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/kitchen-sink.graphql @@ -0,0 +1,76 @@ +query NodeQuery( + $cond: Boolean! = false + $id: ID! + $size: [Int] = [32] + $query: CheckinSearchInput! +) { + node(id: $id) { + id + ... on User @include(if: $cond) { + name + } + ...UserFragment @include(if: $cond) @arguments(size: $size) + } + checkinSearchQuery(query: $query) { + query + } +} + +fragment UserFragment on User + @argumentDefinitions( + after: {type: "ID"} + first: {type: "Int", defaultValue: 5} + size: {type: "[Int]"} + storyType: {type: "StoryType", defaultValue: DIRECTED} + # storyType_invalid_string: {type: "StoryType", defaultValue: "DIRECTED"} + # storyType_invalid_lowercase: {type: "StoryType", defaultValue: directed} + ) { + id + __typename + checkins(environments: [WEB]) { + __typename + } + nakedEnum: checkins(environments: WEB) { + __typename + } + friends(after: $after, first: $first, traits: [HELPFUL]) { + count + } + secondFriends: friends(first: 10) { + count + } + name @include(if: $cond) + otherName: name @customDirective(level: 3) + thumbnail: profilePicture2( + size: 32 + cropPosition: CENTER + fileExtension: PNG + # TODO add support for custom scalars + # additionalParameters: {filter: "Boston"} + options: {newName: null} + ) { + height + width + src: uri + } + profilePicture(size: $size) @include(if: $cond) @skip(if: $foo) { + height + width + src: uri + } + storySearch(query: {type: DIRECTED}) { + id + } + ... @include(if: $cond) @skip(if: $foo) { + address { + city + } + alternate_name + } + + ... @include(if: $cond) { + address { + city + } + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.expected b/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.expected new file mode 100644 index 0000000000000..08905768f58c8 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.expected @@ -0,0 +1,11 @@ +==================================== INPUT ==================================== +query SingleValueArrayQuery { + route(waypoints: {lat: "123", lon: "456"}) { + steps { + lat + lon + } + } +} +==================================== OUTPUT =================================== +query SingleValueArrayQuery{route(waypoints:{lat:"123",lon:"456"}){steps{lat,lon}}} diff --git a/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.graphql b/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.graphql new file mode 100644 index 0000000000000..2ef9bcc746dfd --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/fixtures/single-value-array-of-objects.graphql @@ -0,0 +1,8 @@ +query SingleValueArrayQuery { + route(waypoints: {lat: "123", lon: "456"}) { + steps { + lat + lon + } + } +} diff --git a/compiler/crates/graphql-text-printer/tests/compact/mod.rs b/compiler/crates/graphql-text-printer/tests/compact/mod.rs new file mode 100644 index 0000000000000..c58485de49d02 --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact/mod.rs @@ -0,0 +1,49 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +use common::SourceLocationKey; +use fixture_tests::Fixture; +use graphql_ir::{ + build, node_identifier::LocationAgnosticPartialEq, ExecutableDefinition, Program, +}; +use graphql_syntax::parse_executable; +use graphql_text_printer::{print_full_operation, PrinterOptions}; +use relay_test_schema::TEST_SCHEMA; +use relay_transforms::RelayLocationAgnosticBehavior; +use std::sync::Arc; + +pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { + let source_location = SourceLocationKey::standalone(fixture.file_name); + let initial_ast = parse_executable(fixture.content, source_location).unwrap(); + let initial_ir = build(&TEST_SCHEMA, &initial_ast.definitions).unwrap(); + let initial_ir_copy = initial_ir.clone(); + let program = Program::from_definitions(Arc::clone(&TEST_SCHEMA), initial_ir.clone()); + let options = PrinterOptions { + compact: true, + ..Default::default() + }; + + // Print the IR into a GraphQL string for the fixture + let output = initial_ir + .into_iter() + .filter_map(|definition| match definition { + ExecutableDefinition::Operation(operation) => Some(operation), + _ => None, + }) + .map(|operation| print_full_operation(&program, &operation, options)) + .collect::>() + .join("\n\n"); + + // Roundtrip the output back into an IR + let roundtrip_ast = parse_executable(output.as_str(), SourceLocationKey::Generated).unwrap(); + let roundtrip_ir = build(&TEST_SCHEMA, &roundtrip_ast.definitions).unwrap(); + + // Check the roundtripped IR matches the initial IR to ensure we printed a valid schema + assert!(roundtrip_ir.location_agnostic_eq::(&initial_ir_copy)); + + Ok(output) +} diff --git a/compiler/crates/graphql-text-printer/tests/compact_test.rs b/compiler/crates/graphql-text-printer/tests/compact_test.rs new file mode 100644 index 0000000000000..e60d3899e0a4f --- /dev/null +++ b/compiler/crates/graphql-text-printer/tests/compact_test.rs @@ -0,0 +1,63 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + */ + +mod compact; + +use compact::transform_fixture; +use fixture_tests::test_fixture; + + +#[test] +fn compact_test() { + let input = include_str!("compact/fixtures/compact_test.graphql"); + let expected = include_str!("compact/fixtures/compact_test.expected"); + test_fixture(transform_fixture, "compact_test.graphql", "compact/fixtures/compact_test.expected", input, expected); +} + +#[test] +fn compact_basic_directives() { + let input = include_str!("compact/fixtures/basic_directives.graphql"); + let expected = include_str!("compact/fixtures/basic_directives.expected"); + test_fixture(transform_fixture, "basic_directives.graphql", "compact/fixtures/basic_directives.expected", input, expected); +} + +#[test] +fn compact_basic_query() { + let input = include_str!("compact/fixtures/basic_query.graphql"); + let expected = include_str!("compact/fixtures/basic_query.expected"); + test_fixture(transform_fixture, "basic_query.graphql", "compact/fixtures/basic_query.expected", input, expected); +} + +#[test] +fn compact_basic_var_defs() { + let input = include_str!("compact/fixtures/basic_var_defs.graphql"); + let expected = include_str!("compact/fixtures/basic_var_defs.expected"); + test_fixture(transform_fixture, "basic_var_defs.graphql", "compact/fixtures/basic_var_defs.expected", input, expected); +} + +#[test] +fn compact_empty_args() { + let input = include_str!("compact/fixtures/empty_args.graphql"); + let expected = include_str!("compact/fixtures/empty_args.expected"); + test_fixture(transform_fixture, "empty_args.graphql", "compact/fixtures/empty_args.expected", input, expected); +} + +#[test] +fn compact_kitchen_sink() { + let input = include_str!("compact/fixtures/kitchen-sink.graphql"); + let expected = include_str!("compact/fixtures/kitchen-sink.expected"); + test_fixture(transform_fixture, "kitchen-sink.graphql", "compact/fixtures/kitchen-sink.expected", input, expected); +} + +#[test] +fn compact_single_value_array_of_objects() { + let input = include_str!("compact/fixtures/single-value-array-of-objects.graphql"); + let expected = include_str!("compact/fixtures/single-value-array-of-objects.expected"); + test_fixture(transform_fixture, "single-value-array-of-objects.graphql", "compact/fixtures/single-value-array-of-objects.expected", input, expected); +} diff --git a/compiler/crates/graphql-text-printer/tests/operation_printer/mod.rs b/compiler/crates/graphql-text-printer/tests/operation_printer/mod.rs index 6535c3d7e05de..6c4aec13a0b98 100644 --- a/compiler/crates/graphql-text-printer/tests/operation_printer/mod.rs +++ b/compiler/crates/graphql-text-printer/tests/operation_printer/mod.rs @@ -25,7 +25,11 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { .into_iter() .filter_map(|definition| { if let ExecutableDefinition::Operation(operation) = definition { - Some(print_full_operation(&program, &operation)) + Some(print_full_operation( + &program, + &operation, + Default::default(), + )) } else { None } diff --git a/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs b/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs index 38f365791104e..107f0094dba63 100644 --- a/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs +++ b/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs @@ -11,7 +11,7 @@ use crate::config::{Config, ProjectConfig}; use common::{NamedItem, SourceLocationKey}; use fnv::FnvHashMap; use graphql_ir::{FragmentDefinition, OperationDefinition}; -use graphql_text_printer::OperationPrinter; +use graphql_text_printer::{OperationPrinter, PrinterOptions}; use intern::string_key::StringKey; use relay_transforms::{ ClientEdgeGeneratedQueryMetadataDirective, Programs, RefetchableDerivedFromMetadata, @@ -37,7 +37,14 @@ pub fn generate_artifacts( programs: &Programs, source_hashes: Arc, ) -> Vec { - let mut operation_printer = OperationPrinter::new(&programs.operation_text); + let printer_options = PrinterOptions { + compact: project_config + .feature_flags + .compact_query_text + .is_fully_enabled(), + ..Default::default() + }; + let mut operation_printer = OperationPrinter::new(&programs.operation_text, printer_options); return group_operations(programs) .into_iter() .map(|(_, operations)| -> Artifact { diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs index b5a330ea46789..bf8cd2d22ce69 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs @@ -97,6 +97,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { enable_client_edges: FeatureFlag::Enabled, skip_printing_nulls: FeatureFlag::Disabled, enable_fragment_aliases: FeatureFlag::Enabled, + compact_query_text: FeatureFlag::Disabled, }; let default_project_config = ProjectConfig { @@ -191,7 +192,11 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { let text = print_operation_node.map_or_else( || "Query Text is Empty.".to_string(), |print_operation_node| { - print_full_operation(&programs.operation_text, print_operation_node) + print_full_operation( + &programs.operation_text, + print_operation_node, + Default::default(), + ) }, ); diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs index 8a64618e15928..38842c9beed11 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs @@ -74,6 +74,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { enable_client_edges: FeatureFlag::Enabled, skip_printing_nulls: FeatureFlag::Disabled, enable_fragment_aliases: FeatureFlag::Enabled, + compact_query_text: FeatureFlag::Disabled, }; let project_config = ProjectConfig { @@ -122,7 +123,11 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { let text = print_operation_node.map_or_else( || "Query Text is Empty.".to_string(), |print_operation_node| { - print_full_operation(&programs.operation_text, print_operation_node) + print_full_operation( + &programs.operation_text, + print_operation_node, + Default::default(), + ) }, ); diff --git a/compiler/crates/relay-lsp/src/graphql_tools/mod.rs b/compiler/crates/relay-lsp/src/graphql_tools/mod.rs index 72acbb29b28c2..61fe043e37f75 100644 --- a/compiler/crates/relay-lsp/src/graphql_tools/mod.rs +++ b/compiler/crates/relay-lsp/src/graphql_tools/mod.rs @@ -145,6 +145,7 @@ fn print_full_operation_text(programs: Programs, operation_name: StringKey) -> O Some(print_full_operation( &programs.operation_text, print_operation_node, + Default::default(), )) }