From 6cdf81db7c4a41d036eefc17e41ffb8db0cf54a1 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Tue, 30 Apr 2024 20:12:35 +0200 Subject: [PATCH] feat(cli): add support for jsxImportSourceTypes (#23419) Co-authored-by: David Sherret --- Cargo.lock | 16 ++--- Cargo.toml | 2 +- cli/Cargo.toml | 6 +- cli/args/mod.rs | 1 + cli/lsp/config.rs | 10 ++- cli/resolver.rs | 9 +++ cli/schemas/config-file.v1.json | 6 ++ cli/tools/repl/session.rs | 1 + cli/tools/vendor/build.rs | 2 + tests/integration/lsp_tests.rs | 72 +++++++++++++++++++ .../jsx_import_source_types/__test__.jsonc | 4 ++ .../check/jsx_import_source_types/main.out | 3 + .../check/jsx_import_source_types/main.tsx | 11 +++ .../__test__.jsonc | 4 ++ .../jsx_import_source_types_config/deno.json | 7 ++ .../jsx_import_source_types_config/deno.lock | 6 ++ .../jsx_import_source_types_config/main.out | 3 + .../jsx_import_source_types_config/main.tsx | 7 ++ tests/util/server/src/servers/mod.rs | 40 +++++++++++ 19 files changed, 196 insertions(+), 14 deletions(-) create mode 100644 tests/specs/check/jsx_import_source_types/__test__.jsonc create mode 100644 tests/specs/check/jsx_import_source_types/main.out create mode 100644 tests/specs/check/jsx_import_source_types/main.tsx create mode 100644 tests/specs/check/jsx_import_source_types_config/__test__.jsonc create mode 100644 tests/specs/check/jsx_import_source_types_config/deno.json create mode 100644 tests/specs/check/jsx_import_source_types_config/deno.lock create mode 100644 tests/specs/check/jsx_import_source_types_config/main.out create mode 100644 tests/specs/check/jsx_import_source_types_config/main.tsx diff --git a/Cargo.lock b/Cargo.lock index 1eea1d20ea..7b97117d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,9 +1166,9 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffefe28ebd657419ab0f7fbf4ab9cd4ae38d55c2a0e4fe1661c76d7fa2b81ba" +checksum = "7e2417aad5382d10d035e46d35f2f5fbbb93a922816408245ee585e7ca775194" dependencies = [ "anyhow", "base64", @@ -1272,9 +1272,9 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28ad258b58ade470cd745191eacee35562db3c967ffb26b4aa6f0f88f0882dd" +checksum = "971658ccd8dbd7de18f44d2270a6881a78a88f123584fc6497189ee5d20aa307" dependencies = [ "anyhow", "glob", @@ -1405,9 +1405,9 @@ dependencies = [ [[package]] name = "deno_emit" -version = "0.40.1" +version = "0.40.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b9cd09751a6493567d773c2a610f86d41b2f76ecfaf9eff23d3400970f8d30" +checksum = "efe4e71f7c2b0ddef4a4927a193ce47824488f29c90166700605b3fe560fecb7" dependencies = [ "anyhow", "base64", @@ -1477,9 +1477,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.74.0" +version = "0.74.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f5fa7d6a74edd749de34216fa52aad7af6b4e47b321cc7e91e38b9a7a2bb48" +checksum = "d828c95097ea836267c058ac912b5bd9e5c95cec11f57a32b25ac9e4bbe698fc" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 8808058be2..bff543f2f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ license = "MIT" repository = "https://github.com/denoland/deno" [workspace.dependencies] -deno_ast = { version = "=0.38.0", features = ["transpiling"] } +deno_ast = { version = "=0.38.1", features = ["transpiling"] } deno_core = { version = "0.278.0" } deno_bench_util = { version = "0.142.0", path = "./bench_util" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 605b1075ec..02f44563ea 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -65,11 +65,11 @@ winres.workspace = true [dependencies] deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } deno_cache_dir = { workspace = true } -deno_config = "=0.16.2" +deno_config = "=0.16.3" deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "=0.128.1", features = ["html", "syntect"] } -deno_emit = "=0.40.1" -deno_graph = { version = "=0.74.0", features = ["tokio_executor"] } +deno_emit = "=0.40.2" +deno_graph = { version = "=0.74.2", features = ["tokio_executor"] } deno_lint = { version = "=0.58.4", features = ["docs"] } deno_lockfile.workspace = true deno_npm = "=0.18.0" diff --git a/cli/args/mod.rs b/cli/args/mod.rs index b77a8afdbf..f4d5743dce 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -196,6 +196,7 @@ pub fn ts_config_to_transpile_and_emit_options( inline_sources: options.inline_sources, keep_comments: false, source_map, + source_map_file: None, }, )) } diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index e5703a21a4..ec209e0e68 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -1071,8 +1071,14 @@ impl LspTsConfig { let import_map = import_map?; let referrer = &config_file?.specifier; let compiler_options = ts_config.inner.0.as_object_mut()?; - let jsx_import_source = - compiler_options.get("jsxImportSource")?.as_str()?; + let jsx_import_source = compiler_options + .get("jsxImportSourceTypes") + .and_then(|v| v.as_str()) + .or_else(|| { + compiler_options + .get("jsxImportSource") + .and_then(|v| v.as_str()) + })?; let jsx_import_source = import_map.resolve(jsx_import_source, referrer).ok()?; compiler_options diff --git a/cli/resolver.rs b/cli/resolver.rs index dfee9a7048..32233e961f 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -447,6 +447,7 @@ pub struct CliGraphResolver { sloppy_imports_resolver: Option, mapped_specifier_resolver: MappedSpecifierResolver, maybe_default_jsx_import_source: Option, + maybe_default_jsx_import_source_types: Option, maybe_jsx_import_source_module: Option, maybe_vendor_specifier: Option, node_resolver: Option>, @@ -488,6 +489,10 @@ impl CliGraphResolver { .maybe_jsx_import_source_config .as_ref() .and_then(|c| c.default_specifier.clone()), + maybe_default_jsx_import_source_types: options + .maybe_jsx_import_source_config + .as_ref() + .and_then(|c| c.default_types_specifier.clone()), maybe_jsx_import_source_module: options .maybe_jsx_import_source_config .map(|c| c.module), @@ -554,6 +559,10 @@ impl Resolver for CliGraphResolver { self.maybe_default_jsx_import_source.clone() } + fn default_jsx_import_source_types(&self) -> Option { + self.maybe_default_jsx_import_source_types.clone() + } + fn jsx_import_source_module(&self) -> &str { self .maybe_jsx_import_source_module diff --git a/cli/schemas/config-file.v1.json b/cli/schemas/config-file.v1.json index a188940167..bfcae271b0 100644 --- a/cli/schemas/config-file.v1.json +++ b/cli/schemas/config-file.v1.json @@ -76,6 +76,12 @@ "default": "react", "markdownDescription": "Specify module specifier used to import the JSX factory functions when using jsx: `react-jsx*`.\n\nSee more: https://www.typescriptlang.org/tsconfig/#jsxImportSource" }, + "jsxImportSourceTypes": { + "description": "Specify module specifier used to import the types for the JSX factory functions when using jsx: 'react-jsx*'. This is the logical equivalent of prefixing an import to the jsxImportSource with `// @deno-types=\"...\"`.", + "type": "string", + "default": "@types/react", + "markdownDescription": "Specify module specifier used to import the types for the JSX factory functions when using jsx: `react-jsx*`. This is the logical equivalent of prefixing an import to the jsxImportSource with `// @deno-types=\"...\"`." + }, "jsxPrecompileSkipElements": { "description": "Specify list of elements that should be exempt from being precompiled when the jsx 'precompile' transform is used.", "type": "array", diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 671dad4b50..1bc8a96d0e 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -637,6 +637,7 @@ impl ReplSession { }, &deno_ast::EmitOptions { source_map: deno_ast::SourceMapOption::None, + source_map_file: None, inline_sources: false, keep_comments: false, }, diff --git a/cli/tools/vendor/build.rs b/cli/tools/vendor/build.rs index 0590992b04..5ff986f0cb 100644 --- a/cli/tools/vendor/build.rs +++ b/cli/tools/vendor/build.rs @@ -1205,6 +1205,7 @@ mod test { builder.add_entry_point("/mod.tsx"); builder.set_jsx_import_source_config(JsxImportSourceConfig { default_specifier: Some("preact".to_string()), + default_types_specifier: None, module: "jsx-runtime".to_string(), base_url: builder.resolve_to_url("/deno.json"), }); @@ -1254,6 +1255,7 @@ mod test { builder.add_entry_point("/mod.ts"); builder.set_jsx_import_source_config(JsxImportSourceConfig { default_specifier: Some("preact".to_string()), + default_types_specifier: None, module: "jsx-runtime".to_string(), base_url: builder.resolve_to_url("/deno.json"), }); diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 2e4b6da308..d000973c0f 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -10525,6 +10525,10 @@ export function B() { } }) ); + + let diagnostics = client.read_diagnostics(); + println!("{:?}", diagnostics); + client.shutdown(); } @@ -10584,6 +10588,74 @@ fn lsp_jsx_import_source_config_file_automatic_cache() { client.shutdown(); } +#[test] +fn lsp_jsx_import_source_types_pragma() { + let context = TestContextBuilder::new() + .use_http_server() + .use_temp_cwd() + .build(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": "file:///a/file.tsx", + "languageId": "typescriptreact", + "version": 1, + "text": +"/** @jsxImportSource http://localhost:4545/jsx */ +/** @jsxImportSourceTypes http://localhost:4545/jsx-types */ +/** @jsxRuntime automatic */ + +function A() { + return Hello; +} + +export function B() { + return ; +} +", + } + })); + client.write_request( + "workspace/executeCommand", + json!({ + "command": "deno.cache", + "arguments": [ + [], + "file:///a/file.tsx", + ], + }), + ); + + let diagnostics = client.read_diagnostics(); + assert_eq!(diagnostics.all().len(), 0); + + let res = client.write_request( + "textDocument/hover", + json!({ + "textDocument": { + "uri": "file:///a/file.tsx" + }, + "position": { "line": 0, "character": 25 } + }), + ); + assert_eq!( + res, + json!({ + "contents": { + "kind": "markdown", + "value": "**Resolved Dependency**\n\n**Code**: http​://localhost:4545/jsx/jsx-runtime\n\n**Types**: http​://localhost:4545/jsx-types/jsx-runtime\n", + }, + "range": { + "start": { "line": 0, "character": 21 }, + "end": { "line": 0, "character": 46 } + } + }) + ); + + client.shutdown(); +} + #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct TestData { diff --git a/tests/specs/check/jsx_import_source_types/__test__.jsonc b/tests/specs/check/jsx_import_source_types/__test__.jsonc new file mode 100644 index 0000000000..4cd2aa4235 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "check --all main.tsx", + "output": "main.out" +} diff --git a/tests/specs/check/jsx_import_source_types/main.out b/tests/specs/check/jsx_import_source_types/main.out new file mode 100644 index 0000000000..b1fade200d --- /dev/null +++ b/tests/specs/check/jsx_import_source_types/main.out @@ -0,0 +1,3 @@ +Download http://localhost:4545/jsx-types/jsx-runtime +Download http://localhost:4545/jsx-types/jsx-runtime.d.ts +Check file:///[WILDLINE]/main.tsx diff --git a/tests/specs/check/jsx_import_source_types/main.tsx b/tests/specs/check/jsx_import_source_types/main.tsx new file mode 100644 index 0000000000..c46ae9d460 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types/main.tsx @@ -0,0 +1,11 @@ +/** @jsxImportSource http://localhost:4545/jsx */ +/** @jsxImportSourceTypes http://localhost:4545/jsx-types */ +/** @jsxRuntime automatic */ + +function A() { + return Hello; +} + +export function B() { + return ; +} diff --git a/tests/specs/check/jsx_import_source_types_config/__test__.jsonc b/tests/specs/check/jsx_import_source_types_config/__test__.jsonc new file mode 100644 index 0000000000..4cd2aa4235 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types_config/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "check --all main.tsx", + "output": "main.out" +} diff --git a/tests/specs/check/jsx_import_source_types_config/deno.json b/tests/specs/check/jsx_import_source_types_config/deno.json new file mode 100644 index 0000000000..2f5ef6b0d6 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types_config/deno.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "http://localhost:4545/jsx", + "jsxImportSourceTypes": "http://localhost:4545/jsx-types" + } +} diff --git a/tests/specs/check/jsx_import_source_types_config/deno.lock b/tests/specs/check/jsx_import_source_types_config/deno.lock new file mode 100644 index 0000000000..30d3ed1f73 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types_config/deno.lock @@ -0,0 +1,6 @@ +{ + "version": "3", + "remote": { + "http://localhost:4545/jsx-types/jsx-runtime": "a9bf78bd825e7db35e1932615ea3a8bee5302a9fe7802f58d52859505ac9cf4a" + } +} diff --git a/tests/specs/check/jsx_import_source_types_config/main.out b/tests/specs/check/jsx_import_source_types_config/main.out new file mode 100644 index 0000000000..b1fade200d --- /dev/null +++ b/tests/specs/check/jsx_import_source_types_config/main.out @@ -0,0 +1,3 @@ +Download http://localhost:4545/jsx-types/jsx-runtime +Download http://localhost:4545/jsx-types/jsx-runtime.d.ts +Check file:///[WILDLINE]/main.tsx diff --git a/tests/specs/check/jsx_import_source_types_config/main.tsx b/tests/specs/check/jsx_import_source_types_config/main.tsx new file mode 100644 index 0000000000..c38572fc36 --- /dev/null +++ b/tests/specs/check/jsx_import_source_types_config/main.tsx @@ -0,0 +1,7 @@ +function A() { + return Hello; +} + +export function B() { + return ; +} diff --git a/tests/util/server/src/servers/mod.rs b/tests/util/server/src/servers/mod.rs index 18f893a118..38f6d8dfd8 100644 --- a/tests/util/server/src/servers/mod.rs +++ b/tests/util/server/src/servers/mod.rs @@ -801,6 +801,46 @@ async fn main_server( ); Ok(res) } + (_, "/jsx-types/jsx-runtime") | (_, "/jsx-types/jsx-dev-runtime") => { + let mut res = Response::new(string_body( + r#" +/// + "#, + )); + res.headers_mut().insert( + "Content-type", + HeaderValue::from_static("application/javascript"), + ); + Ok(res) + } + (_, "/jsx-types/jsx-runtime.d.ts") => { + let mut res = Response::new(string_body( + r#"export function jsx( + _type: "a" | "b", + _props: any, + _key: any, + _source: any, + _self: any, + ): any; + export const jsxs: typeof jsx; + export const jsxDEV: typeof jsx; + export const Fragment: unique symbol; + + declare global { + namespace JSX { + interface IntrinsicElements { + [tagName: string]: Record; + } + } + } + "#, + )); + res.headers_mut().insert( + "Content-type", + HeaderValue::from_static("application/typescript"), + ); + Ok(res) + } (_, "/dynamic") => { let mut res = Response::new(string_body( &serde_json::to_string_pretty(&std::time::SystemTime::now()).unwrap(),