From 9d3a87db15f9258be18498368f1126bd37a73d71 Mon Sep 17 00:00:00 2001 From: Andrey Lunyov Date: Wed, 12 Oct 2022 20:13:59 -0700 Subject: [PATCH] Compiler flag to enable named imports Summary: If this feature flag is enabled, we'll use named imports for resolver functions. This will allow us define multiple resolvers in a single file. In this diff we passing this flag to the relay docblock parser, so it can start adding field name (for now) as a `named` import. In the next diff this `import_name` will be used in codegen/typegen. Reviewed By: captbaritone Differential Revision: D40240874 fbshipit-source-id: 7944ee65a52bcbcb6b5edc305c15ae6c2cce561f --- compiler/crates/common/src/feature_flags.rs | 5 ++ .../src/build_project/build_schema.rs | 1 + .../crates/relay-compiler/src/docblocks.rs | 26 ++++++- .../tests/compile_relay_artifacts/mod.rs | 1 + .../mod.rs | 1 + compiler/crates/relay-docblock/src/ir.rs | 1 + compiler/crates/relay-docblock/src/lib.rs | 17 ++++- ...esolver-deprecated-no-description.expected | 1 + .../relay-resolver-deprecated.expected | 1 + .../relay-resolver-named-export.expected | 75 +++++++++++++++++++ .../fixtures/relay-resolver-named-export.js | 27 +++++++ .../relay-resolver-with-args.expected | 1 + ...lver-with-field-and-fragment-args.expected | 1 + .../relay-resolver-with-field-args.expected | 1 + .../relay-resolver-with-fragment.expected | 1 + .../relay-resolver-with-output-type.expected | 1 + .../parse/fixtures/relay-resolver.expected | 1 + .../crates/relay-docblock/tests/parse/mod.rs | 13 +++- .../crates/relay-docblock/tests/parse_test.rs | 9 ++- .../relay-resolver-named-export.expected | 32 ++++++++ .../fixtures/relay-resolver-named-export.js | 27 +++++++ .../relay-docblock/tests/to_schema/mod.rs | 10 ++- .../relay-docblock/tests/to_schema_test.rs | 9 ++- .../crates/relay-lsp/src/server/lsp_state.rs | 25 ++++++- compiler/crates/relay-lsp/src/utils.rs | 15 +++- 25 files changed, 288 insertions(+), 14 deletions(-) create mode 100644 compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.expected create mode 100644 compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.js create mode 100644 compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.expected create mode 100644 compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.js diff --git a/compiler/crates/common/src/feature_flags.rs b/compiler/crates/common/src/feature_flags.rs index 2407e0515a423..0a58e9ea50074 100644 --- a/compiler/crates/common/src/feature_flags.rs +++ b/compiler/crates/common/src/feature_flags.rs @@ -26,6 +26,11 @@ pub struct FeatureFlags { #[serde(default)] pub enable_relay_resolver_transform: bool, + /// Use `named export` in Relay resolvers modules + /// this should allow defining multiple resolvers per module. + #[serde(default)] + pub use_named_imports_for_relay_resolvers: bool, + /// Enable hashing of the `supported` argument of 3D fields. Partial /// enabling of the feature flag checks the name based on the field type. #[serde(default)] diff --git a/compiler/crates/relay-compiler/src/build_project/build_schema.rs b/compiler/crates/relay-compiler/src/build_project/build_schema.rs index 1cbbeb6d92b5c..b13826badc34b 100644 --- a/compiler/crates/relay-compiler/src/build_project/build_schema.rs +++ b/compiler/crates/relay-compiler/src/build_project/build_schema.rs @@ -68,6 +68,7 @@ pub fn build_schema( graphql_asts.get_executable_definitions_for_file(file_path); for schema_document in extract_schema_from_docblock_sources( + project_config, file_path, docblock_sources, &schema, diff --git a/compiler/crates/relay-compiler/src/docblocks.rs b/compiler/crates/relay-compiler/src/docblocks.rs index 74ab107523af3..e6b40c20a8e5d 100644 --- a/compiler/crates/relay-compiler/src/docblocks.rs +++ b/compiler/crates/relay-compiler/src/docblocks.rs @@ -13,25 +13,35 @@ use docblock_syntax::parse_docblock; use errors::try_all; use graphql_syntax::ExecutableDefinition; use graphql_syntax::SchemaDocument; +use relay_config::ProjectConfig; use relay_docblock::parse_docblock_ast; +use relay_docblock::ParseOptions; use schema::SDLSchema; use crate::file_source::LocatedDocblockSource; pub fn extract_schema_from_docblock_sources( + project_config: &ProjectConfig, file_path: &Path, docblock_sources: &[LocatedDocblockSource], schema: &SDLSchema, definitions: Option<&Vec>, ) -> DiagnosticsResult> { try_all(docblock_sources.iter().filter_map(|docblock_source| { - parse_source(file_path, docblock_source, schema, definitions) - // Convert Result> to Option> so we can take advantage of filter_map - .transpose() + parse_source( + project_config, + file_path, + docblock_source, + schema, + definitions, + ) + // Convert Result> to Option> so we can take advantage of filter_map + .transpose() })) } fn parse_source( + project_config: &ProjectConfig, file_path: &Path, docblock_source: &LocatedDocblockSource, schema: &SDLSchema, @@ -45,7 +55,15 @@ fn parse_source( source_location, )?; - let maybe_ir = parse_docblock_ast(&ast, definitions)?; + let maybe_ir = parse_docblock_ast( + &ast, + definitions, + ParseOptions { + use_named_imports: project_config + .feature_flags + .use_named_imports_for_relay_resolvers, + }, + )?; maybe_ir .map(|ir| ir.to_graphql_schema_ast(schema)) .transpose() 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 4e322bb3c9e32..09154295e2da1 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs @@ -117,6 +117,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { skip_printing_nulls: FeatureFlag::Disabled, enable_fragment_aliases: FeatureFlag::Enabled, compact_query_text: FeatureFlag::Disabled, + use_named_imports_for_relay_resolvers: false, }; let default_project_config = ProjectConfig { 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 a6d76518a8dbb..2d852e080f151 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 @@ -87,6 +87,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { skip_printing_nulls: FeatureFlag::Disabled, enable_fragment_aliases: FeatureFlag::Enabled, compact_query_text: FeatureFlag::Disabled, + use_named_imports_for_relay_resolvers: false, }; let project_config = ProjectConfig { diff --git a/compiler/crates/relay-docblock/src/ir.rs b/compiler/crates/relay-docblock/src/ir.rs index a27bf3426f61b..a83934c5c73d0 100644 --- a/compiler/crates/relay-docblock/src/ir.rs +++ b/compiler/crates/relay-docblock/src/ir.rs @@ -140,6 +140,7 @@ pub struct RelayResolverIr { pub live: Option, pub location: Location, pub fragment_arguments: Option>, + pub named_import: Option, } impl RelayResolverIr { diff --git a/compiler/crates/relay-docblock/src/lib.rs b/compiler/crates/relay-docblock/src/lib.rs index 4b1f0cb1e4764..4c2bf7e85c3ea 100644 --- a/compiler/crates/relay-docblock/src/lib.rs +++ b/compiler/crates/relay-docblock/src/lib.rs @@ -43,6 +43,11 @@ use lazy_static::lazy_static; use crate::errors::ErrorMessages; +#[derive(Default)] +pub struct ParseOptions { + pub use_named_imports: bool, +} + lazy_static! { static ref RELAY_RESOLVER_FIELD: StringKey = "RelayResolver".intern(); static ref FIELD_NAME_FIELD: StringKey = "fieldName".intern(); @@ -63,12 +68,13 @@ lazy_static! { pub fn parse_docblock_ast( ast: &DocblockAST, definitions: Option<&Vec>, + parse_options: ParseOptions, ) -> DiagnosticsResult> { if ast.find_field(*RELAY_RESOLVER_FIELD).is_none() { return Ok(None); } - let parser = RelayResolverParser::new(); + let parser = RelayResolverParser::new(parse_options); let resolver_ir = parser.parse(ast, definitions)?; Ok(Some(DocblockIr::RelayResolver(resolver_ir))) } @@ -81,10 +87,11 @@ struct RelayResolverParser { description: Option>, allowed_fields: Vec, errors: Vec, + options: ParseOptions, } impl RelayResolverParser { - fn new() -> Self { + fn new(options: ParseOptions) -> Self { Self { fields: Default::default(), description: Default::default(), @@ -100,6 +107,7 @@ impl RelayResolverParser { *LIVE_FIELD, *OUTPUT_TYPE_FIELD, ], + options, } } fn parse( @@ -186,6 +194,10 @@ impl RelayResolverParser { } } } + // For the initial version the name of the export have to match + // the name of the resolver field. Adding JS parser capabilities will allow + // us to derive the name of the export from the source. + let named_import = self.options.use_named_imports.then_some(field.name.value); Ok(RelayResolverIr { field, @@ -198,6 +210,7 @@ impl RelayResolverParser { deprecated, live, fragment_arguments, + named_import, }) } diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated-no-description.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated-no-description.expected index 2422d7337838d..2760e61172fdd 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated-no-description.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated-no-description.expected @@ -81,5 +81,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver-deprecated-no-description.js:0:130, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated.expected index 7865f4545ed81..666976ef2762a 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-deprecated.expected @@ -86,5 +86,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver-deprecated.js:0:160, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.expected new file mode 100644 index 0000000000000..588742de3f286 --- /dev/null +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.expected @@ -0,0 +1,75 @@ +==================================== INPUT ==================================== +/** + * 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. + */ + +// relay:use_named_imports + +/** + * @RelayResolver + * + * @onType User + * @fieldName favorite_page + * @rootFragment myRootFragment + * + * The user's favorite page! They probably clicked something in the UI + * to tell us that it was their favorite page and then we put that in a + * database or something. Then we got that info out again and put it out + * again. Anyway, I'm rambling now. Its a page that the user likes. A lot. + */ + +graphql` + fragment myRootFragment on User { + id + } +` +==================================== OUTPUT =================================== +RelayResolver( + RelayResolverIr { + field: FieldDefinitionStub { + name: Identifier { + span: 53:66, + token: Token { + span: 53:66, + kind: Identifier, + }, + value: "favorite_page", + }, + arguments: None, + }, + on: Type( + PopulatedIrField { + key_location: /path/to/test/fixture/relay-resolver-named-export.js:27:33, + value: WithLocation { + location: /path/to/test/fixture/relay-resolver-named-export.js:34:38, + item: "User", + }, + }, + ), + root_fragment: Some( + WithLocation { + location: /path/to/test/fixture/relay-resolver-named-export.js:84:98, + item: FragmentDefinitionName( + "myRootFragment", + ), + }, + ), + output_type: None, + description: Some( + WithLocation { + location: /path/to/test/fixture/relay-resolver-named-export.js:101:392, + item: "\nThe user's favorite page! They probably clicked something in the UI\nto tell us that it was their favorite page and then we put that in a\ndatabase or something. Then we got that info out again and put it out\nagain. Anyway, I'm rambling now. Its a page that the user likes. A lot.", + }, + ), + deprecated: None, + live: None, + location: /path/to/test/fixture/relay-resolver-named-export.js:0:393, + fragment_arguments: None, + named_import: Some( + "favorite_page", + ), + }, +) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.js b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.js new file mode 100644 index 0000000000000..75554ab830eee --- /dev/null +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-named-export.js @@ -0,0 +1,27 @@ +/** + * 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. + */ + +// relay:use_named_imports + +/** + * @RelayResolver + * + * @onType User + * @fieldName favorite_page + * @rootFragment myRootFragment + * + * The user's favorite page! They probably clicked something in the UI + * to tell us that it was their favorite page and then we put that in a + * database or something. Then we got that info out again and put it out + * again. Anyway, I'm rambling now. Its a page that the user likes. A lot. + */ + +graphql` + fragment myRootFragment on User { + id + } +` diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-args.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-args.expected index f1382907480cd..eca2e1387bba8 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-args.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-args.expected @@ -134,5 +134,6 @@ RelayResolver( }, ], ), + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-and-fragment-args.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-and-fragment-args.expected index 3ff9dd363ef2e..86c1a52156ef3 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-and-fragment-args.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-and-fragment-args.expected @@ -172,5 +172,6 @@ RelayResolver( }, ], ), + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-args.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-args.expected index 2865797fa8053..e6224f8ad0888 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-args.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-field-args.expected @@ -104,5 +104,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver-with-field-args.js:0:118, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-fragment.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-fragment.expected index 418c4fa297caf..a461e9ac2822d 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-fragment.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-fragment.expected @@ -56,5 +56,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver-with-fragment.js:0:94, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-output-type.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-output-type.expected index b53801620b397..fb6dd3d347e37 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-output-type.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver-with-output-type.expected @@ -85,5 +85,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver-with-output-type.js:0:419, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver.expected index 3db03f82fc685..a3d4e14178899 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/relay-resolver.expected @@ -85,5 +85,6 @@ RelayResolver( live: None, location: /path/to/test/fixture/relay-resolver.js:0:409, fragment_arguments: None, + named_import: None, }, ) diff --git a/compiler/crates/relay-docblock/tests/parse/mod.rs b/compiler/crates/relay-docblock/tests/parse/mod.rs index f2d304f001b8f..31adb9ce1cc66 100644 --- a/compiler/crates/relay-docblock/tests/parse/mod.rs +++ b/compiler/crates/relay-docblock/tests/parse/mod.rs @@ -15,6 +15,7 @@ use graphql_syntax::parse_executable; use graphql_syntax::ExecutableDefinition; use intern::string_key::Intern; use relay_docblock::parse_docblock_ast; +use relay_docblock::ParseOptions; pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { let js_features = extract_graphql::extract(fixture.content); @@ -54,7 +55,17 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { index: i as u16, }, ) - .and_then(|ast| parse_docblock_ast(&ast, Some(&executable_documents))) + .and_then(|ast| { + parse_docblock_ast( + &ast, + Some(&executable_documents), + ParseOptions { + use_named_imports: fixture + .content + .contains("// relay:use_named_imports"), + }, + ) + }) .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics)), ), }) diff --git a/compiler/crates/relay-docblock/tests/parse_test.rs b/compiler/crates/relay-docblock/tests/parse_test.rs index cb6c7ce942f6f..c8e03cd668b24 100644 --- a/compiler/crates/relay-docblock/tests/parse_test.rs +++ b/compiler/crates/relay-docblock/tests/parse_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<5f08fb834712e36cfb8d384567778614>> + * @generated SignedSource<> */ mod parse; @@ -89,6 +89,13 @@ fn relay_resolver_missing_multiple_fields_invalid() { test_fixture(transform_fixture, "relay-resolver-missing-multiple-fields.invalid.js", "parse/fixtures/relay-resolver-missing-multiple-fields.invalid.expected", input, expected); } +#[test] +fn relay_resolver_named_export() { + let input = include_str!("parse/fixtures/relay-resolver-named-export.js"); + let expected = include_str!("parse/fixtures/relay-resolver-named-export.expected"); + test_fixture(transform_fixture, "relay-resolver-named-export.js", "parse/fixtures/relay-resolver-named-export.expected", input, expected); +} + #[test] fn relay_resolver_on_interface_mismatch_invalid() { let input = include_str!("parse/fixtures/relay-resolver-on-interface-mismatch.invalid.js"); diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.expected new file mode 100644 index 0000000000000..aa6053577bc2e --- /dev/null +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.expected @@ -0,0 +1,32 @@ +==================================== INPUT ==================================== +/** + * 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. + */ + +// relay:use_named_imports + +/** + * @RelayResolver + * + * @onType User + * @fieldName favorite_page + * @rootFragment myRootFragment + * + * The user's favorite page! They probably clicked something in the UI + * to tell us that it was their favorite page and then we put that in a + * database or something. Then we got that info out again and put it out + * again. Anyway, I'm rambling now. Its a page that the user likes. A lot. + */ + +graphql` + fragment myRootFragment on User { + id + } +` +==================================== OUTPUT =================================== +extend type User { + favorite_page: Int @relay_resolver(import_path: "/path/to/test/fixture/relay-resolver-named-export.js", fragment_name: "myRootFragment") +} diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.js b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.js new file mode 100644 index 0000000000000..75554ab830eee --- /dev/null +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-named-export.js @@ -0,0 +1,27 @@ +/** + * 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. + */ + +// relay:use_named_imports + +/** + * @RelayResolver + * + * @onType User + * @fieldName favorite_page + * @rootFragment myRootFragment + * + * The user's favorite page! They probably clicked something in the UI + * to tell us that it was their favorite page and then we put that in a + * database or something. Then we got that info out again and put it out + * again. Anyway, I'm rambling now. Its a page that the user likes. A lot. + */ + +graphql` + fragment myRootFragment on User { + id + } +` diff --git a/compiler/crates/relay-docblock/tests/to_schema/mod.rs b/compiler/crates/relay-docblock/tests/to_schema/mod.rs index 39c44efb08e1a..5c1b6a5743632 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/mod.rs +++ b/compiler/crates/relay-docblock/tests/to_schema/mod.rs @@ -18,6 +18,7 @@ use graphql_syntax::ExecutableDefinition; use graphql_test_helpers::diagnostics_to_sorted_string; use intern::string_key::Intern; use relay_docblock::parse_docblock_ast; +use relay_docblock::ParseOptions; use relay_test_schema::get_test_schema; use relay_test_schema::get_test_schema_with_extensions; use schema::SDLSchema; @@ -59,7 +60,14 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { index: i as u16, }, )?; - let ir = parse_docblock_ast(&ast, Some(&executable_documents))?.unwrap(); + let ir = parse_docblock_ast( + &ast, + Some(&executable_documents), + ParseOptions { + use_named_imports: fixture.content.contains("// relay:use_named_imports"), + }, + )? + .unwrap(); ir.to_sdl_string(&schema) }; diff --git a/compiler/crates/relay-docblock/tests/to_schema_test.rs b/compiler/crates/relay-docblock/tests/to_schema_test.rs index 4e8b73e0d5a59..109203ebb305e 100644 --- a/compiler/crates/relay-docblock/tests/to_schema_test.rs +++ b/compiler/crates/relay-docblock/tests/to_schema_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<4bf1e2d6bf147bdfbf0b6d9c763f2289>> */ mod to_schema; @@ -68,6 +68,13 @@ fn relay_resolver_implementing_a_field_defined_by_parent_interface() { test_fixture(transform_fixture, "relay-resolver-implementing-a-field-defined-by-parent-interface.js", "to_schema/fixtures/relay-resolver-implementing-a-field-defined-by-parent-interface.expected", input, expected); } +#[test] +fn relay_resolver_named_export() { + let input = include_str!("to_schema/fixtures/relay-resolver-named-export.js"); + let expected = include_str!("to_schema/fixtures/relay-resolver-named-export.expected"); + test_fixture(transform_fixture, "relay-resolver-named-export.js", "to_schema/fixtures/relay-resolver-named-export.expected", input, expected); +} + #[test] fn relay_resolver_on_interface() { let input = include_str!("to_schema/fixtures/relay-resolver-on-interface.js"); diff --git a/compiler/crates/relay-lsp/src/server/lsp_state.rs b/compiler/crates/relay-lsp/src/server/lsp_state.rs index a8382ed54e57a..7d7cba0f1cb88 100644 --- a/compiler/crates/relay-lsp/src/server/lsp_state.rs +++ b/compiler/crates/relay-lsp/src/server/lsp_state.rs @@ -37,6 +37,7 @@ use lsp_types::Url; use relay_compiler::config::Config; use relay_compiler::FileCategorizer; use relay_docblock::parse_docblock_ast; +use relay_docblock::ParseOptions; use relay_transforms::deprecated_fields_for_executable_definition; use schema::SDLSchema; use schema_documentation::CombinedSchemaDocumentation; @@ -279,12 +280,22 @@ impl LSPRuntimeResult<(Feature, Span)> { - extract_feature_from_text(&self.synced_javascript_features, position, index_offset) + let project_name = self.extract_project_name_from_url(&position.text_document.uri)?; + let project_config = self.config.projects.get(&project_name).unwrap(); + + extract_feature_from_text( + project_config, + &self.synced_javascript_features, + position, + index_offset, + ) } fn get_schema_documentation(&self, schema_name: &str) -> Self::TSchemaDocumentation { diff --git a/compiler/crates/relay-lsp/src/utils.rs b/compiler/crates/relay-lsp/src/utils.rs index 5de22ce1df1a7..152045d9b2267 100644 --- a/compiler/crates/relay-lsp/src/utils.rs +++ b/compiler/crates/relay-lsp/src/utils.rs @@ -22,7 +22,9 @@ use lsp_types::TextDocumentPositionParams; use lsp_types::Url; use relay_compiler::FileCategorizer; use relay_compiler::FileGroup; +use relay_compiler::ProjectConfig; use relay_docblock::parse_docblock_ast; +use relay_docblock::ParseOptions; use crate::lsp_runtime_error::LSPRuntimeError; use crate::lsp_runtime_error::LSPRuntimeResult; @@ -97,6 +99,7 @@ pub fn extract_project_name_from_url( /// Return a parsed executable document, or parsed Docblock IR for this LSP /// request, only if the request occurs within a GraphQL document or Docblock. pub fn extract_feature_from_text( + project_config: &ProjectConfig, source_feature_cache: &DashMap>, text_document_position: &TextDocumentPositionParams, index_offset: usize, @@ -154,7 +157,17 @@ pub fn extract_feature_from_text( let text_source = &docblock_source.text_source(); let text = &text_source.text; let docblock_ir = parse_docblock(text, source_location_key) - .and_then(|ast| parse_docblock_ast(&ast, Some(&executable_definitions_in_file))) + .and_then(|ast| { + parse_docblock_ast( + &ast, + Some(&executable_definitions_in_file), + ParseOptions { + use_named_imports: project_config + .feature_flags + .use_named_imports_for_relay_resolvers, + }, + ) + }) .map_err(|_| { LSPRuntimeError::UnexpectedError("Failed to parse docblock".to_string()) })?