mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(add): Handle packages without root exports (#25102)
Fixes #24607. This PR makes the logic that caches top level dependencies (things present in import map) smarter, so we handle JSR dependencies without root exports.
This commit is contained in:
parent
9aaad3064a
commit
48da3c17ea
17 changed files with 190 additions and 65 deletions
|
@ -18,7 +18,6 @@ use crate::cache::CodeCache;
|
||||||
use crate::cache::FastInsecureHasher;
|
use crate::cache::FastInsecureHasher;
|
||||||
use crate::cache::ParsedSourceCache;
|
use crate::cache::ParsedSourceCache;
|
||||||
use crate::emit::Emitter;
|
use crate::emit::Emitter;
|
||||||
use crate::factory::CliFactory;
|
|
||||||
use crate::graph_container::MainModuleGraphContainer;
|
use crate::graph_container::MainModuleGraphContainer;
|
||||||
use crate::graph_container::ModuleGraphContainer;
|
use crate::graph_container::ModuleGraphContainer;
|
||||||
use crate::graph_container::ModuleGraphUpdatePermit;
|
use crate::graph_container::ModuleGraphUpdatePermit;
|
||||||
|
@ -70,54 +69,6 @@ use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
use deno_semver::npm::NpmPackageReqReference;
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
use node_resolver::NodeResolutionMode;
|
use node_resolver::NodeResolutionMode;
|
||||||
|
|
||||||
pub async fn load_top_level_deps(factory: &CliFactory) -> Result<(), AnyError> {
|
|
||||||
let npm_resolver = factory.npm_resolver().await?;
|
|
||||||
let cli_options = factory.cli_options()?;
|
|
||||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
|
||||||
if !npm_resolver.ensure_top_level_package_json_install().await? {
|
|
||||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
|
||||||
lockfile.error_if_changed()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
npm_resolver.cache_packages().await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// cache as many entries in the import map as we can
|
|
||||||
let resolver = factory.workspace_resolver().await?;
|
|
||||||
if let Some(import_map) = resolver.maybe_import_map() {
|
|
||||||
let roots = import_map
|
|
||||||
.imports()
|
|
||||||
.entries()
|
|
||||||
.filter_map(|entry| {
|
|
||||||
if entry.key.ends_with('/') {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
entry.value.cloned()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let mut graph_permit = factory
|
|
||||||
.main_module_graph_container()
|
|
||||||
.await?
|
|
||||||
.acquire_update_permit()
|
|
||||||
.await;
|
|
||||||
let graph = graph_permit.graph_mut();
|
|
||||||
factory
|
|
||||||
.module_load_preparer()
|
|
||||||
.await?
|
|
||||||
.prepare_module_load(
|
|
||||||
graph,
|
|
||||||
&roots,
|
|
||||||
false,
|
|
||||||
factory.cli_options()?.ts_type_lib_window(),
|
|
||||||
deno_runtime::deno_permissions::PermissionsContainer::allow_all(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModuleLoadPreparer {
|
pub struct ModuleLoadPreparer {
|
||||||
options: Arc<CliOptions>,
|
options: Arc<CliOptions>,
|
||||||
lockfile: Option<Arc<CliLockfile>>,
|
lockfile: Option<Arc<CliLockfile>>,
|
||||||
|
|
|
@ -275,7 +275,7 @@ async fn install_local(
|
||||||
}
|
}
|
||||||
|
|
||||||
let factory = CliFactory::from_flags(flags);
|
let factory = CliFactory::from_flags(flags);
|
||||||
crate::module_loader::load_top_level_deps(&factory).await?;
|
crate::tools::registry::cache_top_level_deps(&factory, None).await?;
|
||||||
|
|
||||||
if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() {
|
if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() {
|
||||||
lockfile.write_if_changed()?;
|
lockfile.write_if_changed()?;
|
||||||
|
|
|
@ -52,6 +52,7 @@ use crate::util::display::human_size;
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod auth;
|
mod auth;
|
||||||
|
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
mod graph;
|
mod graph;
|
||||||
mod paths;
|
mod paths;
|
||||||
|
@ -64,6 +65,7 @@ mod unfurl;
|
||||||
use auth::get_auth_method;
|
use auth::get_auth_method;
|
||||||
use auth::AuthMethod;
|
use auth::AuthMethod;
|
||||||
pub use pm::add;
|
pub use pm::add;
|
||||||
|
pub use pm::cache_top_level_deps;
|
||||||
pub use pm::remove;
|
pub use pm::remove;
|
||||||
pub use pm::AddCommandName;
|
pub use pm::AddCommandName;
|
||||||
use publish_order::PublishOrderGraph;
|
use publish_order::PublishOrderGraph;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
mod cache_deps;
|
||||||
|
|
||||||
|
pub use cache_deps::cache_top_level_deps;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -236,13 +240,16 @@ pub async fn add(
|
||||||
|
|
||||||
let package_futures = package_reqs
|
let package_futures = package_reqs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(move |package_req| {
|
.map({
|
||||||
find_package_and_select_version_for_req(
|
let jsr_resolver = jsr_resolver.clone();
|
||||||
jsr_resolver.clone(),
|
move |package_req| {
|
||||||
npm_resolver.clone(),
|
find_package_and_select_version_for_req(
|
||||||
package_req,
|
jsr_resolver.clone(),
|
||||||
)
|
npm_resolver.clone(),
|
||||||
.boxed_local()
|
package_req,
|
||||||
|
)
|
||||||
|
.boxed_local()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -350,7 +357,7 @@ pub async fn add(
|
||||||
// make a new CliFactory to pick up the updated config file
|
// make a new CliFactory to pick up the updated config file
|
||||||
let cli_factory = CliFactory::from_flags(flags);
|
let cli_factory = CliFactory::from_flags(flags);
|
||||||
// cache deps
|
// cache deps
|
||||||
crate::module_loader::load_top_level_deps(&cli_factory).await?;
|
cache_deps::cache_top_level_deps(&cli_factory, Some(jsr_resolver)).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -597,7 +604,7 @@ pub async fn remove(
|
||||||
// Update deno.lock
|
// Update deno.lock
|
||||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||||
let cli_factory = CliFactory::from_flags(flags);
|
let cli_factory = CliFactory::from_flags(flags);
|
||||||
crate::module_loader::load_top_level_deps(&cli_factory).await?;
|
cache_deps::cache_top_level_deps(&cli_factory, None).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
115
cli/tools/registry/pm/cache_deps.rs
Normal file
115
cli/tools/registry/pm/cache_deps.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::factory::CliFactory;
|
||||||
|
use crate::graph_container::ModuleGraphContainer;
|
||||||
|
use crate::graph_container::ModuleGraphUpdatePermit;
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_core::futures::stream::FuturesUnordered;
|
||||||
|
use deno_core::futures::StreamExt;
|
||||||
|
use deno_semver::package::PackageReq;
|
||||||
|
|
||||||
|
pub async fn cache_top_level_deps(
|
||||||
|
factory: &CliFactory,
|
||||||
|
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
let npm_resolver = factory.npm_resolver().await?;
|
||||||
|
let cli_options = factory.cli_options()?;
|
||||||
|
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||||
|
if !npm_resolver.ensure_top_level_package_json_install().await? {
|
||||||
|
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||||
|
lockfile.error_if_changed()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
npm_resolver.cache_packages().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// cache as many entries in the import map as we can
|
||||||
|
let resolver = factory.workspace_resolver().await?;
|
||||||
|
if let Some(import_map) = resolver.maybe_import_map() {
|
||||||
|
let jsr_resolver = if let Some(resolver) = jsr_resolver {
|
||||||
|
resolver
|
||||||
|
} else {
|
||||||
|
Arc::new(crate::jsr::JsrFetchResolver::new(
|
||||||
|
factory.file_fetcher()?.clone(),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut roots = Vec::new();
|
||||||
|
|
||||||
|
let mut info_futures = FuturesUnordered::new();
|
||||||
|
|
||||||
|
let mut seen_reqs = std::collections::HashSet::new();
|
||||||
|
|
||||||
|
for entry in import_map.imports().entries() {
|
||||||
|
let Some(specifier) = entry.value else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
match specifier.scheme() {
|
||||||
|
"jsr" => {
|
||||||
|
let specifier_str = specifier.as_str();
|
||||||
|
let specifier_str =
|
||||||
|
specifier_str.strip_prefix("jsr:").unwrap_or(specifier_str);
|
||||||
|
if let Ok(req) = PackageReq::from_str(specifier_str) {
|
||||||
|
if !seen_reqs.insert(req.clone()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let jsr_resolver = jsr_resolver.clone();
|
||||||
|
info_futures.push(async move {
|
||||||
|
if let Some(nv) = jsr_resolver.req_to_nv(&req).await {
|
||||||
|
if let Some(info) = jsr_resolver.package_version_info(&nv).await
|
||||||
|
{
|
||||||
|
return Some((specifier.clone(), info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"npm" => roots.push(specifier.clone()),
|
||||||
|
_ => {
|
||||||
|
if entry.key.ends_with('/') && specifier.as_str().ends_with('/') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
roots.push(specifier.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(info_future) = info_futures.next().await {
|
||||||
|
if let Some((specifier, info)) = info_future {
|
||||||
|
if info.export(".").is_some() {
|
||||||
|
roots.push(specifier.clone());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let exports = info.exports();
|
||||||
|
for (k, _) in exports {
|
||||||
|
if let Ok(spec) = specifier.join(k) {
|
||||||
|
roots.push(spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut graph_permit = factory
|
||||||
|
.main_module_graph_container()
|
||||||
|
.await?
|
||||||
|
.acquire_update_permit()
|
||||||
|
.await;
|
||||||
|
let graph = graph_permit.graph_mut();
|
||||||
|
factory
|
||||||
|
.module_load_preparer()
|
||||||
|
.await?
|
||||||
|
.prepare_module_load(
|
||||||
|
graph,
|
||||||
|
&roots,
|
||||||
|
false,
|
||||||
|
deno_config::deno_json::TsTypeLib::DenoWorker,
|
||||||
|
deno_runtime::deno_permissions::PermissionsContainer::allow_all(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
2
tests/registry/jsr/@std/testing/1.0.0/bdd.ts
Normal file
2
tests/registry/jsr/@std/testing/1.0.0/bdd.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export function it(_name: string, _fn: () => void) {
|
||||||
|
}
|
1
tests/registry/jsr/@std/testing/1.0.0/types.ts
Normal file
1
tests/registry/jsr/@std/testing/1.0.0/types.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export type AssertType<A, B> = A extends B ? true : never;
|
6
tests/registry/jsr/@std/testing/1.0.0_meta.json
Normal file
6
tests/registry/jsr/@std/testing/1.0.0_meta.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"exports": {
|
||||||
|
"./bdd": "./bdd.ts",
|
||||||
|
"./types": "./types.ts"
|
||||||
|
}
|
||||||
|
}
|
8
tests/registry/jsr/@std/testing/meta.json
Normal file
8
tests/registry/jsr/@std/testing/meta.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"scope": "std",
|
||||||
|
"name": "path",
|
||||||
|
"latest": "1.0.0",
|
||||||
|
"versions": {
|
||||||
|
"1.0.0": {}
|
||||||
|
}
|
||||||
|
}
|
9
tests/specs/add/no_root_export/__test__.jsonc
Normal file
9
tests/specs/add/no_root_export/__test__.jsonc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"tempDir": true,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"args": "add @std/testing",
|
||||||
|
"output": "add.out"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
tests/specs/add/no_root_export/add.out
Normal file
5
tests/specs/add/no_root_export/add.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Add jsr:@std/testing@1.0.0
|
||||||
|
[UNORDERED_START]
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/bdd.ts
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/types.ts
|
||||||
|
[UNORDERED_END]
|
0
tests/specs/add/no_root_export/deno.json
Normal file
0
tests/specs/add/no_root_export/deno.json
Normal file
3
tests/specs/add/no_root_export/main.ts
Normal file
3
tests/specs/add/no_root_export/main.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { it } from "@std/testing/bdd";
|
||||||
|
|
||||||
|
const _it = it;
|
|
@ -3,6 +3,8 @@
|
||||||
"@std/fs/": "https://deno.land/std@0.224.0/fs/",
|
"@std/fs/": "https://deno.land/std@0.224.0/fs/",
|
||||||
"@denotest/esm-basic": "npm:@denotest/esm-basic@^1.0.0",
|
"@denotest/esm-basic": "npm:@denotest/esm-basic@^1.0.0",
|
||||||
"@denotest/add": "jsr:@denotest/add",
|
"@denotest/add": "jsr:@denotest/add",
|
||||||
"test-http": "http://localhost:4545/v1/extensionless"
|
"test-http": "http://localhost:4545/v1/extensionless",
|
||||||
|
"@std/testing": "jsr:@std/testing",
|
||||||
|
"@std/testing/": "jsr:/@std/testing/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,15 @@
|
||||||
"version": "4",
|
"version": "4",
|
||||||
"specifiers": {
|
"specifiers": {
|
||||||
"jsr:@denotest/add": "jsr:@denotest/add@1.0.0",
|
"jsr:@denotest/add": "jsr:@denotest/add@1.0.0",
|
||||||
|
"jsr:@std/testing": "jsr:@std/testing@1.0.0",
|
||||||
"npm:@denotest/esm-basic@^1.0.0": "npm:@denotest/esm-basic@1.0.0"
|
"npm:@denotest/esm-basic@^1.0.0": "npm:@denotest/esm-basic@1.0.0"
|
||||||
},
|
},
|
||||||
"jsr": {
|
"jsr": {
|
||||||
"@denotest/add@1.0.0": {
|
"@denotest/add@1.0.0": {
|
||||||
"integrity": "[WILDCARD]"
|
"integrity": "[WILDCARD]"
|
||||||
|
},
|
||||||
|
"@std/testing@1.0.0": {
|
||||||
|
"integrity": "[WILDCARD]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npm": {
|
"npm": {
|
||||||
|
@ -14,10 +18,16 @@
|
||||||
"integrity": "[WILDCARD]"
|
"integrity": "[WILDCARD]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"remote": [WILDCARD],
|
"remote": {
|
||||||
|
"http://localhost:4545/subdir/mod1.ts": "[WILDCARD]",
|
||||||
|
"http://localhost:4545/subdir/print_hello.ts": "[WILDCARD]",
|
||||||
|
"http://localhost:4545/subdir/subdir2/mod2.ts": "[WILDCARD]",
|
||||||
|
"http://localhost:4545/v1/extensionless": "[WILDCARD]"
|
||||||
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@denotest/add",
|
"jsr:@denotest/add",
|
||||||
|
"jsr:@std/testing",
|
||||||
"npm:@denotest/esm-basic@^1.0.0"
|
"npm:@denotest/esm-basic@^1.0.0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/meta.json
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/1.0.0_meta.json
|
||||||
Download http://localhost:4545/v1/extensionless
|
Download http://localhost:4545/v1/extensionless
|
||||||
Download http://localhost:4545/subdir/mod1.ts
|
Download http://localhost:4545/subdir/mod1.ts
|
||||||
Download http://localhost:4545/subdir/subdir2/mod2.ts
|
Download http://localhost:4545/subdir/subdir2/mod2.ts
|
||||||
|
@ -8,4 +10,6 @@ Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json
|
||||||
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest/esm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/bdd.ts
|
||||||
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/types.ts
|
||||||
[UNORDERED_END]
|
[UNORDERED_END]
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
Created deno.json configuration file.
|
Created deno.json configuration file.
|
||||||
Add jsr:@std/assert@1.0.0
|
|
||||||
Add jsr:@std/http@1.0.0
|
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://127.0.0.1:4250/@std/http/1.0.0_meta.json
|
Add jsr:@std/http@1.0.0
|
||||||
Download http://127.0.0.1:4250/@std/assert/1.0.0_meta.json
|
Add jsr:@std/assert@1.0.0
|
||||||
|
[UNORDERED_END]
|
||||||
|
[UNORDERED_START]
|
||||||
Download http://127.0.0.1:4250/@std/http/1.0.0/mod.ts
|
Download http://127.0.0.1:4250/@std/http/1.0.0/mod.ts
|
||||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/mod.ts
|
Download http://127.0.0.1:4250/@std/assert/1.0.0/mod.ts
|
||||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/assert_equals.ts
|
Download http://127.0.0.1:4250/@std/assert/1.0.0/assert_equals.ts
|
||||||
|
|
Loading…
Reference in a new issue