Skip to content

Commit

Permalink
Compiler flag to enable named imports
Browse files Browse the repository at this point in the history
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
  • Loading branch information
alunyov authored and facebook-github-bot committed Oct 13, 2022
1 parent 9065f2a commit 9d3a87d
Show file tree
Hide file tree
Showing 25 changed files with 288 additions and 14 deletions.
5 changes: 5 additions & 0 deletions compiler/crates/common/src/feature_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 22 additions & 4 deletions compiler/crates/relay-compiler/src/docblocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExecutableDefinition>>,
) -> DiagnosticsResult<Vec<SchemaDocument>> {
try_all(docblock_sources.iter().filter_map(|docblock_source| {
parse_source(file_path, docblock_source, schema, definitions)
// Convert Result<Option<_>> to Option<Result<T>> so we can take advantage of filter_map
.transpose()
parse_source(
project_config,
file_path,
docblock_source,
schema,
definitions,
)
// Convert Result<Option<_>> to Option<Result<T>> so we can take advantage of filter_map
.transpose()
}))
}

fn parse_source(
project_config: &ProjectConfig,
file_path: &Path,
docblock_source: &LocatedDocblockSource,
schema: &SDLSchema,
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
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 {
Expand Down
1 change: 1 addition & 0 deletions compiler/crates/relay-docblock/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ pub struct RelayResolverIr {
pub live: Option<IrField>,
pub location: Location,
pub fragment_arguments: Option<Vec<Argument>>,
pub named_import: Option<StringKey>,
}

impl RelayResolverIr {
Expand Down
17 changes: 15 additions & 2 deletions compiler/crates/relay-docblock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -63,12 +68,13 @@ lazy_static! {
pub fn parse_docblock_ast(
ast: &DocblockAST,
definitions: Option<&Vec<ExecutableDefinition>>,
parse_options: ParseOptions,
) -> DiagnosticsResult<Option<DocblockIr>> {
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)))
}
Expand All @@ -81,10 +87,11 @@ struct RelayResolverParser {
description: Option<WithLocation<StringKey>>,
allowed_fields: Vec<StringKey>,
errors: Vec<Diagnostic>,
options: ParseOptions,
}

impl RelayResolverParser {
fn new() -> Self {
fn new(options: ParseOptions) -> Self {
Self {
fields: Default::default(),
description: Default::default(),
Expand All @@ -100,6 +107,7 @@ impl RelayResolverParser {
*LIVE_FIELD,
*OUTPUT_TYPE_FIELD,
],
options,
}
}
fn parse(
Expand Down Expand Up @@ -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,
Expand All @@ -198,6 +210,7 @@ impl RelayResolverParser {
deprecated,
live,
fragment_arguments,
named_import,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,6 @@ RelayResolver(
live: None,
location: /path/to/test/fixture/relay-resolver-deprecated.js:0:160,
fragment_arguments: None,
named_import: None,
},
)
Original file line number Diff line number Diff line change
@@ -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",
),
},
)
Original file line number Diff line number Diff line change
@@ -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
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,6 @@ RelayResolver(
},
],
),
named_import: None,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,6 @@ RelayResolver(
},
],
),
named_import: None,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,6 @@ RelayResolver(
live: None,
location: /path/to/test/fixture/relay-resolver.js:0:409,
fragment_arguments: None,
named_import: None,
},
)
13 changes: 12 additions & 1 deletion compiler/crates/relay-docblock/tests/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> {
let js_features = extract_graphql::extract(fixture.content);
Expand Down Expand Up @@ -54,7 +55,17 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
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)),
),
})
Expand Down
9 changes: 8 additions & 1 deletion compiler/crates/relay-docblock/tests/parse_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<<d6a144e0412b4a4564bd2ab1f006f398>>
*/

mod parse;
Expand Down Expand Up @@ -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");
Expand Down
Loading

0 comments on commit 9d3a87d

Please sign in to comment.