Skip to content

Commit 524d3f1

Browse files
captbaritonemeta-codesync[bot]
authored andcommitted
Make module name prefix validation opt-in for non-Haste projects (#5200)
Summary: The compiler previously enforced that all GraphQL operation/fragment names are prefixed with the file name. This restriction only makes sense for Haste module resolution where file names are globally unique. Now the validation runs automatically for Haste projects, and non-Haste projects can opt in via the enforce_module_name_prefix_for_non_haste feature flag. Pull Request resolved: #5200 Reviewed By: josephsavona Differential Revision: D95463492 Pulled By: captbaritone fbshipit-source-id: 8a6cab182374c6f59abd189e4eb5f4ada405e020
1 parent 61332da commit 524d3f1

12 files changed

Lines changed: 229 additions & 51 deletions

compiler/Cargo.lock

Lines changed: 60 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/crates/common/src/feature_flags.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ pub struct FeatureFlags {
203203
/// alias for `@relayType` / `@relayField`.
204204
#[serde(default)]
205205
pub allow_legacy_relay_resolver_tag: FeatureFlag,
206+
207+
/// Enforce that GraphQL operation and fragment names start with the file
208+
/// name. Haste projects have this enforcement automatically; this flag
209+
/// is only needed for non-Haste projects that want the same validation.
210+
#[serde(default)]
211+
pub enforce_module_name_prefix_for_non_haste: bool,
206212
}
207213

208214
impl Default for FeatureFlags {
@@ -238,6 +244,7 @@ impl Default for FeatureFlags {
238244
enable_shadow_resolvers: Default::default(),
239245
new_flow_casting_syntax: Default::default(),
240246
allow_legacy_relay_resolver_tag: Default::default(),
247+
enforce_module_name_prefix_for_non_haste: Default::default(),
241248

242249
// enabled-by-default
243250
enforce_fragment_alias_where_ambiguous: FeatureFlag::Enabled,

compiler/crates/relay-compiler/relay-compiler-config-schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,11 @@
682682
"kind": "enabled"
683683
}
684684
},
685+
"enforce_module_name_prefix_for_non_haste": {
686+
"description": "Enforce that GraphQL operation and fragment names start with the file\nname. Haste projects have this enforcement automatically; this flag\nis only needed for non-Haste projects that want the same validation.",
687+
"type": "boolean",
688+
"default": false
689+
},
685690
"legacy_include_path_in_required_reader_nodes": {
686691
"description": "The `path` field in `@required` Reader AST nodes is no longer used. But\nremoving them in one diff is too large of a change to ship at once.\n\nThis flag will allow us to use the rollout FeatureFlag to remove them\nacross a number of diffs.",
687692
"$ref": "#/$defs/FeatureFlag",
@@ -947,6 +952,7 @@
947952
"enforce_fragment_alias_where_ambiguous": {
948953
"kind": "enabled"
949954
},
955+
"enforce_module_name_prefix_for_non_haste": false,
950956
"legacy_include_path_in_required_reader_nodes": {
951957
"kind": "disabled"
952958
},

compiler/crates/relay-compiler/src/build_project/validate.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use common::WithDiagnostics;
1212
use common::escalate_and_check;
1313
use errors::try_all;
1414
use graphql_ir::Program;
15+
use relay_config::JsModuleFormat;
1516
use relay_config::ProjectConfig;
1617
use relay_transforms::ValidateVariablesOptions;
1718
use relay_transforms::disallow_circular_no_inline_fragments;
@@ -76,7 +77,15 @@ pub fn validate(
7677
validate_connections(program, &project_config.schema_config.connection_interface),
7778
validate_relay_directives(program),
7879
validate_global_variable_names(program),
79-
validate_module_names(program),
80+
if matches!(project_config.js_module_format, JsModuleFormat::Haste)
81+
|| project_config
82+
.feature_flags
83+
.enforce_module_name_prefix_for_non_haste
84+
{
85+
validate_module_names(program)
86+
} else {
87+
Ok(())
88+
},
8089
validate_client_schema_extensions_use_catch(program),
8190
validate_no_inline_fragments_with_raw_response_type(program),
8291
disallow_typename_on_root(program),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
==================================== INPUT ====================================
2+
//- foo.js
3+
graphql`
4+
fragment notMatchingModuleName on User {
5+
name
6+
}`;
7+
8+
//- relay.config.json
9+
{
10+
"language": "typescript",
11+
"schema": "./schema.graphql",
12+
"featureFlags": {
13+
"enforce_module_name_prefix_for_non_haste": true
14+
}
15+
}
16+
17+
//- schema.graphql
18+
type Query { me: User }
19+
type User { name: String }
20+
==================================== OUTPUT ===================================
21+
✖︎ Fragments in graphql tags must start with the module name ('foo'). Got 'notMatchingModuleName' instead.
22+
23+
foo.js:2:12
24+
1 │
25+
2 │ fragment notMatchingModuleName on User {
26+
│ ^^^^^^^^^^^^^^^^^^^^^
27+
3 │ name
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//- foo.js
2+
graphql`
3+
fragment notMatchingModuleName on User {
4+
name
5+
}`;
6+
7+
//- relay.config.json
8+
{
9+
"language": "typescript",
10+
"schema": "./schema.graphql",
11+
"featureFlags": {
12+
"enforce_module_name_prefix_for_non_haste": true
13+
}
14+
}
15+
16+
//- schema.graphql
17+
type Query { me: User }
18+
type User { name: String }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
==================================== INPUT ====================================
2+
//- foo.js
3+
graphql`
4+
fragment notMatchingModuleName on User {
5+
name
6+
}`;
7+
8+
//- relay.config.json
9+
{
10+
"language": "typescript",
11+
"schema": "./schema.graphql"
12+
}
13+
14+
//- schema.graphql
15+
type Query { me: User }
16+
type User { name: String }
17+
==================================== OUTPUT ===================================
18+
//-++ __generated__/notMatchingModuleName.graphql.ts
19+
/**
20+
* <auto-generated> SignedSource<<a726d4c8346058ffbabeb81fc4927256>>
21+
* @lightSyntaxTransform
22+
* @nogrep
23+
*/
24+
25+
/* tslint:disable */
26+
/* eslint-disable */
27+
// @ts-nocheck
28+
29+
import { ReaderFragment } from 'relay-runtime';
30+
import { FragmentRefs } from "relay-runtime";
31+
export type notMatchingModuleName$data = {
32+
readonly name: string | null | undefined;
33+
readonly " $fragmentType": "notMatchingModuleName";
34+
};
35+
export type notMatchingModuleName$key = {
36+
readonly " $data"?: notMatchingModuleName$data;
37+
readonly " $fragmentSpreads": FragmentRefs<"notMatchingModuleName">;
38+
};
39+
40+
const node: ReaderFragment = {
41+
"argumentDefinitions": [],
42+
"kind": "Fragment",
43+
"metadata": null,
44+
"name": "notMatchingModuleName",
45+
"selections": [
46+
{
47+
"alias": null,
48+
"args": null,
49+
"kind": "ScalarField",
50+
"name": "name",
51+
"storageKey": null
52+
}
53+
],
54+
"type": "User",
55+
"abstractKey": null
56+
};
57+
58+
(node as any).hash = "e153e2a2bafa3b8ef4a86c54db559336";
59+
60+
export default node;
61+
62+
63+
64+
Artifact Map:
65+
Project: default
66+
Type: Mapping
67+
- Source: ExecutableDefinition: notMatchingModuleName
68+
Path: __generated__/notMatchingModuleName.graphql.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//- foo.js
2+
graphql`
3+
fragment notMatchingModuleName on User {
4+
name
5+
}`;
6+
7+
//- relay.config.json
8+
{
9+
"language": "typescript",
10+
"schema": "./schema.graphql"
11+
}
12+
13+
//- schema.graphql
14+
type Query { me: User }
15+
type User { name: String }

0 commit comments

Comments
 (0)