From bcf7d6f230cb70bd751728264bdf0744902dee5d Mon Sep 17 00:00:00 2001 From: Tom Gasson Date: Fri, 30 Sep 2022 09:18:37 -0700 Subject: [PATCH] Use `import type` in typescript for all imports (#4029) Summary: This makes the following change to typescript artifacts: ```diff -import { ConcreteRequest, Query } from "relay-runtime"; +import type { ConcreteRequest, Query } from "relay-runtime"; import type { FragmentRefs } from "relay-runtime"; ``` Using the existing `useImportTypeSyntax` config. As stated in the config, the `import type` syntax introduced in Typescript version 3.8 and prevents warnings from `importsNotUsedAsValues`. This setting also assists naive bundlers from taking a dependency on `relay-runtime`, when only the types are needed. I kept this simple. Other paths for implementation would be - There's a mix of distinct typegen printers e.g. compiler/crates/relay-typegen/src/typescript.rs, and the inline use of conditionals on the language directly in compiler/crates/relay-compiler/src/artifact_content/content.rs. Consolidating these would allow sharing the existing `write_import_type` function - The imports could instead be consolidated and printed together, rather than potentially having multiple imports from the same file as it is now Pull Request resolved: https://github.com/facebook/relay/pull/4029 Test Plan: Imported from GitHub, without a `Test Plan:` line. Static Docs Site previews have moved into the custom phabricator field "Static Docs", and will no longer modify test plans after 5th October 2022. Reviewed By: alunyov Differential Revision: D38279030 Pulled By: alunyov fbshipit-source-id: 1e252d2fe9041963a33d6dedecb4ac4b512628dd --- .../src/artifact_content/content.rs | 23 +++- .../fixtures/simple.expected | 24 ++++ .../fixtures/simple.graphql | 8 ++ .../generate_typescript_import_syntax/mod.rs | 120 ++++++++++++++++++ .../generate_typescript_import_syntax_test.rs | 20 +++ 5 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.expected create mode 100644 compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.graphql create mode 100644 compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/mod.rs create mode 100644 compiler/crates/relay-typegen/tests/generate_typescript_import_syntax_test.rs diff --git a/compiler/crates/relay-compiler/src/artifact_content/content.rs b/compiler/crates/relay-compiler/src/artifact_content/content.rs index b3557ce29f92f..5d6e0c20d127a 100644 --- a/compiler/crates/relay-compiler/src/artifact_content/content.rs +++ b/compiler/crates/relay-compiler/src/artifact_content/content.rs @@ -96,7 +96,7 @@ pub fn generate_updatable_query( } write_import_type_from( - &project_config.typegen_config.language, + project_config, &mut section, generated_types.imported_types, "relay-runtime", @@ -260,7 +260,7 @@ pub fn generate_operation( } write_import_type_from( - &project_config.typegen_config.language, + project_config, &mut section, generated_types.imported_types, "relay-runtime", @@ -426,7 +426,7 @@ pub fn generate_split_operation( writeln!(section, "/*::")?; } write_import_type_from( - &project_config.typegen_config.language, + project_config, &mut section, "NormalizationSplitOperation", "relay-runtime", @@ -600,7 +600,7 @@ fn generate_read_only_fragment( } write_import_type_from( - &project_config.typegen_config.language, + project_config, &mut section, generated_types.imported_types, "relay-runtime", @@ -790,15 +790,26 @@ fn generate_use_strict_section(language: &TypegenLanguage) -> Result FmtResult { + let language = &project_config.typegen_config.language; match language { TypegenLanguage::JavaScript => Ok(()), TypegenLanguage::Flow => writeln!(section, "import type {{ {} }} from '{}';", type_, from), - TypegenLanguage::TypeScript => writeln!(section, "import {{ {} }} from '{}';", type_, from), + TypegenLanguage::TypeScript => writeln!( + section, + "import {}{{ {} }} from '{}';", + if project_config.typegen_config.use_import_type_syntax { + "type " + } else { + "" + }, + type_, + from + ), } } diff --git a/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.expected b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.expected new file mode 100644 index 0000000000000..b175a1638d38d --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.expected @@ -0,0 +1,24 @@ +==================================== INPUT ==================================== +fragment LinkedField on User { + name + profilePicture { + uri + width + height + } +} +==================================== OUTPUT =================================== +import type { FragmentRefs } from "relay-runtime"; +export type LinkedField$data = { + readonly name: string | null; + readonly profilePicture: { + readonly height: number | null; + readonly uri: string | null; + readonly width: number | null; + } | null; + readonly " $fragmentType": "LinkedField"; +}; +export type LinkedField$key = { + readonly " $data"?: LinkedField$data; + readonly " $fragmentSpreads": FragmentRefs<"LinkedField">; +}; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.graphql b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.graphql new file mode 100644 index 0000000000000..80d214783ca3b --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/fixtures/simple.graphql @@ -0,0 +1,8 @@ +fragment LinkedField on User { + name + profilePicture { + uri + width + height + } +} \ No newline at end of file diff --git a/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/mod.rs b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/mod.rs new file mode 100644 index 0000000000000..96b6c03749322 --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax/mod.rs @@ -0,0 +1,120 @@ +/* + * 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. + */ + +use std::sync::Arc; + +use common::ConsoleLogger; +use common::FeatureFlag; +use common::FeatureFlags; +use common::SourceLocationKey; +use fixture_tests::Fixture; +use fnv::FnvBuildHasher; +use fnv::FnvHashMap; +use graphql_ir::build; +use graphql_ir::Program; +use graphql_syntax::parse_executable; +use indexmap::IndexMap; +use intern::string_key::Intern; +use relay_codegen::JsModuleFormat; +use relay_config::CustomScalarType; +use relay_config::CustomScalarTypeImport; +use relay_config::ProjectConfig; +use relay_test_schema::get_test_schema; +use relay_test_schema::get_test_schema_with_extensions; +use relay_transforms::apply_transforms; +use relay_typegen::FragmentLocations; +use relay_typegen::TypegenConfig; +use relay_typegen::TypegenLanguage; +use relay_typegen::{self}; + +type FnvIndexMap = IndexMap; + +pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { + let parts = fixture.content.split("%extensions%").collect::>(); + let (source, schema) = match parts.as_slice() { + [source, extensions] => (source, get_test_schema_with_extensions(extensions)), + [source] => (source, get_test_schema()), + _ => panic!(), + }; + + let source_location = SourceLocationKey::standalone(fixture.file_name); + + let mut sources = FnvHashMap::default(); + sources.insert(source_location, source); + let ast = parse_executable(source, source_location).unwrap_or_else(|e| { + panic!("Encountered error building AST: {:?}", e); + }); + let ir = build(&schema, &ast.definitions).unwrap_or_else(|e| { + panic!("Encountered error building IR {:?}", e); + }); + let program = Program::from_definitions(Arc::clone(&schema), ir); + let mut custom_scalar_types = FnvIndexMap::default(); + custom_scalar_types.insert( + "JSON".intern(), + CustomScalarType::Path(CustomScalarTypeImport { + name: "JSON".intern(), + path: "TypeDefsFile".into(), + }), + ); + let project_config = ProjectConfig { + name: "test".intern(), + js_module_format: JsModuleFormat::Haste, + typegen_config: TypegenConfig { + language: TypegenLanguage::TypeScript, + use_import_type_syntax: true, + custom_scalar_types, + ..Default::default() + }, + feature_flags: Arc::new(FeatureFlags { + enable_fragment_aliases: FeatureFlag::Enabled, + ..Default::default() + }), + ..Default::default() + }; + let programs = apply_transforms( + &project_config, + Arc::new(program), + Default::default(), + Arc::new(ConsoleLogger), + None, + None, + ) + .unwrap(); + + let fragment_locations = FragmentLocations::new(programs.typegen.fragments()); + let mut operations: Vec<_> = programs.typegen.operations().collect(); + operations.sort_by_key(|op| op.name.item); + let operation_strings = operations.into_iter().map(|typegen_operation| { + let normalization_operation = programs + .normalization + .operation(typegen_operation.name.item) + .unwrap(); + relay_typegen::generate_operation_type_exports_section( + typegen_operation, + normalization_operation, + &schema, + &project_config, + &fragment_locations, + ) + }); + + let mut fragments: Vec<_> = programs.typegen.fragments().collect(); + fragments.sort_by_key(|frag| frag.name.item); + let fragment_strings = fragments.into_iter().map(|frag| { + relay_typegen::generate_fragment_type_exports_section( + frag, + &schema, + &project_config, + &fragment_locations, + ) + }); + + let mut result: Vec = operation_strings.collect(); + result.extend(fragment_strings); + Ok(result + .join("-------------------------------------------------------------------------------\n")) +} diff --git a/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax_test.rs b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax_test.rs new file mode 100644 index 0000000000000..11636b1e1f432 --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_typescript_import_syntax_test.rs @@ -0,0 +1,20 @@ +/* + * 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. + * + * @generated SignedSource<> + */ + +mod generate_typescript_import_syntax; + +use generate_typescript_import_syntax::transform_fixture; +use fixture_tests::test_fixture; + +#[test] +fn simple() { + let input = include_str!("generate_typescript_import_syntax/fixtures/simple.graphql"); + let expected = include_str!("generate_typescript_import_syntax/fixtures/simple.expected"); + test_fixture(transform_fixture, "simple.graphql", "generate_typescript_import_syntax/fixtures/simple.expected", input, expected); +}