diff --git a/src/graph.rs b/src/graph.rs index ccc33359e..2a961ea9c 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -3800,20 +3800,10 @@ impl<'a, 'graph> Builder<'a, 'graph> { .unwrap(); match fut.await { Ok(info) => { - // resolve the best version out of the existing versions first let package_req = pending_resolution.package_ref.req(); - match self.resolve_jsr_version(&info, package_req) { - Some(version) => { + match self.resolve_jsr_nv(&info, package_req) { + Some(package_nv) => { // now queue a pending load for that version information - let package_nv = PackageNv { - name: package_name.clone(), - version, - }; - self - .graph - .packages - .add_nv(package_req.clone(), package_nv.clone()); - self.queue_load_package_version_info(&package_nv); pending_version_resolutions.push(PendingJsrNvResolutionItem { specifier: pending_resolution.specifier, @@ -4158,69 +4148,84 @@ impl<'a, 'graph> Builder<'a, 'graph> { async move { self.fill(roots, imports).await }.boxed_local() } - fn resolve_jsr_version( + fn resolve_jsr_nv( &mut self, package_info: &JsrPackageInfo, package_req: &PackageReq, - ) -> Option { - // 1. try to resolve with the list of existing versions - if let Some(existing_versions) = - self.graph.packages.versions_by_name(&package_req.name) - { - if let Some(version) = resolve_version( - &package_req.version_req, - existing_versions.iter().map(|nv| &nv.version), - ) { - let is_yanked = package_info - .versions - .get(version) - .map(|i| i.yanked) - .unwrap_or(false); - let version = version.clone(); - if is_yanked { - self.graph.packages.add_used_yanked_package(PackageNv { - name: package_req.name.clone(), - version: version.clone(), - }); + ) -> Option { + if let Some(package_nv) = self.graph.packages.mappings().get(package_req) { + return Some(package_nv.clone()); + } + let version = (|| { + // 1. try to resolve with the list of existing versions + if let Some(existing_versions) = + self.graph.packages.versions_by_name(&package_req.name) + { + if let Some(version) = resolve_version( + &package_req.version_req, + existing_versions.iter().map(|nv| &nv.version), + ) { + let is_yanked = package_info + .versions + .get(version) + .map(|i| i.yanked) + .unwrap_or(false); + let version = version.clone(); + if is_yanked { + self.graph.packages.add_used_yanked_package(PackageNv { + name: package_req.name.clone(), + version: version.clone(), + }); + } + return Some(version); } - return Some(version); } - } - // 2. attempt to resolve with the unyanked versions - let unyanked_versions = - package_info.versions.iter().filter_map(|(v, i)| { - if !i.yanked { - Some(v) - } else { - None - } - }); - if let Some(version) = - resolve_version(&package_req.version_req, unyanked_versions) - { - return Some(version.clone()); - } + // 2. attempt to resolve with the unyanked versions + let unyanked_versions = + package_info.versions.iter().filter_map(|(v, i)| { + if !i.yanked { + Some(v) + } else { + None + } + }); + if let Some(version) = + resolve_version(&package_req.version_req, unyanked_versions) + { + return Some(version.clone()); + } - // 3. attempt to resolve with the the yanked versions - let yanked_versions = package_info.versions.iter().filter_map(|(v, i)| { - if i.yanked { - Some(v) - } else { - None + // 3. attempt to resolve with the the yanked versions + let yanked_versions = + package_info.versions.iter().filter_map(|(v, i)| { + if i.yanked { + Some(v) + } else { + None + } + }); + if let Some(version) = + resolve_version(&package_req.version_req, yanked_versions) + { + self.graph.packages.add_used_yanked_package(PackageNv { + name: package_req.name.clone(), + version: version.clone(), + }); + return Some(version.clone()); } - }); - if let Some(version) = - resolve_version(&package_req.version_req, yanked_versions) - { - self.graph.packages.add_used_yanked_package(PackageNv { - name: package_req.name.clone(), - version: version.clone(), - }); - return Some(version.clone()); - } - None + None + })()?; + let package_nv = PackageNv { + name: package_req.name.clone(), + version, + }; + self + .graph + .packages + .add_nv(package_req.clone(), package_nv.clone()); + Some(package_nv) } /// Checks if the specifier is redirected or not and updates any redirects in diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 4687ffdf4..0ac28ac67 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -688,14 +688,20 @@ await import(`./a/${test}`); .await; } -#[test] -fn test_fill_from_lockfile() { +#[tokio::test] +async fn test_fill_from_lockfile() { let mut graph = ModuleGraph::new(GraphKind::All); let redirects = [("https://example.com", "https://example.com/final")]; - let specifiers = [( - JsrDepPackageReq::from_str("jsr:@scope/example").unwrap(), - "1.0.0", - )]; + let specifiers = [ + ( + JsrDepPackageReq::from_str("jsr:@scope/example").unwrap(), + "1.0.0", + ), + ( + JsrDepPackageReq::from_str("jsr:@scope/example@1.0.1").unwrap(), + "1.0.1", + ), + ]; graph.fill_from_lockfile(FillFromLockfileOptions { redirects: redirects.iter().copied(), package_specifiers: specifiers.iter().map(|(k, v)| (k, *v)), @@ -717,6 +723,69 @@ fn test_fill_from_lockfile() { .unwrap(), PackageNv::from_str("@scope/example@1.0.0").unwrap(), ); + + let mut loader = MemoryLoader::default(); + loader.add_jsr_package_info( + "@scope/example", + &JsrPackageInfo { + versions: vec![ + ( + deno_semver::Version::parse_standard("1.0.0").unwrap(), + JsrPackageInfoVersion::default(), + ), + ( + deno_semver::Version::parse_standard("1.0.1").unwrap(), + JsrPackageInfoVersion::default(), + ), + ] + .into_iter() + .collect(), + }, + ); + loader.add_jsr_version_info( + "@scope/example", + "1.0.0", + &JsrPackageVersionInfo { + exports: serde_json::json!({ + ".": "./mod.ts" + }), + ..Default::default() + }, + ); + loader.add_jsr_version_info( + "@scope/example", + "1.0.1", + &JsrPackageVersionInfo { + exports: serde_json::json!({ + ".": "./mod.ts" + }), + ..Default::default() + }, + ); + loader.add_source_with_text( + "https://jsr.io/@scope/example/1.0.0/mod.ts", + "// This is version 1.0.0 of this package.", + ); + loader.add_source_with_text( + "https://jsr.io/@scope/example/1.0.1/mod.ts", + "// This is version 1.0.1 of this package.", + ); + graph + .build( + // This should match 1.0.0 due to the first entry in the lockfile. + vec![Url::parse("jsr:/@scope/example").unwrap()], + &loader, + Default::default(), + ) + .await; + graph.valid().unwrap(); + let modules = graph.modules().collect::>(); + assert_eq!(modules.len(), 1); + let module = modules.into_iter().next().unwrap().js().unwrap(); + assert_eq!( + module.source.as_ref(), + "// This is version 1.0.0 of this package." + ); } #[tokio::test] diff --git a/tests/specs/ecosystem/mrii/rocket_io/0_1_3.test b/tests/specs/ecosystem/mrii/rocket_io/0_1_3.test index 96e67e49f..711d46fbb 100644 --- a/tests/specs/ecosystem/mrii/rocket_io/0_1_3.test +++ b/tests/specs/ecosystem/mrii/rocket_io/0_1_3.test @@ -73,10 +73,10 @@ mrii/rocket-io/0.1.3 -- stderr -- error: Error: [ERR_PACKAGE_PATH_NOT_EXPORTED] Package subpath './build/esm/socket' is not defined for types by "exports" in '/socket.io-client/4.7.5/package.json' imported from 'file:///src/types/socket-reserved-events.ts' - at Object.resolveModuleNameLiterals (ext:deno_cli_tsc/97_ts_host.js:622:26) - at ext:deno_cli_tsc/97_ts_host.js:757:49 + at Object.resolveModuleNameLiterals (ext:deno_cli_tsc/97_ts_host.js:623:26) + at ext:deno_cli_tsc/97_ts_host.js:758:49 at spanned (ext:deno_cli_tsc/97_ts_host.js:16:12) - at Object.host. [as resolveModuleNameLiterals] (ext:deno_cli_tsc/97_ts_host.js:757:14) + at Object.host. [as resolveModuleNameLiterals] (ext:deno_cli_tsc/97_ts_host.js:758:14) at resolveModuleNamesWorker (ext:deno_cli_tsc/00_typescript.js:126315:20) at resolveNamesReusingOldState (ext:deno_cli_tsc/00_typescript.js:126457:14) at resolveModuleNamesReusingOldState (ext:deno_cli_tsc/00_typescript.js:126413:12)