Skip to content

Commit 539ce8d

Browse files
committed
Make the lockfile work
1 parent d4dd20a commit 539ce8d

6 files changed

Lines changed: 116 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ deno_cache_dir = "0.44.0"
1717
deno_config = "0.102.0"
1818
deno_error = { version = "0.7.1", features = ["serde", "serde_json", "url"] }
1919
deno_graph = { version = "0.109.0", features = ["swc"], default-features = false }
20+
deno_lockfile = "0.54.0"
2021
deno_path_util = "0.6.4"
2122
deno_resolver = { version = "0.83.0", features = ["graph"] }
2223
serde_json = { version = "1.0.140", features = ["preserve_order"] }

rs-lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ deno_cache_dir.workspace = true
2020
deno_config.workspace = true
2121
deno_error.workspace = true
2222
deno_graph.workspace = true
23+
deno_lockfile.workspace = true
2324
deno_path_util.workspace = true
2425
deno_resolver.workspace = true
2526
deno_semver = "=0.10.0"

rs-lib/src/graph.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub struct ModuleGraphOptions<'a, TSys: WorkspaceFactorySys> {
4040
pub compiler_options_resolver: Rc<CompilerOptionsResolver>,
4141
pub cjs_tracker:
4242
Rc<deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, TSys>>,
43+
/// The project's deno lockfile, used to lock module versions and verify
44+
/// remote module checksums while building the graph.
45+
pub maybe_lockfile: Option<deno_resolver::lockfile::LockfileLockRc<TSys>>,
4346
}
4447

4548
/// Wrapper around deno_graph::ModuleGraph.
@@ -67,6 +70,15 @@ impl ModuleGraph {
6770
let capturing_analyzer =
6871
CapturingModuleAnalyzer::new(Some(Box::new(source_parser)), None);
6972
let mut graph = deno_graph::ModuleGraph::new(deno_graph::GraphKind::All);
73+
// seed the graph with the locked module versions and redirects so the
74+
// same versions Deno resolved for the project are used
75+
if let Some(lockfile) = &options.maybe_lockfile {
76+
lockfile.fill_graph(&mut graph);
77+
}
78+
let mut locker = options
79+
.maybe_lockfile
80+
.as_ref()
81+
.map(|lockfile| lockfile.as_deno_graph_locker());
7082
let graph_resolver = resolver.as_graph_resolver(
7183
&options.cjs_tracker,
7284
&scoped_jsx_import_source_config,
@@ -87,7 +99,9 @@ impl ModuleGraph {
8799
is_dynamic: false,
88100
skip_dynamic_deps: false,
89101
resolver: Some(&graph_resolver),
90-
locker: None,
102+
locker: locker
103+
.as_mut()
104+
.map(|l| l as &mut dyn deno_graph::source::Locker),
91105
module_analyzer: &capturing_analyzer,
92106
module_info_cacher: &NullModuleInfoCacher,
93107
reporter: None,

rs-lib/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ pub async fn transform(
409409
);
410410
let deno_resolver = resolver_factory.deno_resolver().await?;
411411
let cjs_tracker = resolver_factory.cjs_tracker()?.clone();
412+
let maybe_lockfile = resolver_factory
413+
.workspace_factory()
414+
.maybe_lockfile(&NullNpmPackageInfoProvider)
415+
.await?
416+
.cloned();
412417

413418
let loader = Rc::new(DenoGraphLoader::new(
414419
Rc::new(file_fetcher),
@@ -452,6 +457,7 @@ pub async fn transform(
452457
.compiler_options_resolver()?
453458
.clone(),
454459
cjs_tracker,
460+
maybe_lockfile,
455461
})
456462
.await?;
457463

@@ -647,6 +653,27 @@ pub async fn transform(
647653
})
648654
}
649655

656+
/// Provides npm package info when reading the lockfile.
657+
///
658+
/// dnt resolves npm specifiers via the specifier mappers rather than through
659+
/// the module graph, and never writes the lockfile back, so the only time this
660+
/// is consulted is when an older lockfile is migrated to the latest version in
661+
/// memory. Returning default info for each requested package is sufficient.
662+
struct NullNpmPackageInfoProvider;
663+
664+
#[async_trait::async_trait(?Send)]
665+
impl deno_lockfile::NpmPackageInfoProvider for NullNpmPackageInfoProvider {
666+
async fn get_npm_package_info(
667+
&self,
668+
values: &[deno_semver::package::PackageNv],
669+
) -> Result<
670+
Vec<deno_lockfile::Lockfile5NpmInfo>,
671+
Box<dyn std::error::Error + Send + Sync>,
672+
> {
673+
Ok(vec![Default::default(); values.len()])
674+
}
675+
}
676+
650677
fn add_shim_types_packages_to_test_environment<'a>(
651678
test_output_env: &mut TransformOutputEnvironment,
652679
all_shims: impl Iterator<Item = &'a Shim>,

rs-lib/tests/integration_test.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,77 @@ async fn npm_specifier() {
21472147
);
21482148
}
21492149

2150+
#[tokio::test]
2151+
async fn transform_uses_lockfile_remote_checksum() {
2152+
// a deno.lock with a non-matching remote checksum should cause an
2153+
// integrity error, proving the lockfile is being used
2154+
let result = TestBuilder::new()
2155+
.with_loader(|loader| {
2156+
loader
2157+
.add_local_file("/deno.json", "{}")
2158+
.add_local_file(
2159+
"/deno.lock",
2160+
concat!(
2161+
"{\n",
2162+
" \"version\": \"5\",\n",
2163+
" \"remote\": {\n",
2164+
" \"https://localhost/mod.ts\": \"0000000000000000000000000000000000000000000000000000000000000000\"\n",
2165+
" }\n",
2166+
"}\n"
2167+
),
2168+
)
2169+
.add_local_file("/mod.ts", "import 'https://localhost/mod.ts';")
2170+
.add_remote_file("https://localhost/mod.ts", "console.log(1);");
2171+
})
2172+
.transform()
2173+
.await
2174+
.err()
2175+
.unwrap();
2176+
2177+
assert!(
2178+
result
2179+
.to_string()
2180+
.to_lowercase()
2181+
.contains("integrity check failed"),
2182+
"unexpected error: {:#}",
2183+
result
2184+
);
2185+
}
2186+
2187+
#[tokio::test]
2188+
async fn transform_uses_lockfile_matching_remote_checksum() {
2189+
// a deno.lock with a matching remote checksum should transform successfully
2190+
let result = TestBuilder::new()
2191+
.with_loader(|loader| {
2192+
loader
2193+
.add_local_file("/deno.json", "{}")
2194+
.add_local_file(
2195+
"/deno.lock",
2196+
concat!(
2197+
"{\n",
2198+
" \"version\": \"5\",\n",
2199+
" \"remote\": {\n",
2200+
" \"https://localhost/mod.ts\": \"35c146f76e129477c64061bc84511e1090f3d4d8059713e6663dd4b35b1f7642\"\n",
2201+
" }\n",
2202+
"}\n"
2203+
),
2204+
)
2205+
.add_local_file("/mod.ts", "import 'https://localhost/mod.ts';")
2206+
.add_remote_file("https://localhost/mod.ts", "console.log(1);");
2207+
})
2208+
.transform()
2209+
.await
2210+
.unwrap();
2211+
2212+
assert_files!(
2213+
result.main.files,
2214+
&[
2215+
("mod.ts", "import './deps/localhost/mod.js';"),
2216+
("deps/localhost/mod.ts", "console.log(1);"),
2217+
]
2218+
);
2219+
}
2220+
21502221
fn get_shim_file_text(mut text: String) -> String {
21512222
text.push('\n');
21522223
text.push_str(

0 commit comments

Comments
 (0)