From 3946956b8cbda33b84d6f9dc80c96f09c3afcd37 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:19:37 -0800 Subject: [PATCH] fix(lockfile): include dependencies listed in external import map in lockfile (#27337) --- cli/args/deno_json.rs | 9 ++++ cli/args/lockfile.rs | 9 +++- cli/args/mod.rs | 48 +++++++++++++++++-- cli/lsp/language_server.rs | 1 + .../external_import_map/__test__.jsonc | 10 ++++ .../lockfile/external_import_map/deno.json | 3 ++ .../external_import_map/deno.lock.out | 17 +++++++ .../external_import_map/import_map.json | 10 ++++ .../lockfile/external_import_map/main.ts | 2 + 9 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 tests/specs/lockfile/external_import_map/__test__.jsonc create mode 100644 tests/specs/lockfile/external_import_map/deno.json create mode 100644 tests/specs/lockfile/external_import_map/deno.lock.out create mode 100644 tests/specs/lockfile/external_import_map/import_map.json create mode 100644 tests/specs/lockfile/external_import_map/main.ts diff --git a/cli/args/deno_json.rs b/cli/args/deno_json.rs index c2ba31fd36..8853107eef 100644 --- a/cli/args/deno_json.rs +++ b/cli/args/deno_json.rs @@ -64,6 +64,15 @@ impl<'a> deno_config::fs::DenoConfigFs for DenoConfigFsAdapter<'a> { } } +pub fn import_map_deps( + import_map: &serde_json::Value, +) -> HashSet { + let values = imports_values(import_map.get("imports")) + .into_iter() + .chain(scope_values(import_map.get("scopes"))); + values_to_set(values) +} + pub fn deno_json_deps( config: &deno_config::deno_json::ConfigFile, ) -> HashSet { diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index 74eab78f1c..1075f93a6f 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -9,11 +9,13 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; use deno_core::parking_lot::MutexGuard; +use deno_core::serde_json; use deno_lockfile::WorkspaceMemberConfig; use deno_package_json::PackageJsonDepValue; use deno_runtime::deno_node::PackageJson; use deno_semver::jsr::JsrDepPackageReq; +use crate::args::deno_json::import_map_deps; use crate::cache; use crate::util::fs::atomic_write_file_with_retries; use crate::Flags; @@ -101,6 +103,7 @@ impl CliLockfile { pub fn discover( flags: &Flags, workspace: &Workspace, + maybe_external_import_map: Option<&serde_json::Value>, ) -> Result, AnyError> { fn pkg_json_deps( maybe_pkg_json: Option<&PackageJson>, @@ -171,7 +174,11 @@ impl CliLockfile { let config = deno_lockfile::WorkspaceConfig { root: WorkspaceMemberConfig { package_json_deps: pkg_json_deps(root_folder.pkg_json.as_deref()), - dependencies: deno_json_deps(root_folder.deno_json.as_deref()), + dependencies: if let Some(map) = maybe_external_import_map { + import_map_deps(map) + } else { + deno_json_deps(root_folder.deno_json.as_deref()) + }, }, members: workspace .config_folders() diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 71f79e12e0..450aa11652 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -808,6 +808,7 @@ pub struct CliOptions { maybe_node_modules_folder: Option, npmrc: Arc, maybe_lockfile: Option>, + maybe_external_import_map: Option<(PathBuf, serde_json::Value)>, overrides: CliOptionOverrides, pub start_dir: Arc, pub deno_dir_provider: Arc, @@ -821,6 +822,7 @@ impl CliOptions { npmrc: Arc, start_dir: Arc, force_global_cache: bool, + maybe_external_import_map: Option<(PathBuf, serde_json::Value)>, ) -> Result { if let Some(insecure_allowlist) = flags.unsafely_ignore_certificate_errors.as_ref() @@ -858,6 +860,7 @@ impl CliOptions { maybe_node_modules_folder, overrides: Default::default(), main_module_cell: std::sync::OnceLock::new(), + maybe_external_import_map, start_dir, deno_dir_provider, }) @@ -933,7 +936,33 @@ impl CliOptions { let (npmrc, _) = discover_npmrc_from_workspace(&start_dir.workspace)?; - let maybe_lock_file = CliLockfile::discover(&flags, &start_dir.workspace)?; + fn load_external_import_map( + deno_json: &ConfigFile, + ) -> Result, AnyError> { + if !deno_json.is_an_import_map() { + if let Some(path) = deno_json.to_import_map_path()? { + let contents = std::fs::read_to_string(&path).with_context(|| { + format!("Unable to read import map at '{}'", path.display()) + })?; + let map = serde_json::from_str(&contents)?; + return Ok(Some((path, map))); + } + } + Ok(None) + } + + let external_import_map = + if let Some(deno_json) = start_dir.workspace.root_deno_json() { + load_external_import_map(deno_json)? + } else { + None + }; + + let maybe_lock_file = CliLockfile::discover( + &flags, + &start_dir.workspace, + external_import_map.as_ref().map(|(_, v)| v), + )?; log::debug!("Finished config loading."); @@ -944,6 +973,7 @@ impl CliOptions { npmrc, Arc::new(start_dir), false, + external_import_map, ) } @@ -1064,7 +1094,7 @@ impl CliOptions { file_fetcher: &FileFetcher, pkg_json_dep_resolution: PackageJsonDepResolution, ) -> Result { - let overrode_no_import_map = self + let overrode_no_import_map: bool = self .overrides .import_map_specifier .as_ref() @@ -1092,7 +1122,19 @@ impl CliOptions { value, }) } - None => None, + None => { + if let Some((path, import_map)) = + self.maybe_external_import_map.as_ref() + { + let path_url = deno_path_util::url_from_file_path(path)?; + Some(deno_config::workspace::SpecifiedImportMap { + base_url: path_url, + value: import_map.clone(), + }) + } else { + None + } + } } }; Ok(self.workspace().create_resolver( diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 3c4cb0930e..839d28469e 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -3676,6 +3676,7 @@ impl Inner { .unwrap_or_else(create_default_npmrc), workspace, force_global_cache, + None, )?; let open_docs = self.documents.documents(DocumentsFilter::OpenDiagnosable); diff --git a/tests/specs/lockfile/external_import_map/__test__.jsonc b/tests/specs/lockfile/external_import_map/__test__.jsonc new file mode 100644 index 0000000000..2bdffed334 --- /dev/null +++ b/tests/specs/lockfile/external_import_map/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "run -A main.ts", + "output": "[WILDCARD]" + }, { + "args": ["eval", "console.log(Deno.readTextFileSync('deno.lock').trim())"], + "output": "deno.lock.out" + }] +} diff --git a/tests/specs/lockfile/external_import_map/deno.json b/tests/specs/lockfile/external_import_map/deno.json new file mode 100644 index 0000000000..ee44ba9472 --- /dev/null +++ b/tests/specs/lockfile/external_import_map/deno.json @@ -0,0 +1,3 @@ +{ + "importMap": "import_map.json" +} diff --git a/tests/specs/lockfile/external_import_map/deno.lock.out b/tests/specs/lockfile/external_import_map/deno.lock.out new file mode 100644 index 0000000000..c811061125 --- /dev/null +++ b/tests/specs/lockfile/external_import_map/deno.lock.out @@ -0,0 +1,17 @@ +{ + "version": "4", + "specifiers": { + "jsr:@denotest/add@1.0.0": "1.0.0" + }, + "jsr": { + "@denotest/add@1.0.0": { + "integrity": "[WILDLINE]" + } + }, + "workspace": { + "dependencies": [ + "jsr:@denotest/add@1.0.0", + "npm:@denotest/esm-basic@1.0.0" + ] + } +} diff --git a/tests/specs/lockfile/external_import_map/import_map.json b/tests/specs/lockfile/external_import_map/import_map.json new file mode 100644 index 0000000000..069b294ce4 --- /dev/null +++ b/tests/specs/lockfile/external_import_map/import_map.json @@ -0,0 +1,10 @@ +{ + "imports": { + "@denotest/add": "jsr:@denotest/add@1.0.0" + }, + "scopes": { + "/foo/": { + "@denotest/esm-basic": "npm:@denotest/esm-basic@1.0.0" + } + } +} diff --git a/tests/specs/lockfile/external_import_map/main.ts b/tests/specs/lockfile/external_import_map/main.ts new file mode 100644 index 0000000000..b75bbc03ed --- /dev/null +++ b/tests/specs/lockfile/external_import_map/main.ts @@ -0,0 +1,2 @@ +import { add } from "@denotest/add"; +console.log(add(1, 2));