From 97221cbabef26c30b872ecb34d3660ee17c42169 Mon Sep 17 00:00:00 2001 From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:48:07 +0200 Subject: [PATCH] Add feature flag to allow opt-out --- compiler/crates/common/src/feature_flags.rs | 6 + .../relay-compiler-config-schema.json | 261 ++++++++++++++++++ compiler/crates/relay-typegen/src/visit.rs | 34 ++- compiler/crates/relay-typegen/src/write.rs | 4 + 4 files changed, 301 insertions(+), 4 deletions(-) diff --git a/compiler/crates/common/src/feature_flags.rs b/compiler/crates/common/src/feature_flags.rs index d0b946e300cf1..b7502c5918000 100644 --- a/compiler/crates/common/src/feature_flags.rs +++ b/compiler/crates/common/src/feature_flags.rs @@ -134,9 +134,15 @@ pub struct FeatureFlags { /// This flag will be removed in a future version of Relay. #[serde(default)] pub disable_full_argument_type_validation: FeatureFlag, + /// Enable a custom path for artifacts #[serde(default)] pub enable_custom_artifacts_path: FeatureFlag, + + /// Disable the generation of a more precise raw response type + /// for selections on abstract types. + #[serde(default)] + pub disable_more_precise_abstract_selection_raw_response_type: FeatureFlag, } #[derive(Debug, Deserialize, Clone, Serialize, Default, JsonSchema)] diff --git a/compiler/crates/relay-compiler/relay-compiler-config-schema.json b/compiler/crates/relay-compiler/relay-compiler-config-schema.json index 413cbdf141578..954f7ab50116e 100644 --- a/compiler/crates/relay-compiler/relay-compiler-config-schema.json +++ b/compiler/crates/relay-compiler/relay-compiler-config-schema.json @@ -712,6 +712,92 @@ } ] }, + "disable_more_precise_abstract_selection_raw_response_type": { + "description": "Disable the generation of a more precise raw response type for selections on abstract types.", + "default": { + "kind": "disabled" + }, + "oneOf": [ + { + "description": "Fully disabled: developers may not use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "disabled" + ] + } + } + }, + { + "description": "Fully enabled: developers may use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "enabled" + ] + } + } + }, + { + "description": "Partially enabled: developers may only use this feature on the listed items (fragments, fields, types).", + "type": "object", + "required": [ + "allowlist", + "kind" + ], + "properties": { + "allowlist": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "kind": { + "type": "string", + "enum": [ + "limited" + ] + } + } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rollout" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", + "type": [ + "integer", + "null" + ], + "format": "uint8", + "minimum": 0.0 + } + } + } + ] + }, "disable_resolver_reader_ast": { "description": "Mirror of `enable_resolver_normalization_ast` excludes resolver metadata from reader ast", "default": false, @@ -1808,6 +1894,9 @@ "disable_full_argument_type_validation": { "kind": "disabled" }, + "disable_more_precise_abstract_selection_raw_response_type": { + "kind": "disabled" + }, "disable_resolver_reader_ast": false, "disable_schema_validation": false, "enable_3d_branch_arg_generation": false, @@ -2440,6 +2529,92 @@ } ] }, + "disable_more_precise_abstract_selection_raw_response_type": { + "description": "Disable the generation of a more precise raw response type for selections on abstract types.", + "default": { + "kind": "disabled" + }, + "oneOf": [ + { + "description": "Fully disabled: developers may not use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "disabled" + ] + } + } + }, + { + "description": "Fully enabled: developers may use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "enabled" + ] + } + } + }, + { + "description": "Partially enabled: developers may only use this feature on the listed items (fragments, fields, types).", + "type": "object", + "required": [ + "allowlist", + "kind" + ], + "properties": { + "allowlist": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "kind": { + "type": "string", + "enum": [ + "limited" + ] + } + } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rollout" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", + "type": [ + "integer", + "null" + ], + "format": "uint8", + "minimum": 0.0 + } + } + } + ] + }, "disable_resolver_reader_ast": { "description": "Mirror of `enable_resolver_normalization_ast` excludes resolver metadata from reader ast", "default": false, @@ -3821,6 +3996,92 @@ } ] }, + "disable_more_precise_abstract_selection_raw_response_type": { + "description": "Disable the generation of a more precise raw response type for selections on abstract types.", + "default": { + "kind": "disabled" + }, + "oneOf": [ + { + "description": "Fully disabled: developers may not use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "disabled" + ] + } + } + }, + { + "description": "Fully enabled: developers may use this feature", + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "enabled" + ] + } + } + }, + { + "description": "Partially enabled: developers may only use this feature on the listed items (fragments, fields, types).", + "type": "object", + "required": [ + "allowlist", + "kind" + ], + "properties": { + "allowlist": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "kind": { + "type": "string", + "enum": [ + "limited" + ] + } + } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rollout" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", + "type": [ + "integer", + "null" + ], + "format": "uint8", + "minimum": 0.0 + } + } + } + ] + }, "disable_resolver_reader_ast": { "description": "Mirror of `enable_resolver_normalization_ast` excludes resolver metadata from reader ast", "default": false, diff --git a/compiler/crates/relay-typegen/src/visit.rs b/compiler/crates/relay-typegen/src/visit.rs index 3f79da254a4d7..7e8ff9a42e597 100644 --- a/compiler/crates/relay-typegen/src/visit.rs +++ b/compiler/crates/relay-typegen/src/visit.rs @@ -30,6 +30,7 @@ use graphql_ir::FragmentSpread; use graphql_ir::InlineFragment; use graphql_ir::LinkedField; use graphql_ir::OperationDefinition; +use graphql_ir::OperationDefinitionName; use graphql_ir::ScalarField; use graphql_ir::Selection; use indexmap::map::Entry; @@ -1103,6 +1104,7 @@ fn visit_actor_change( #[allow(clippy::too_many_arguments)] fn raw_response_visit_inline_fragment( typegen_context: &'_ TypegenContext<'_>, + operation_name: OperationDefinitionName, type_selections: &mut Vec, inline_fragment: &InlineFragment, encountered_enums: &mut EncounteredEnums, @@ -1116,6 +1118,7 @@ fn raw_response_visit_inline_fragment( ) { let mut selections = raw_response_visit_selections( typegen_context, + operation_name, &inline_fragment.selections, encountered_enums, match_fields, @@ -1141,6 +1144,7 @@ fn raw_response_visit_inline_fragment( if !match_fields.0.contains_key(&fragment_name.0) { let match_field = raw_response_selections_to_babel( typegen_context, + operation_name, selections.iter().filter(|sel| !sel.is_js_field()).cloned(), None, encountered_enums, @@ -1641,6 +1645,7 @@ fn should_emit_discriminated_union( pub(crate) fn raw_response_selections_to_babel( typegen_context: &'_ TypegenContext<'_>, + operation_name: OperationDefinitionName, selections: impl Iterator, concrete_type: Option, encountered_enums: &mut EncounteredEnums, @@ -1658,10 +1663,19 @@ pub(crate) fn raw_response_selections_to_babel( .or_default() .push(selection); } else if let Some(abstract_type) = selection.get_enclosing_abstract_type() { - by_abstract_type - .entry(abstract_type) - .or_default() - .push(selection); + if typegen_context + .project_config + .feature_flags + .disable_more_precise_abstract_selection_raw_response_type + .is_enabled_for(operation_name.0) + { + base_fields.push(selection); + } else { + by_abstract_type + .entry(abstract_type) + .or_default() + .push(selection); + } } else { base_fields.push(selection); } @@ -1716,6 +1730,7 @@ pub(crate) fn raw_response_selections_to_babel( .map(|selection| { raw_response_make_prop( typegen_context, + operation_name, selection, Some(concrete_type), encountered_enums, @@ -1727,6 +1742,7 @@ pub(crate) fn raw_response_selections_to_babel( ))); append_local_3d_payload( typegen_context, + operation_name, &mut types, &merged_selections, Some(concrete_type), @@ -1777,6 +1793,7 @@ pub(crate) fn raw_response_selections_to_babel( .map(|selection| { raw_response_make_prop( typegen_context, + operation_name, selection, concrete_type, encountered_enums, @@ -1788,6 +1805,7 @@ pub(crate) fn raw_response_selections_to_babel( ))); append_local_3d_payload( typegen_context, + operation_name, &mut types, &base_fields, concrete_type, @@ -1802,6 +1820,7 @@ pub(crate) fn raw_response_selections_to_babel( fn append_local_3d_payload( typegen_context: &'_ TypegenContext<'_>, + operation_name: OperationDefinitionName, types: &mut Vec, type_selections: &[TypeSelection], concrete_type: Option, @@ -1827,6 +1846,7 @@ fn append_local_3d_payload( .map(|sel| { raw_response_make_prop( typegen_context, + operation_name, sel.clone(), concrete_type, encountered_enums, @@ -2098,6 +2118,7 @@ fn make_prop( fn raw_response_make_prop( typegen_context: &'_ TypegenContext<'_>, + operation_name: OperationDefinitionName, type_selection: TypeSelection, concrete_type: Option, encountered_enums: &mut EncounteredEnums, @@ -2124,6 +2145,7 @@ fn raw_response_make_prop( }; let object_props = raw_response_selections_to_babel( typegen_context, + operation_name, hashmap_into_values(linked_field.node_selections), inner_concrete_type, encountered_enums, @@ -2301,6 +2323,7 @@ fn transform_graphql_enum_type( #[allow(clippy::too_many_arguments)] pub(crate) fn raw_response_visit_selections( typegen_context: &'_ TypegenContext<'_>, + operation_name: OperationDefinitionName, selections: &[Selection], encountered_enums: &mut EncounteredEnums, match_fields: &mut MatchFields, @@ -2336,6 +2359,7 @@ pub(crate) fn raw_response_visit_selections( } Selection::InlineFragment(inline_fragment) => raw_response_visit_inline_fragment( typegen_context, + operation_name, &mut type_selections, inline_fragment, encountered_enums, @@ -2378,6 +2402,7 @@ pub(crate) fn raw_response_visit_selections( |selections| { raw_response_visit_selections( typegen_context, + operation_name, selections, encountered_enums, match_fields, @@ -2404,6 +2429,7 @@ pub(crate) fn raw_response_visit_selections( Selection::Condition(condition) => { type_selections.extend(raw_response_visit_selections( typegen_context, + operation_name, &condition.selections, encountered_enums, match_fields, diff --git a/compiler/crates/relay-typegen/src/write.rs b/compiler/crates/relay-typegen/src/write.rs index 851c8ec5a1cc6..d338b45b8432e 100644 --- a/compiler/crates/relay-typegen/src/write.rs +++ b/compiler/crates/relay-typegen/src/write.rs @@ -144,6 +144,7 @@ pub(crate) fn write_operation_type_exports_section( let mut match_fields = Default::default(); let raw_response_selections = raw_response_visit_selections( typegen_context, + normalization_operation.name.item, &normalization_operation.selections, &mut encountered_enums, &mut match_fields, @@ -157,6 +158,7 @@ pub(crate) fn write_operation_type_exports_section( Some(( raw_response_selections_to_babel( typegen_context, + normalization_operation.name.item, raw_response_selections.into_iter(), None, &mut encountered_enums, @@ -301,6 +303,7 @@ pub(crate) fn write_split_operation_type_exports_section( let raw_response_selections = raw_response_visit_selections( typegen_context, + normalization_operation.name.item, &normalization_operation.selections, &mut encountered_enums, &mut match_fields, @@ -313,6 +316,7 @@ pub(crate) fn write_split_operation_type_exports_section( ); let raw_response_type = raw_response_selections_to_babel( typegen_context, + normalization_operation.name.item, raw_response_selections.into_iter(), None, &mut encountered_enums,