diff --git a/js/test.ts b/js/test.ts index 86077bc71..a3f53e20c 100644 --- a/js/test.ts +++ b/js/test.ts @@ -175,7 +175,7 @@ Deno.test({ return Promise.resolve(fixtures[specifier]); }, }); - assertEquals(resolveCount, 1); + assertEquals(resolveCount, 2); assertEquals(graph, { "roots": [ "file:///a/test.js", @@ -251,7 +251,7 @@ Deno.test({ "file:///a/deno.json": ["https://esm.sh/preact/jsx-runtime"], }, }); - assertEquals(resolveCount, 2); + assertEquals(resolveCount, 3); assertEquals(graph, { "roots": [ "file:///a/test.ts", @@ -348,7 +348,7 @@ Deno.test({ return Promise.resolve(fixtures[specifier]); }, }); - assertEquals(resolveCount, 1); + assertEquals(resolveCount, 2); assertEquals(graph, { "roots": [ "file:///a/test.js", diff --git a/src/graph.rs b/src/graph.rs index 64e0cedf4..74ebf5f2d 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -475,6 +475,14 @@ impl Resolution { self.ok().map(|r| &r.specifier) } + pub fn maybe_range(&self) -> Option<&Range> { + match self { + Resolution::None => None, + Resolution::Ok(r) => Some(&r.range), + Resolution::Err(e) => Some(e.range()), + } + } + pub fn ok(&self) -> Option<&ResolutionResolved> { if let Resolution::Ok(resolved) = self { Some(&**resolved) @@ -2054,7 +2062,31 @@ pub(crate) fn parse_esm_module_from_module_info( maybe_npm_resolver, ) } else { - Resolution::None + let range = Range::from_position_range( + module.specifier.clone(), + desc.specifier_range.clone(), + ); + // only check if the code resolution is for the same range + if Some(&range) == dep.maybe_code.maybe_range() { + let types_resolution = resolve( + &desc.specifier, + range, + ResolutionMode::Types, + maybe_resolver, + maybe_npm_resolver, + ); + // only bother setting if the resolved specifier + // does not match the code specifier + if types_resolution.maybe_specifier() + != dep.maybe_code.maybe_specifier() + { + types_resolution + } else { + Resolution::None + } + } else { + Resolution::None + } }; dep.maybe_type = maybe_type } diff --git a/src/lib.rs b/src/lib.rs index 174c91d56..317d0a543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3647,4 +3647,131 @@ export function a(a: A): B { assert!(iterator.next().is_none()); } } + + #[tokio::test] + async fn test_resolver_execution_and_types_resolution() { + #[derive(Debug)] + struct ExtResolver; + + impl crate::source::Resolver for ExtResolver { + fn resolve( + &self, + specifier_text: &str, + referrer: &ModuleSpecifier, + mode: ResolutionMode, + ) -> Result { + let specifier_text = match mode { + ResolutionMode::Types => format!("{}.d.ts", specifier_text), + ResolutionMode::Execution => format!("{}.js", specifier_text), + }; + Ok(resolve_import(&specifier_text, referrer)?) + } + } + + let mut loader = setup( + vec![ + ( + "file:///a/test01.ts", + Source::Module { + specifier: "file:///a/test01.ts", + maybe_headers: None, + content: r#" + import a from "./a"; + "#, + }, + ), + ( + "file:///a/a.js", + Source::Module { + specifier: "file:///a/a.js", + maybe_headers: None, + content: r#"export default 5;"#, + }, + ), + ( + "file:///a/a.d.ts", + Source::Module { + specifier: "file:///a/a.d.ts", + maybe_headers: None, + content: r#"export default 5;"#, + }, + ), + ], + vec![], + ); + let root_specifier = + ModuleSpecifier::parse("file:///a/test01.ts").expect("bad url"); + let mut graph = ModuleGraph::new(GraphKind::All); + let resolver = ExtResolver; + graph + .build( + vec![root_specifier.clone()], + &mut loader, + BuildOptions { + resolver: Some(&resolver), + ..Default::default() + }, + ) + .await; + assert_eq!( + json!(graph), + json!({ + "roots": [ + "file:///a/test01.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 17, + "mediaType": "Dts", + "specifier": "file:///a/a.d.ts" + }, + { + "kind": "esm", + "size": 17, + "mediaType": "JavaScript", + "specifier": "file:///a/a.js" + }, + { + "dependencies": [ + { + "specifier": "./a", + "code": { + "specifier": "file:///a/a.js", + "span": { + "start": { + "line": 1, + "character": 26 + }, + "end": { + "line": 1, + "character": 31 + } + } + }, + "type": { + "specifier": "file:///a/a.d.ts", + "span": { + "start": { + "line": 1, + "character": 26 + }, + "end": { + "line": 1, + "character": 31 + } + } + }, + } + ], + "kind": "esm", + "size": 46, + "mediaType": "TypeScript", + "specifier": "file:///a/test01.ts" + } + ], + "redirects": {} + }) + ); + } }