mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
fix(check): should bust check cache when json module or npm resolution changes (#19941)
A small part of #19928.
This commit is contained in:
parent
53e077133f
commit
cf16df00d9
17 changed files with 223 additions and 58 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -1035,9 +1035,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_doc"
|
name = "deno_doc"
|
||||||
version = "0.63.1"
|
version = "0.64.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "499936300106c3c67caae87e29def3df5ea9385db6ed7428f154972f70ed39fa"
|
checksum = "c25d38dc94e4c2190bc7a1851790dd142fd0068888b3a26a1acb958db5113829"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"deno_ast",
|
"deno_ast",
|
||||||
|
@ -1053,9 +1053,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_emit"
|
name = "deno_emit"
|
||||||
version = "0.24.0"
|
version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6bdc024d2c1e5ec56ef6f923be2c2fea4662d596b0a68074ccf89991b38a05e7"
|
checksum = "0ef00ad78bc75e7f35a01bd4b5c32a97018eebc55c311e4b287e158a29021348"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
|
@ -1121,9 +1121,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_graph"
|
name = "deno_graph"
|
||||||
version = "0.49.0"
|
version = "0.50.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7e07fdff6c7dc1a9a7c03ce69435fda4b53641d2d6d3d3ed6d29cf67fefd3ea"
|
checksum = "73502c4d93a17f259b6edee6d5a5ba063e2fcdcdaeb6ca1c6953129cc14be6a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"data-url",
|
"data-url",
|
||||||
|
@ -1330,9 +1330,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_npm"
|
name = "deno_npm"
|
||||||
version = "0.9.1"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "371ef0398b5b5460d66b78a958d5015658e198ad3a29fb9ce329459272fd29aa"
|
checksum = "fa5d1097de53e8ce3316d3e44095e253719ae367cf7478263f83082f44dddabf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1340,7 +1340,6 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
"monch",
|
"monch",
|
||||||
"once_cell",
|
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
@ -1424,11 +1423,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_semver"
|
name = "deno_semver"
|
||||||
version = "0.2.2"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "242c8ad9f4ce614ec0fa2e6b3d834f2662ce024ca78e9ed4c58d812cbfc3e41d"
|
checksum = "96f99990457915af1f444900003ffd5a9d3ab2e5337b06d681e56ca371b3e11f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"monch",
|
"monch",
|
||||||
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"url",
|
"url",
|
||||||
|
@ -1944,9 +1944,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eszip"
|
name = "eszip"
|
||||||
version = "0.45.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbf5a0f47c2e73cb7631accc282ebda9bc9ed9b2034abfddec983dc9c8f78e7a"
|
checksum = "58d2382a70396ccffd260adb879ed9f954c45457e8075830c7d4ec30c6dc8ad2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.21.0",
|
"base64 0.21.0",
|
||||||
|
|
|
@ -51,8 +51,8 @@ deno_bench_util = { version = "0.107.0", path = "./bench_util" }
|
||||||
test_util = { path = "./test_util" }
|
test_util = { path = "./test_util" }
|
||||||
deno_lockfile = "0.14.1"
|
deno_lockfile = "0.14.1"
|
||||||
deno_media_type = { version = "0.1.0", features = ["module_specifier"] }
|
deno_media_type = { version = "0.1.0", features = ["module_specifier"] }
|
||||||
deno_npm = "0.9.1"
|
deno_npm = "0.10.1"
|
||||||
deno_semver = "0.2.2"
|
deno_semver = "0.3.0"
|
||||||
|
|
||||||
# exts
|
# exts
|
||||||
deno_broadcast_channel = { version = "0.107.0", path = "./ext/broadcast_channel" }
|
deno_broadcast_channel = { version = "0.107.0", path = "./ext/broadcast_channel" }
|
||||||
|
|
|
@ -42,16 +42,16 @@ winres.workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
||||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||||
deno_doc = "=0.63.1"
|
deno_doc = "=0.64.0"
|
||||||
deno_emit = "=0.24.0"
|
deno_emit = "=0.25.0"
|
||||||
deno_graph = "=0.49.0"
|
deno_graph = "=0.50.0"
|
||||||
deno_lint = { version = "=0.49.0", features = ["docs"] }
|
deno_lint = { version = "=0.49.0", features = ["docs"] }
|
||||||
deno_lockfile.workspace = true
|
deno_lockfile.workspace = true
|
||||||
deno_npm.workspace = true
|
deno_npm.workspace = true
|
||||||
deno_runtime = { workspace = true, features = ["dont_create_runtime_snapshot", "include_js_files_for_snapshotting"] }
|
deno_runtime = { workspace = true, features = ["dont_create_runtime_snapshot", "include_js_files_for_snapshotting"] }
|
||||||
deno_semver.workspace = true
|
deno_semver.workspace = true
|
||||||
deno_task_shell = "=0.13.1"
|
deno_task_shell = "=0.13.1"
|
||||||
eszip = "=0.45.0"
|
eszip = "=0.48.0"
|
||||||
napi_sym.workspace = true
|
napi_sym.workspace = true
|
||||||
|
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
|
|
|
@ -85,7 +85,7 @@ pub fn get_local_package_json_version_reqs(
|
||||||
match result {
|
match result {
|
||||||
Ok(version_req) => Ok(NpmPackageReq {
|
Ok(version_req) => Ok(NpmPackageReq {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
version_req: Some(version_req),
|
version_req,
|
||||||
}),
|
}),
|
||||||
Err(err) => Err(PackageJsonDepValueParseError::Specifier(err)),
|
Err(err) => Err(PackageJsonDepValueParseError::Specifier(err)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -249,6 +250,10 @@ impl NpmResolution {
|
||||||
Ok(nv)
|
Ok(nv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn package_reqs(&self) -> HashMap<NpmPackageReq, NpmPackageNv> {
|
||||||
|
self.snapshot.read().package_reqs().clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn all_system_packages(
|
pub fn all_system_packages(
|
||||||
&self,
|
&self,
|
||||||
system_info: &NpmSystemInfo,
|
system_info: &NpmSystemInfo,
|
||||||
|
@ -303,45 +308,44 @@ async fn add_package_reqs_to_snapshot(
|
||||||
get_new_snapshot: impl Fn() -> NpmResolutionSnapshot,
|
get_new_snapshot: impl Fn() -> NpmResolutionSnapshot,
|
||||||
) -> Result<NpmResolutionSnapshot, AnyError> {
|
) -> Result<NpmResolutionSnapshot, AnyError> {
|
||||||
let snapshot = get_new_snapshot();
|
let snapshot = get_new_snapshot();
|
||||||
if !snapshot.has_pending()
|
let snapshot = if !snapshot.has_pending()
|
||||||
&& package_reqs
|
&& package_reqs
|
||||||
.iter()
|
.iter()
|
||||||
.all(|req| snapshot.package_reqs().contains_key(req))
|
.all(|req| snapshot.package_reqs().contains_key(req))
|
||||||
{
|
{
|
||||||
log::debug!("Snapshot already up to date. Skipping pending resolution.");
|
log::debug!("Snapshot already up to date. Skipping pending resolution.");
|
||||||
return Ok(snapshot);
|
snapshot
|
||||||
}
|
} else {
|
||||||
|
let pending_resolver = get_npm_pending_resolver(api);
|
||||||
|
let result = pending_resolver
|
||||||
|
.resolve_pending(snapshot, package_reqs)
|
||||||
|
.await;
|
||||||
|
api.clear_memory_cache();
|
||||||
|
match result {
|
||||||
|
Ok(snapshot) => snapshot,
|
||||||
|
Err(NpmResolutionError::Resolution(err)) if api.mark_force_reload() => {
|
||||||
|
log::debug!("{err:#}");
|
||||||
|
log::debug!("npm resolution failed. Trying again...");
|
||||||
|
|
||||||
let pending_resolver = get_npm_pending_resolver(api);
|
// try again
|
||||||
let result = pending_resolver
|
let snapshot = get_new_snapshot();
|
||||||
.resolve_pending(snapshot, package_reqs)
|
let result = pending_resolver
|
||||||
.await;
|
.resolve_pending(snapshot, package_reqs)
|
||||||
api.clear_memory_cache();
|
.await;
|
||||||
let snapshot = match result {
|
api.clear_memory_cache();
|
||||||
Ok(snapshot) => snapshot,
|
// now surface the result after clearing the cache
|
||||||
Err(NpmResolutionError::Resolution(err)) if api.mark_force_reload() => {
|
result?
|
||||||
log::debug!("{err:#}");
|
}
|
||||||
log::debug!("npm resolution failed. Trying again...");
|
Err(err) => return Err(err.into()),
|
||||||
|
|
||||||
// try again
|
|
||||||
let snapshot = get_new_snapshot();
|
|
||||||
let result = pending_resolver
|
|
||||||
.resolve_pending(snapshot, package_reqs)
|
|
||||||
.await;
|
|
||||||
api.clear_memory_cache();
|
|
||||||
// now surface the result after clearing the cache
|
|
||||||
result?
|
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(lockfile_mutex) = maybe_lockfile {
|
if let Some(lockfile_mutex) = maybe_lockfile {
|
||||||
let mut lockfile = lockfile_mutex.lock();
|
let mut lockfile = lockfile_mutex.lock();
|
||||||
populate_lockfile_from_snapshot(&mut lockfile, &snapshot)?;
|
populate_lockfile_from_snapshot(&mut lockfile, &snapshot)?;
|
||||||
Ok(snapshot)
|
|
||||||
} else {
|
|
||||||
Ok(snapshot)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_npm_pending_resolver(
|
fn get_npm_pending_resolver(
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod common;
|
||||||
mod global;
|
mod global;
|
||||||
mod local;
|
mod local;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -153,7 +154,7 @@ impl CliNpmResolver {
|
||||||
let Some(cache_folder_id) = self
|
let Some(cache_folder_id) = self
|
||||||
.fs_resolver
|
.fs_resolver
|
||||||
.resolve_package_cache_folder_id_from_specifier(specifier)? else {
|
.resolve_package_cache_folder_id_from_specifier(specifier)? else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
self
|
self
|
||||||
|
@ -229,6 +230,10 @@ return Ok(None);
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn package_reqs(&self) -> HashMap<NpmPackageReq, NpmPackageNv> {
|
||||||
|
self.resolution.package_reqs()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self) -> NpmResolutionSnapshot {
|
pub fn snapshot(&self) -> NpmResolutionSnapshot {
|
||||||
self.resolution.snapshot()
|
self.resolution.snapshot()
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = module?;
|
let module = module?;
|
||||||
let code = module.source().await.unwrap_or_default();
|
let code = module.source().await.unwrap_or_else(|| Arc::new([]));
|
||||||
let code = std::str::from_utf8(&code)
|
let code = std::str::from_utf8(&code)
|
||||||
.map_err(|_| type_error("Module source is not utf-8"))?
|
.map_err(|_| type_error("Module source is not utf-8"))?
|
||||||
.to_owned()
|
.to_owned()
|
||||||
|
@ -204,6 +204,9 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
eszip::ModuleKind::Jsonc => {
|
eszip::ModuleKind::Jsonc => {
|
||||||
return Err(type_error("jsonc modules not supported"))
|
return Err(type_error("jsonc modules not supported"))
|
||||||
}
|
}
|
||||||
|
eszip::ModuleKind::OpaqueData => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
code,
|
code,
|
||||||
&module_specifier,
|
&module_specifier,
|
||||||
|
|
|
@ -307,3 +307,80 @@ fn check_error_in_dep_then_fix() {
|
||||||
output.assert_matches_text("Check [WILDCARD]main.ts\nerror: TS234[WILDCARD]");
|
output.assert_matches_text("Check [WILDCARD]main.ts\nerror: TS234[WILDCARD]");
|
||||||
output.assert_exit_code(1);
|
output.assert_exit_code(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_module_check_then_error() {
|
||||||
|
let test_context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let temp_dir = test_context.temp_dir();
|
||||||
|
let correct_code = "{ \"foo\": \"bar\" }";
|
||||||
|
let incorrect_code = "{ \"foo2\": \"bar\" }";
|
||||||
|
|
||||||
|
temp_dir.write(
|
||||||
|
"main.ts",
|
||||||
|
"import test from './test.json' assert { type: 'json' }; console.log(test.foo);\n",
|
||||||
|
);
|
||||||
|
temp_dir.write("test.json", correct_code);
|
||||||
|
|
||||||
|
let check_command = test_context.new_command().args_vec(["check", "main.ts"]);
|
||||||
|
|
||||||
|
check_command.run().assert_exit_code(0).skip_output_check();
|
||||||
|
|
||||||
|
temp_dir.write("test.json", incorrect_code);
|
||||||
|
check_command
|
||||||
|
.run()
|
||||||
|
.assert_matches_text("Check [WILDCARD]main.ts\nerror: TS2551[WILDCARD]")
|
||||||
|
.assert_exit_code(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn npm_module_check_then_error() {
|
||||||
|
let test_context = TestContextBuilder::new()
|
||||||
|
.use_temp_cwd()
|
||||||
|
.add_npm_env_vars()
|
||||||
|
.use_http_server()
|
||||||
|
.build();
|
||||||
|
let temp_dir = test_context.temp_dir();
|
||||||
|
temp_dir.write("deno.json", "{}"); // so the lockfile gets loaded
|
||||||
|
|
||||||
|
// get the lockfiles values first (this is necessary because the test
|
||||||
|
// server generates different tarballs based on the operating system)
|
||||||
|
test_context
|
||||||
|
.new_command()
|
||||||
|
.args_vec([
|
||||||
|
"cache",
|
||||||
|
"npm:@denotest/breaking-change-between-versions@1.0.0",
|
||||||
|
"npm:@denotest/breaking-change-between-versions@2.0.0",
|
||||||
|
])
|
||||||
|
.run()
|
||||||
|
.skip_output_check();
|
||||||
|
let lockfile = temp_dir.path().join("deno.lock");
|
||||||
|
let mut lockfile_content =
|
||||||
|
lockfile.read_json::<deno_lockfile::LockfileContent>();
|
||||||
|
|
||||||
|
// make the specifier resolve to version 1
|
||||||
|
lockfile_content.npm.specifiers.insert(
|
||||||
|
"@denotest/breaking-change-between-versions".to_string(),
|
||||||
|
"@denotest/breaking-change-between-versions@1.0.0".to_string(),
|
||||||
|
);
|
||||||
|
lockfile.write_json(&lockfile_content);
|
||||||
|
temp_dir.write(
|
||||||
|
"main.ts",
|
||||||
|
"import { oldName } from 'npm:@denotest/breaking-change-between-versions'; console.log(oldName());\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
let check_command = test_context.new_command().args_vec(["check", "main.ts"]);
|
||||||
|
check_command.run().assert_exit_code(0).skip_output_check();
|
||||||
|
|
||||||
|
// now update the lockfile to use version 2 instead, which should cause a
|
||||||
|
// type checking error because the oldName no longer exists
|
||||||
|
lockfile_content.npm.specifiers.insert(
|
||||||
|
"@denotest/breaking-change-between-versions".to_string(),
|
||||||
|
"@denotest/breaking-change-between-versions@2.0.0".to_string(),
|
||||||
|
);
|
||||||
|
lockfile.write_json(&lockfile_content);
|
||||||
|
|
||||||
|
check_command
|
||||||
|
.run()
|
||||||
|
.assert_matches_text("Check [WILDCARD]main.ts\nerror: TS2305[WILDCARD]has no exported member 'oldName'[WILDCARD]")
|
||||||
|
.assert_exit_code(1);
|
||||||
|
}
|
||||||
|
|
1
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/1.0.0/index.d.ts
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/1.0.0/index.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export function oldName(): 1;
|
3
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/1.0.0/index.js
vendored
Normal file
3
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/1.0.0/index.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export function newName() {
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "@denotest/breaking-change-between-versions",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js"
|
||||||
|
}
|
1
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/2.0.0/index.d.ts
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/2.0.0/index.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export function newName(): 2;
|
3
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/2.0.0/index.js
vendored
Normal file
3
cli/tests/testdata/npm/registry/@denotest/breaking-change-between-versions/2.0.0/index.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export function newName() {
|
||||||
|
return 2;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "@denotest/breaking-change-between-versions",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js"
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -10,6 +11,8 @@ use deno_graph::Module;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
use deno_runtime::colors;
|
use deno_runtime::colors;
|
||||||
use deno_runtime::deno_node::NodeResolver;
|
use deno_runtime::deno_node::NodeResolver;
|
||||||
|
use deno_semver::npm::NpmPackageNv;
|
||||||
|
use deno_semver::npm::NpmPackageReq;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
@ -93,7 +96,12 @@ impl TypeChecker {
|
||||||
let debug = self.cli_options.log_level() == Some(log::Level::Debug);
|
let debug = self.cli_options.log_level() == Some(log::Level::Debug);
|
||||||
let cache = TypeCheckCache::new(self.caches.type_checking_cache_db());
|
let cache = TypeCheckCache::new(self.caches.type_checking_cache_db());
|
||||||
let check_js = ts_config.get_check_js();
|
let check_js = ts_config.get_check_js();
|
||||||
let check_hash = match get_check_hash(&graph, type_check_mode, &ts_config) {
|
let check_hash = match get_check_hash(
|
||||||
|
&graph,
|
||||||
|
self.npm_resolver.package_reqs(),
|
||||||
|
type_check_mode,
|
||||||
|
&ts_config,
|
||||||
|
) {
|
||||||
CheckHashResult::NoFiles => return Ok(()),
|
CheckHashResult::NoFiles => return Ok(()),
|
||||||
CheckHashResult::Hash(hash) => hash,
|
CheckHashResult::Hash(hash) => hash,
|
||||||
};
|
};
|
||||||
|
@ -186,6 +194,7 @@ enum CheckHashResult {
|
||||||
/// be used to tell
|
/// be used to tell
|
||||||
fn get_check_hash(
|
fn get_check_hash(
|
||||||
graph: &ModuleGraph,
|
graph: &ModuleGraph,
|
||||||
|
package_reqs: HashMap<NpmPackageReq, NpmPackageNv>,
|
||||||
type_check_mode: TypeCheckMode,
|
type_check_mode: TypeCheckMode,
|
||||||
ts_config: &TsConfig,
|
ts_config: &TsConfig,
|
||||||
) -> CheckHashResult {
|
) -> CheckHashResult {
|
||||||
|
@ -198,11 +207,10 @@ fn get_check_hash(
|
||||||
hasher.write(&ts_config.as_bytes());
|
hasher.write(&ts_config.as_bytes());
|
||||||
|
|
||||||
let check_js = ts_config.get_check_js();
|
let check_js = ts_config.get_check_js();
|
||||||
let mut sorted_modules = graph.modules().collect::<Vec<_>>();
|
|
||||||
sorted_modules.sort_by_key(|m| m.specifier().as_str()); // make it deterministic
|
|
||||||
let mut has_file = false;
|
let mut has_file = false;
|
||||||
let mut has_file_to_type_check = false;
|
let mut has_file_to_type_check = false;
|
||||||
for module in sorted_modules {
|
// this iterator of modules is already deterministic, so no need to sort it
|
||||||
|
for module in graph.modules() {
|
||||||
match module {
|
match module {
|
||||||
Module::Esm(module) => {
|
Module::Esm(module) => {
|
||||||
let ts_check = has_ts_check(module.media_type, &module.source);
|
let ts_check = has_ts_check(module.media_type, &module.source);
|
||||||
|
@ -240,15 +248,36 @@ fn get_check_hash(
|
||||||
hasher.write_str(module.specifier.as_str());
|
hasher.write_str(module.specifier.as_str());
|
||||||
hasher.write_str(&module.source);
|
hasher.write_str(&module.source);
|
||||||
}
|
}
|
||||||
Module::Json(_)
|
Module::Node(_) => {
|
||||||
| Module::External(_)
|
// the @types/node package will be in the resolved
|
||||||
| Module::Node(_)
|
// snapshot below so don't bother including it here
|
||||||
| Module::Npm(_) => {
|
}
|
||||||
// ignore
|
Module::Npm(_) => {
|
||||||
|
// don't bother adding this specifier to the hash
|
||||||
|
// because what matters is the resolved npm snapshot,
|
||||||
|
// which is hashed below
|
||||||
|
}
|
||||||
|
Module::Json(module) => {
|
||||||
|
has_file_to_type_check = true;
|
||||||
|
hasher.write_str(module.specifier.as_str());
|
||||||
|
hasher.write_str(&module.source);
|
||||||
|
}
|
||||||
|
Module::External(module) => {
|
||||||
|
hasher.write_str(module.specifier.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if any of the top level npm pckages have changed. We could go
|
||||||
|
// further and check all the individual npm packages, but that's
|
||||||
|
// probably overkill.
|
||||||
|
let mut package_reqs = package_reqs.into_iter().collect::<Vec<_>>();
|
||||||
|
package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism
|
||||||
|
for (pkg_req, pkg_nv) in package_reqs {
|
||||||
|
hasher.write_hashable(&pkg_req);
|
||||||
|
hasher.write_hashable(&pkg_nv);
|
||||||
|
}
|
||||||
|
|
||||||
if !has_file || !check_js && !has_file_to_type_check {
|
if !has_file || !check_js && !has_file_to_type_check {
|
||||||
// no files to type check
|
// no files to type check
|
||||||
CheckHashResult::NoFiles
|
CheckHashResult::NoFiles
|
||||||
|
|
|
@ -28,6 +28,7 @@ use deno_core::ModuleSpecifier;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::RuntimeOptions;
|
use deno_core::RuntimeOptions;
|
||||||
use deno_core::Snapshot;
|
use deno_core::Snapshot;
|
||||||
|
use deno_graph::GraphKind;
|
||||||
use deno_graph::Module;
|
use deno_graph::Module;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
use deno_graph::ResolutionResolved;
|
use deno_graph::ResolutionResolved;
|
||||||
|
@ -319,7 +320,7 @@ pub struct Response {
|
||||||
pub stats: Stats,
|
pub stats: Stats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
struct State {
|
struct State {
|
||||||
hash_data: u64,
|
hash_data: u64,
|
||||||
graph: Arc<ModuleGraph>,
|
graph: Arc<ModuleGraph>,
|
||||||
|
@ -331,6 +332,21 @@ struct State {
|
||||||
current_dir: PathBuf,
|
current_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for State {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
hash_data: Default::default(),
|
||||||
|
graph: Arc::new(ModuleGraph::new(GraphKind::All)),
|
||||||
|
maybe_tsbuildinfo: Default::default(),
|
||||||
|
maybe_response: Default::default(),
|
||||||
|
maybe_node_resolver: Default::default(),
|
||||||
|
remapped_specifiers: Default::default(),
|
||||||
|
root_map: Default::default(),
|
||||||
|
current_dir: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
graph: Arc<ModuleGraph>,
|
graph: Arc<ModuleGraph>,
|
||||||
|
|
|
@ -10,6 +10,8 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lsp_types::Url;
|
use lsp_types::Url;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::assertions::assert_wildcard_match;
|
use crate::assertions::assert_wildcard_match;
|
||||||
|
|
||||||
|
@ -110,6 +112,10 @@ impl PathRef {
|
||||||
.with_context(|| format!("Could not read file: {}", self))
|
.with_context(|| format!("Could not read file: {}", self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_json<TValue: DeserializeOwned>(&self) -> TValue {
|
||||||
|
serde_json::from_str(&self.read_to_string()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rename(&self, to: impl AsRef<Path>) {
|
pub fn rename(&self, to: impl AsRef<Path>) {
|
||||||
fs::rename(self, self.join(to)).unwrap();
|
fs::rename(self, self.join(to)).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -118,6 +124,11 @@ impl PathRef {
|
||||||
fs::write(self, text.as_ref()).unwrap();
|
fs::write(self, text.as_ref()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_json<TValue: Serialize>(&self, value: &TValue) {
|
||||||
|
let text = serde_json::to_string_pretty(value).unwrap();
|
||||||
|
self.write(text);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn symlink_dir(
|
pub fn symlink_dir(
|
||||||
&self,
|
&self,
|
||||||
oldpath: impl AsRef<Path>,
|
oldpath: impl AsRef<Path>,
|
||||||
|
|
Loading…
Reference in a new issue