Skip to content

Commit

Permalink
Add support for Typescript in Rust Relay compiler (#3182)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Maarten Staa authored and facebook-github-bot committed Sep 17, 2020
1 parent d3ec569 commit ab5c96b
Show file tree
Hide file tree
Showing 94 changed files with 4,903 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ mod tests {
Some("SliderIos".to_string())
);
assert_eq!(
extract_module_name("/path/Typescript.ts"),
Some("Typescript".to_string())
extract_module_name("/path/TypeScript.ts"),
Some("TypeScript".to_string())
);
assert_eq!(
extract_module_name("/path/Typescript.tsx"),
Some("Typescript".to_string())
extract_module_name("/path/TypeScript.tsx"),
Some("TypeScript".to_string())
);
assert_eq!(
extract_module_name("/path/button/index.js"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use graphql_text_printer::{
};
use graphql_transforms::{RefetchableDerivedFromMetadata, SplitOperationMetaData, MATCH_CONSTANTS};
use interner::StringKey;
use relay_typegen::TypegenLanguage;
use std::path::PathBuf;
use std::sync::Arc;

Expand Down Expand Up @@ -60,7 +61,7 @@ pub fn generate_artifacts(

artifacts.push(Artifact {
source_definition_names: metadata.parent_sources.into_iter().collect(),
path: path_for_js_artifact(
path: path_for_artifact(
project_config,
source_file,
normalization_operation.name.item,
Expand Down Expand Up @@ -175,7 +176,7 @@ fn generate_normalization_artifact<'a>(
.expect("a type fragment should be generated for this operation");
Ok(Artifact {
source_definition_names: vec![source_definition_name],
path: path_for_js_artifact(project_config, source_file, name),
path: path_for_artifact(project_config, source_file, name),
content: ArtifactContent::Operation {
normalization_operation: Arc::clone(normalization_operation),
reader_operation: Arc::clone(reader_operation),
Expand All @@ -201,7 +202,7 @@ fn generate_reader_artifact(
.expect("a type fragment should be generated for this fragment");
Artifact {
source_definition_names: vec![name],
path: path_for_js_artifact(
path: path_for_artifact(
project_config,
reader_fragment.name.location.source_location(),
name,
Expand Down Expand Up @@ -254,15 +255,18 @@ pub fn create_path_for_artifact(
}
}

fn path_for_js_artifact(
fn path_for_artifact(
project_config: &ProjectConfig,
source_file: SourceLocationKey,
definition_name: StringKey,
) -> PathBuf {
create_path_for_artifact(
project_config,
source_file,
format!("{}.graphql.js", definition_name),
match &project_config.typegen_config.language {
TypegenLanguage::Flow => format!("{}.graphql.js", definition_name),
TypegenLanguage::TypeScript => format!("{}.graphql.ts", definition_name),
},
false,
)
}
45 changes: 34 additions & 11 deletions compiler/crates/relay-compiler/src/watchman/query_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,45 @@
* LICENSE file in the root directory of this source tree.
*/

use crate::compiler_state::SourceSet;
use crate::config::{Config, SchemaLocation};
use relay_typegen::TypegenLanguage;
use std::path::PathBuf;
use watchman_client::prelude::*;

pub fn get_watchman_expr(config: &Config) -> Expr {
let mut sources_conditions = vec![
// ending in *.js
Expr::Suffix(vec!["js".into()]),
// in one of the source roots
expr_any(
get_source_roots(&config)
.into_iter()
.map(|path| Expr::DirName(DirNameTerm { path, depth: None }))
.collect(),
),
];
let mut sources_conditions = vec![expr_any(
config
.sources
.iter()
.flat_map(|(path, name)| match name {
SourceSet::SourceSetName(name) => {
std::iter::once((path, config.projects.get(&name))).collect::<Vec<_>>()
}
SourceSet::SourceSetNames(names) => names
.iter()
.map(|name| (path, config.projects.get(name)))
.collect::<Vec<_>>(),
})
.filter_map(|(path, project)| match project {
Some(p) if p.enabled => Some(Expr::All(vec![
// Ending in *.js(x) or *.ts(x) depending on the project language.
Expr::Suffix(match &p.typegen_config.language {
TypegenLanguage::Flow => vec![PathBuf::from("js"), PathBuf::from("jsx")],
TypegenLanguage::TypeScript => {
vec![PathBuf::from("ts"), PathBuf::from("tsx")]
}
}),
// In the related source root.
Expr::DirName(DirNameTerm {
path: path.clone(),
depth: None,
}),
])),
_ => None,
})
.collect(),
)];
// not excluded by any glob
if !config.excludes.is_empty() {
sources_conditions.push(Expr::Not(Box::new(expr_any(
Expand Down
17 changes: 17 additions & 0 deletions compiler/crates/relay-typegen/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,26 @@ use fnv::FnvHashMap;
use interner::StringKey;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "lowercase")]
pub enum TypegenLanguage {
Flow,
TypeScript,
}

impl Default for TypegenLanguage {
fn default() -> Self {
Self::Flow
}
}

#[derive(Debug, Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct TypegenConfig {
/// The desired output language, "flow" or "typescript".
#[serde(default)]
pub language: TypegenLanguage,

/// # For Flow type generation
/// When set, enum values are imported from a module with this suffix.
/// For example, an enum Foo and this property set to ".test" would be
Expand Down
Loading

0 comments on commit ab5c96b

Please sign in to comment.