Skip to content

Commit ab5c96b

Browse files
Maarten Staafacebook-github-bot
authored andcommitted
Add support for Typescript in Rust Relay compiler (#3182)
Summary: See #3181 and #3180. This PR adds a language option to the typegen_config and refactors the relay-typegen crate to allow completely different output based on the configured language, currently typescript and flow (which is the default when no language is configured, or an invalid one is set). I also made some changes so the watchman query looks for .ts files when using typescript, and the output files also use .ts as their extension. This probably needs a bit more work before it's completely ready. Off the top of my head: - [ ] In `relay-compiler/build_project/artifact_content.rs` some output is generated such as `flow` and a commented out `import type` statement? Those should probably be left out for Typescript. - [x] Currently the language used for typegen is Typescript if the language in the config file is "typescript", and Flow otherwise. We should probably display an error if an invalid language is set, e.g. "typesrcipt". - [ ] I was not able to actually test the compiler due to an error returned by Watchman: `failed to parse query: must use ["suffix", "suffixstring"]`, and I don't have a clue why. This error was already returned before I made the changes to look for .ts files when using Typescript. - [ ] I did not at all look into `relay-lsp` and whether any changes are needed there for Typescript. Looking forward to your feedback! cc kassens josephsavona maraisr Pull Request resolved: #3182 Reviewed By: tyao1 Differential Revision: D23670620 Pulled By: kassens fbshipit-source-id: 0e3e9e6860c6701d934b406c895dc04bfb5b6322
1 parent d3ec569 commit ab5c96b

File tree

94 files changed

+4903
-174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+4903
-174
lines changed

compiler/crates/graphql-transforms/src/validations/validate_module_names/extract_module_name.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ mod tests {
121121
Some("SliderIos".to_string())
122122
);
123123
assert_eq!(
124-
extract_module_name("/path/Typescript.ts"),
125-
Some("Typescript".to_string())
124+
extract_module_name("/path/TypeScript.ts"),
125+
Some("TypeScript".to_string())
126126
);
127127
assert_eq!(
128-
extract_module_name("/path/Typescript.tsx"),
129-
Some("Typescript".to_string())
128+
extract_module_name("/path/TypeScript.tsx"),
129+
Some("TypeScript".to_string())
130130
);
131131
assert_eq!(
132132
extract_module_name("/path/button/index.js"),

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use graphql_text_printer::{
1818
};
1919
use graphql_transforms::{RefetchableDerivedFromMetadata, SplitOperationMetaData, MATCH_CONSTANTS};
2020
use interner::StringKey;
21+
use relay_typegen::TypegenLanguage;
2122
use std::path::PathBuf;
2223
use std::sync::Arc;
2324

@@ -60,7 +61,7 @@ pub fn generate_artifacts(
6061

6162
artifacts.push(Artifact {
6263
source_definition_names: metadata.parent_sources.into_iter().collect(),
63-
path: path_for_js_artifact(
64+
path: path_for_artifact(
6465
project_config,
6566
source_file,
6667
normalization_operation.name.item,
@@ -175,7 +176,7 @@ fn generate_normalization_artifact<'a>(
175176
.expect("a type fragment should be generated for this operation");
176177
Ok(Artifact {
177178
source_definition_names: vec![source_definition_name],
178-
path: path_for_js_artifact(project_config, source_file, name),
179+
path: path_for_artifact(project_config, source_file, name),
179180
content: ArtifactContent::Operation {
180181
normalization_operation: Arc::clone(normalization_operation),
181182
reader_operation: Arc::clone(reader_operation),
@@ -201,7 +202,7 @@ fn generate_reader_artifact(
201202
.expect("a type fragment should be generated for this fragment");
202203
Artifact {
203204
source_definition_names: vec![name],
204-
path: path_for_js_artifact(
205+
path: path_for_artifact(
205206
project_config,
206207
reader_fragment.name.location.source_location(),
207208
name,
@@ -254,15 +255,18 @@ pub fn create_path_for_artifact(
254255
}
255256
}
256257

257-
fn path_for_js_artifact(
258+
fn path_for_artifact(
258259
project_config: &ProjectConfig,
259260
source_file: SourceLocationKey,
260261
definition_name: StringKey,
261262
) -> PathBuf {
262263
create_path_for_artifact(
263264
project_config,
264265
source_file,
265-
format!("{}.graphql.js", definition_name),
266+
match &project_config.typegen_config.language {
267+
TypegenLanguage::Flow => format!("{}.graphql.js", definition_name),
268+
TypegenLanguage::TypeScript => format!("{}.graphql.ts", definition_name),
269+
},
266270
false,
267271
)
268272
}

compiler/crates/relay-compiler/src/watchman/query_builder.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,45 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
use crate::compiler_state::SourceSet;
89
use crate::config::{Config, SchemaLocation};
10+
use relay_typegen::TypegenLanguage;
911
use std::path::PathBuf;
1012
use watchman_client::prelude::*;
1113

1214
pub fn get_watchman_expr(config: &Config) -> Expr {
13-
let mut sources_conditions = vec![
14-
// ending in *.js
15-
Expr::Suffix(vec!["js".into()]),
16-
// in one of the source roots
17-
expr_any(
18-
get_source_roots(&config)
19-
.into_iter()
20-
.map(|path| Expr::DirName(DirNameTerm { path, depth: None }))
21-
.collect(),
22-
),
23-
];
15+
let mut sources_conditions = vec![expr_any(
16+
config
17+
.sources
18+
.iter()
19+
.flat_map(|(path, name)| match name {
20+
SourceSet::SourceSetName(name) => {
21+
std::iter::once((path, config.projects.get(&name))).collect::<Vec<_>>()
22+
}
23+
SourceSet::SourceSetNames(names) => names
24+
.iter()
25+
.map(|name| (path, config.projects.get(name)))
26+
.collect::<Vec<_>>(),
27+
})
28+
.filter_map(|(path, project)| match project {
29+
Some(p) if p.enabled => Some(Expr::All(vec![
30+
// Ending in *.js(x) or *.ts(x) depending on the project language.
31+
Expr::Suffix(match &p.typegen_config.language {
32+
TypegenLanguage::Flow => vec![PathBuf::from("js"), PathBuf::from("jsx")],
33+
TypegenLanguage::TypeScript => {
34+
vec![PathBuf::from("ts"), PathBuf::from("tsx")]
35+
}
36+
}),
37+
// In the related source root.
38+
Expr::DirName(DirNameTerm {
39+
path: path.clone(),
40+
depth: None,
41+
}),
42+
])),
43+
_ => None,
44+
})
45+
.collect(),
46+
)];
2447
// not excluded by any glob
2548
if !config.excludes.is_empty() {
2649
sources_conditions.push(Expr::Not(Box::new(expr_any(

compiler/crates/relay-typegen/src/config.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,26 @@ use fnv::FnvHashMap;
99
use interner::StringKey;
1010
use serde::Deserialize;
1111

12+
#[derive(Debug, Deserialize)]
13+
#[serde(deny_unknown_fields, rename_all = "lowercase")]
14+
pub enum TypegenLanguage {
15+
Flow,
16+
TypeScript,
17+
}
18+
19+
impl Default for TypegenLanguage {
20+
fn default() -> Self {
21+
Self::Flow
22+
}
23+
}
24+
1225
#[derive(Debug, Deserialize, Default)]
1326
#[serde(deny_unknown_fields, rename_all = "camelCase")]
1427
pub struct TypegenConfig {
28+
/// The desired output language, "flow" or "typescript".
29+
#[serde(default)]
30+
pub language: TypegenLanguage,
31+
1532
/// # For Flow type generation
1633
/// When set, enum values are imported from a module with this suffix.
1734
/// For example, an enum Foo and this property set to ".test" would be

0 commit comments

Comments
 (0)