1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00

Merge branch 'main' of github.com:denoland/deno into sqlite_node_cppgc

This commit is contained in:
Divy Srivastava 2024-12-31 22:36:10 +05:30
commit 8b030f3247
273 changed files with 17921 additions and 6821 deletions

View file

@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
// Bump this number when you want to purge the cache. // Bump this number when you want to purge the cache.
// Note: the tools/release/01_bump_crate_versions.ts script will update this version // Note: the tools/release/01_bump_crate_versions.ts script will update this version
// automatically via regex, so ensure that this line maintains this format. // automatically via regex, so ensure that this line maintains this format.
const cacheVersion = 30; const cacheVersion = 32;
const ubuntuX86Runner = "ubuntu-24.04"; const ubuntuX86Runner = "ubuntu-24.04";
const ubuntuX86XlRunner = "ubuntu-24.04-xl"; const ubuntuX86XlRunner = "ubuntu-24.04-xl";

View file

@ -184,8 +184,8 @@ jobs:
~/.cargo/registry/index ~/.cargo/registry/index
~/.cargo/registry/cache ~/.cargo/registry/cache
~/.cargo/git/db ~/.cargo/git/db
key: '30-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' key: '32-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '30-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-' restore-keys: '32-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-'
if: '!(matrix.skip)' if: '!(matrix.skip)'
- uses: dsherret/rust-toolchain-file@v1 - uses: dsherret/rust-toolchain-file@v1
if: '!(matrix.skip)' if: '!(matrix.skip)'
@ -379,7 +379,7 @@ jobs:
!./target/*/*.zip !./target/*/*.zip
!./target/*/*.tar.gz !./target/*/*.tar.gz
key: never_saved key: never_saved
restore-keys: '30-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' restore-keys: '32-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
- name: Apply and update mtime cache - name: Apply and update mtime cache
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
uses: ./.github/mtime_cache uses: ./.github/mtime_cache
@ -689,7 +689,7 @@ jobs:
!./target/*/gn_root !./target/*/gn_root
!./target/*/*.zip !./target/*/*.zip
!./target/*/*.tar.gz !./target/*/*.tar.gz
key: '30-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' key: '32-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
publish-canary: publish-canary:
name: publish canary name: publish canary
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04

350
Cargo.lock generated
View file

@ -39,9 +39,9 @@ dependencies = [
[[package]] [[package]]
name = "aead-gcm-stream" name = "aead-gcm-stream"
version = "0.3.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4947a169074c7e038fa43051d1c4e073f4488b0e4b0a30658f1e1a1b06449ce8" checksum = "e70c8dec860340effb00f6945c49c0daaa6dac963602750db862eabb74bf7886"
dependencies = [ dependencies = [
"aead", "aead",
"aes", "aes",
@ -380,7 +380,7 @@ dependencies = [
"rustversion", "rustversion",
"serde", "serde",
"sync_wrapper", "sync_wrapper",
"tower", "tower 0.4.13",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
] ]
@ -596,9 +596,9 @@ dependencies = [
[[package]] [[package]]
name = "boxed_error" name = "boxed_error"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69aae56aaf59d1994b902ed5c0c79024012bdc2426741def75a635999a030e7e" checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.87", "syn 2.0.87",
@ -670,13 +670,35 @@ checksum = "1bf2a5fb3207c12b5d208ebc145f967fea5cac41a021c37417ccc31ba40f39ee"
[[package]] [[package]]
name = "capacity_builder" name = "capacity_builder"
version = "0.1.1" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab97838e07d98bdddf1e7e191ffe3c718cba7477c0b6607fdfb96ecd696202df" checksum = "58ec49028cb308564429cd8fac4ef21290067a0afe8f5955330a8d487d0d790c"
dependencies = [ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "capacity_builder"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6"
dependencies = [
"capacity_builder_macros",
"ecow",
"hipstr",
"itoa",
]
[[package]]
name = "capacity_builder_macros"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5"
dependencies = [
"quote",
"syn 2.0.87",
]
[[package]] [[package]]
name = "caseless" name = "caseless"
version = "0.2.1" version = "0.2.1"
@ -728,6 +750,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.37" version = "0.4.37"
@ -839,6 +867,7 @@ dependencies = [
"regex", "regex",
"reqwest", "reqwest",
"serde", "serde",
"sys_traits",
"test_server", "test_server",
"tokio", "tokio",
"url", "url",
@ -1193,9 +1222,9 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "data-url" name = "data-url"
version = "0.3.0" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b319d1b62ffbd002e057f36bebd1f42b9f97927c9577461d855f3513c4289f" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
[[package]] [[package]]
name = "debug-ignore" name = "debug-ignore"
@ -1221,8 +1250,10 @@ dependencies = [
"async-trait", "async-trait",
"base64 0.21.7", "base64 0.21.7",
"bincode", "bincode",
"boxed_error",
"bytes", "bytes",
"cache_control", "cache_control",
"capacity_builder 0.5.0",
"chrono", "chrono",
"clap", "clap",
"clap_complete", "clap_complete",
@ -1237,13 +1268,14 @@ dependencies = [
"deno_config", "deno_config",
"deno_core", "deno_core",
"deno_doc", "deno_doc",
"deno_error",
"deno_graph", "deno_graph",
"deno_lint", "deno_lint",
"deno_lockfile", "deno_lockfile",
"deno_npm", "deno_npm",
"deno_npm_cache", "deno_npm_cache",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util 0.3.0",
"deno_resolver", "deno_resolver",
"deno_runtime", "deno_runtime",
"deno_semver", "deno_semver",
@ -1309,6 +1341,7 @@ dependencies = [
"spki", "spki",
"sqlformat", "sqlformat",
"strsim", "strsim",
"sys_traits",
"tar", "tar",
"tempfile", "tempfile",
"test_server", "test_server",
@ -1388,7 +1421,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_bench_util" name = "deno_bench_util"
version = "0.176.0" version = "0.178.0"
dependencies = [ dependencies = [
"bencher", "bencher",
"deno_core", "deno_core",
@ -1397,7 +1430,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_broadcast_channel" name = "deno_broadcast_channel"
version = "0.176.0" version = "0.178.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1408,7 +1441,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_cache" name = "deno_cache"
version = "0.114.0" version = "0.116.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1421,13 +1454,21 @@ dependencies = [
[[package]] [[package]]
name = "deno_cache_dir" name = "deno_cache_dir"
version = "0.14.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cca43605c8cbce6c6787e0daf227864487c07c2b31d438c0bf43d1b38da94b7f" checksum = "e73ed17f285731a23df9779ca1e0e721de866db6776ed919ebd9235e0a107c4c"
dependencies = [ dependencies = [
"async-trait",
"base32", "base32",
"base64 0.21.7",
"boxed_error",
"cache_control",
"chrono",
"data-url",
"deno_error",
"deno_media_type", "deno_media_type",
"deno_path_util", "deno_path_util 0.3.0",
"http 1.1.0",
"indexmap 2.3.0", "indexmap 2.3.0",
"log", "log",
"once_cell", "once_cell",
@ -1435,13 +1476,14 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"sys_traits",
"thiserror 1.0.64", "thiserror 1.0.64",
"url", "url",
] ]
[[package]] [[package]]
name = "deno_canvas" name = "deno_canvas"
version = "0.51.0" version = "0.53.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_webgpu", "deno_webgpu",
@ -1452,13 +1494,13 @@ dependencies = [
[[package]] [[package]]
name = "deno_config" name = "deno_config"
version = "0.39.3" version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce717af3fe6788dae63965d58d5637fd62be8fe4f345f189137ffc06c51837d2" checksum = "b45aaf31e58ca915d5c0746bf8e2d07b94635154ad9e5afe5ff265cae6187b19"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util 0.3.0",
"deno_semver", "deno_semver",
"glob", "glob",
"ignore", "ignore",
@ -1470,22 +1512,23 @@ dependencies = [
"phf", "phf",
"serde", "serde",
"serde_json", "serde_json",
"sys_traits",
"thiserror 1.0.64", "thiserror 1.0.64",
"url", "url",
] ]
[[package]] [[package]]
name = "deno_console" name = "deno_console"
version = "0.182.0" version = "0.184.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
] ]
[[package]] [[package]]
name = "deno_core" name = "deno_core"
version = "0.326.0" version = "0.327.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed157162dc5320a2b46ffeeaec24788339df0f2437cfaea78a8d82696715ad7f" checksum = "eaf8dff204b9c2415deb47b9f30d4d38b0925d0d88f1f9074e8e76f59e6d7ded"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"az", "az",
@ -1493,7 +1536,7 @@ dependencies = [
"bit-set", "bit-set",
"bit-vec", "bit-vec",
"bytes", "bytes",
"capacity_builder", "capacity_builder 0.1.3",
"cooked-waker", "cooked-waker",
"deno_core_icudata", "deno_core_icudata",
"deno_ops", "deno_ops",
@ -1525,7 +1568,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]] [[package]]
name = "deno_cron" name = "deno_cron"
version = "0.62.0" version = "0.64.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1538,7 +1581,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_crypto" name = "deno_crypto"
version = "0.196.0" version = "0.198.0"
dependencies = [ dependencies = [
"aes", "aes",
"aes-gcm", "aes-gcm",
@ -1584,7 +1627,7 @@ dependencies = [
"comrak", "comrak",
"deno_ast", "deno_ast",
"deno_graph", "deno_graph",
"deno_path_util", "deno_path_util 0.2.2",
"handlebars", "handlebars",
"html-escape", "html-escape",
"import_map", "import_map",
@ -1612,6 +1655,7 @@ dependencies = [
"libc", "libc",
"serde", "serde",
"serde_json", "serde_json",
"url",
] ]
[[package]] [[package]]
@ -1627,18 +1671,19 @@ dependencies = [
[[package]] [[package]]
name = "deno_fetch" name = "deno_fetch"
version = "0.206.0" version = "0.208.0"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"bytes", "bytes",
"data-url", "data-url",
"deno_core", "deno_core",
"deno_path_util", "deno_path_util 0.3.0",
"deno_permissions", "deno_permissions",
"deno_tls", "deno_tls",
"dyn-clone", "dyn-clone",
"error_reporter", "error_reporter",
"fast-socks5", "fast-socks5",
"h2 0.4.4",
"hickory-resolver", "hickory-resolver",
"http 1.1.0", "http 1.1.0",
"http-body-util", "http-body-util",
@ -1655,14 +1700,14 @@ dependencies = [
"tokio-rustls", "tokio-rustls",
"tokio-socks", "tokio-socks",
"tokio-util", "tokio-util",
"tower", "tower 0.5.2",
"tower-http", "tower-http",
"tower-service", "tower-service",
] ]
[[package]] [[package]]
name = "deno_ffi" name = "deno_ffi"
version = "0.169.0" version = "0.171.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1682,14 +1727,14 @@ dependencies = [
[[package]] [[package]]
name = "deno_fs" name = "deno_fs"
version = "0.92.0" version = "0.94.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base32", "base32",
"boxed_error", "boxed_error",
"deno_core", "deno_core",
"deno_io", "deno_io",
"deno_path_util", "deno_path_util 0.3.0",
"deno_permissions", "deno_permissions",
"filetime", "filetime",
"junction", "junction",
@ -1705,14 +1750,16 @@ dependencies = [
[[package]] [[package]]
name = "deno_graph" name = "deno_graph"
version = "0.86.3" version = "0.86.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc78ed0b4bbcb4197300f0d6e7d1edc2d2c5019cdb9dedba7ff229158441885b" checksum = "83af194ca492ea7b624d21055f933676d3f3d27586de93be31c8f1babcc73510"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"capacity_builder 0.5.0",
"data-url", "data-url",
"deno_ast", "deno_ast",
"deno_path_util 0.3.0",
"deno_semver", "deno_semver",
"deno_unsync", "deno_unsync",
"encoding_rs", "encoding_rs",
@ -1727,6 +1774,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"sys_traits",
"thiserror 2.0.3", "thiserror 2.0.3",
"twox-hash", "twox-hash",
"url", "url",
@ -1735,7 +1783,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_http" name = "deno_http"
version = "0.180.0" version = "0.182.0"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"async-trait", "async-trait",
@ -1774,7 +1822,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_io" name = "deno_io"
version = "0.92.0" version = "0.94.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1795,7 +1843,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_kv" name = "deno_kv"
version = "0.90.0" version = "0.92.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1805,7 +1853,7 @@ dependencies = [
"chrono", "chrono",
"deno_core", "deno_core",
"deno_fetch", "deno_fetch",
"deno_path_util", "deno_path_util 0.3.0",
"deno_permissions", "deno_permissions",
"deno_tls", "deno_tls",
"denokv_proto", "denokv_proto",
@ -1845,9 +1893,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_lockfile" name = "deno_lockfile"
version = "0.23.2" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "559c19feb00af0c34f0bd4a20e56e12463fafd5c5069d6005f3ce33008027eea" checksum = "632e835a53ed667d62fdd766c5780fe8361c831d3e3fbf1a760a0b7896657587"
dependencies = [ dependencies = [
"deno_semver", "deno_semver",
"serde", "serde",
@ -1857,9 +1905,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_media_type" name = "deno_media_type"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcf552fbdedbe81c89705349d7d2485c7051382b000dfddbdbf7fc25931cf83" checksum = "eaa135b8a9febc9a51c16258e294e268a1276750780d69e46edb31cced2826e4"
dependencies = [ dependencies = [
"data-url", "data-url",
"serde", "serde",
@ -1868,7 +1916,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_napi" name = "deno_napi"
version = "0.113.0" version = "0.115.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1896,7 +1944,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_net" name = "deno_net"
version = "0.174.0" version = "0.176.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1904,6 +1952,7 @@ dependencies = [
"hickory-proto", "hickory-proto",
"hickory-resolver", "hickory-resolver",
"pin-project", "pin-project",
"quinn",
"rustls-tokio-stream", "rustls-tokio-stream",
"serde", "serde",
"socket2", "socket2",
@ -1913,7 +1962,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_node" name = "deno_node"
version = "0.119.0" version = "0.122.0"
dependencies = [ dependencies = [
"aead-gcm-stream", "aead-gcm-stream",
"aes", "aes",
@ -1933,7 +1982,7 @@ dependencies = [
"deno_media_type", "deno_media_type",
"deno_net", "deno_net",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util 0.3.0",
"deno_permissions", "deno_permissions",
"deno_whoami", "deno_whoami",
"der", "der",
@ -1993,6 +2042,7 @@ dependencies = [
"sm3", "sm3",
"spki", "spki",
"stable_deref_trait", "stable_deref_trait",
"sys_traits",
"thiserror 2.0.3", "thiserror 2.0.3",
"tokio", "tokio",
"tokio-eld", "tokio-eld",
@ -2007,12 +2057,13 @@ dependencies = [
[[package]] [[package]]
name = "deno_npm" name = "deno_npm"
version = "0.26.0" version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f125a5dba7839c46394a0a9c835da9fe60f5f412587ab4956a76492a1cc6a8" checksum = "5f818ad5dc4c206b50b5cfa6f10b4b94b127e15c8342c152768eba40c225ca23"
dependencies = [ dependencies = [
"anyhow",
"async-trait", "async-trait",
"capacity_builder 0.5.0",
"deno_error",
"deno_lockfile", "deno_lockfile",
"deno_semver", "deno_semver",
"futures", "futures",
@ -2026,7 +2077,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_npm_cache" name = "deno_npm_cache"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -2034,7 +2085,9 @@ dependencies = [
"boxed_error", "boxed_error",
"deno_cache_dir", "deno_cache_dir",
"deno_core", "deno_core",
"deno_error",
"deno_npm", "deno_npm",
"deno_path_util 0.3.0",
"deno_semver", "deno_semver",
"deno_unsync", "deno_unsync",
"faster-hex", "faster-hex",
@ -2047,6 +2100,7 @@ dependencies = [
"rand", "rand",
"ring", "ring",
"serde_json", "serde_json",
"sys_traits",
"tar", "tar",
"tempfile", "tempfile",
"thiserror 2.0.3", "thiserror 2.0.3",
@ -2055,9 +2109,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_ops" name = "deno_ops"
version = "0.202.0" version = "0.203.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd8ac1af251e292388e516dd339b9a3b982a6d1e7f8644c08e34671ca39003c" checksum = "b146ca74cac431843486ade58e2accc16c11315fb2c6934590a52a73c56b7ec3"
dependencies = [ dependencies = [
"proc-macro-rules", "proc-macro-rules",
"proc-macro2", "proc-macro2",
@ -2071,38 +2125,54 @@ dependencies = [
[[package]] [[package]]
name = "deno_package_json" name = "deno_package_json"
version = "0.2.1" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80b0a3d81c592624a1ae15332a04b4dc2b7c163ef1dfc7c60171f736d1babdf5" checksum = "e1d3c0f699ba2040669204ce24ab73720499fc290af843e4ce0fc8a9b3d67735"
dependencies = [ dependencies = [
"boxed_error",
"deno_error", "deno_error",
"deno_path_util", "deno_path_util 0.3.0",
"deno_semver", "deno_semver",
"indexmap 2.3.0", "indexmap 2.3.0",
"serde", "serde",
"serde_json", "serde_json",
"sys_traits",
"thiserror 2.0.3", "thiserror 2.0.3",
"url", "url",
] ]
[[package]] [[package]]
name = "deno_path_util" name = "deno_path_util"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff25f6e08e7a0214bbacdd6f7195c7f1ebcd850c87a624e4ff06326b68b42d99" checksum = "b02c7d341e1b2cf089daff0f4fb2b4be8f3b5511b1d96040b3f7ed63a66c737b"
dependencies = [ dependencies = [
"deno_error",
"percent-encoding", "percent-encoding",
"thiserror 1.0.64", "thiserror 2.0.3",
"url",
]
[[package]]
name = "deno_path_util"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420e8211aaba7fde83ccaa9a5dad855c3b940ed988d70c95159acd600a70dc87"
dependencies = [
"deno_error",
"percent-encoding",
"sys_traits",
"thiserror 2.0.3",
"url", "url",
] ]
[[package]] [[package]]
name = "deno_permissions" name = "deno_permissions"
version = "0.42.0" version = "0.43.0"
dependencies = [ dependencies = [
"capacity_builder", "capacity_builder 0.5.0",
"deno_core", "deno_core",
"deno_path_util", "deno_path_util 0.3.0",
"deno_terminal 0.2.0", "deno_terminal 0.2.0",
"fqdn", "fqdn",
"libc", "libc",
@ -2117,7 +2187,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_resolver" name = "deno_resolver"
version = "0.14.0" version = "0.15.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base32", "base32",
@ -2126,9 +2196,10 @@ dependencies = [
"deno_config", "deno_config",
"deno_media_type", "deno_media_type",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util 0.3.0",
"deno_semver", "deno_semver",
"node_resolver", "node_resolver",
"sys_traits",
"test_server", "test_server",
"thiserror 2.0.3", "thiserror 2.0.3",
"url", "url",
@ -2136,7 +2207,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_runtime" name = "deno_runtime"
version = "0.191.0" version = "0.192.0"
dependencies = [ dependencies = [
"color-print", "color-print",
"deno_ast", "deno_ast",
@ -2156,7 +2227,7 @@ dependencies = [
"deno_napi", "deno_napi",
"deno_net", "deno_net",
"deno_node", "deno_node",
"deno_path_util", "deno_path_util 0.3.0",
"deno_permissions", "deno_permissions",
"deno_telemetry", "deno_telemetry",
"deno_terminal 0.2.0", "deno_terminal 0.2.0",
@ -2191,6 +2262,7 @@ dependencies = [
"serde", "serde",
"signal-hook", "signal-hook",
"signal-hook-registry", "signal-hook-registry",
"sys_traits",
"tempfile", "tempfile",
"test_server", "test_server",
"thiserror 2.0.3", "thiserror 2.0.3",
@ -2205,11 +2277,14 @@ dependencies = [
[[package]] [[package]]
name = "deno_semver" name = "deno_semver"
version = "0.6.1" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d1259270d66a5e6d29bb75c9289656541874f79ae9ff6c9f1c790846d5c07ba" checksum = "4775271f9b5602482698f76d24ea9ed8ba27af7f587a7e9a876916300c542435"
dependencies = [ dependencies = [
"capacity_builder 0.5.0",
"deno_error", "deno_error",
"ecow",
"hipstr",
"monch", "monch",
"once_cell", "once_cell",
"serde", "serde",
@ -2237,7 +2312,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_telemetry" name = "deno_telemetry"
version = "0.4.0" version = "0.6.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -2278,7 +2353,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_tls" name = "deno_tls"
version = "0.169.0" version = "0.171.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_native_certs", "deno_native_certs",
@ -2311,7 +2386,7 @@ dependencies = [
"serde_json", "serde_json",
"tokio", "tokio",
"tokio-util", "tokio-util",
"tower", "tower 0.4.13",
"tracing", "tracing",
] ]
@ -2328,7 +2403,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_url" name = "deno_url"
version = "0.182.0" version = "0.184.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_console", "deno_console",
@ -2340,7 +2415,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_web" name = "deno_web"
version = "0.213.0" version = "0.215.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64-simd 0.8.0", "base64-simd 0.8.0",
@ -2362,7 +2437,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webgpu" name = "deno_webgpu"
version = "0.149.0" version = "0.151.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"raw-window-handle", "raw-window-handle",
@ -2375,7 +2450,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webidl" name = "deno_webidl"
version = "0.182.0" version = "0.184.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_core", "deno_core",
@ -2383,7 +2458,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_websocket" name = "deno_websocket"
version = "0.187.0" version = "0.189.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"deno_core", "deno_core",
@ -2405,7 +2480,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webstorage" name = "deno_webstorage"
version = "0.177.0" version = "0.179.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_web", "deno_web",
@ -2876,6 +2951,15 @@ dependencies = [
"spki", "spki",
] ]
[[package]]
name = "ecow"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42fc0a93992b20c58b99e59d61eaf1635a25bfbe49e4275c34ba0aee98119ba"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "ed25519" name = "ed25519"
version = "2.2.3" version = "2.2.3"
@ -3812,6 +3896,17 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "hipstr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97971ffc85d4c98de12e2608e992a43f5294ebb625fdb045b27c731b64c4c6d6"
dependencies = [
"serde",
"serde_bytes",
"sptr",
]
[[package]] [[package]]
name = "hkdf" name = "hkdf"
version = "0.12.4" version = "0.12.4"
@ -4012,9 +4107,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-timeout" name = "hyper-timeout"
version = "0.5.1" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
dependencies = [ dependencies = [
"hyper 1.4.1", "hyper 1.4.1",
"hyper-util", "hyper-util",
@ -4541,9 +4636,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]] [[package]]
name = "libffi" name = "libffi"
@ -4919,7 +5014,7 @@ dependencies = [
[[package]] [[package]]
name = "napi_sym" name = "napi_sym"
version = "0.112.0" version = "0.114.0"
dependencies = [ dependencies = [
"quote", "quote",
"serde", "serde",
@ -4974,20 +5069,21 @@ dependencies = [
[[package]] [[package]]
name = "node_resolver" name = "node_resolver"
version = "0.21.0" version = "0.22.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"boxed_error", "boxed_error",
"deno_media_type", "deno_media_type",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util 0.3.0",
"futures", "futures",
"lazy-regex", "lazy-regex",
"once_cell", "once_cell",
"path-clean", "path-clean",
"regex", "regex",
"serde_json", "serde_json",
"sys_traits",
"thiserror 2.0.3", "thiserror 2.0.3",
"tokio", "tokio",
"url", "url",
@ -5895,49 +5991,54 @@ dependencies = [
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.2" version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
dependencies = [ dependencies = [
"bytes", "bytes",
"pin-project-lite", "pin-project-lite",
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rustc-hash 1.1.0", "rustc-hash 2.0.0",
"rustls", "rustls",
"thiserror 1.0.64", "socket2",
"thiserror 2.0.3",
"tokio", "tokio",
"tracing", "tracing",
] ]
[[package]] [[package]]
name = "quinn-proto" name = "quinn-proto"
version = "0.11.8" version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
dependencies = [ dependencies = [
"bytes", "bytes",
"getrandom",
"rand", "rand",
"ring", "ring",
"rustc-hash 2.0.0", "rustc-hash 2.0.0",
"rustls", "rustls",
"rustls-pki-types",
"slab", "slab",
"thiserror 1.0.64", "thiserror 2.0.3",
"tinyvec", "tinyvec",
"tracing", "tracing",
"web-time",
] ]
[[package]] [[package]]
name = "quinn-udp" name = "quinn-udp"
version = "0.5.2" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527"
dependencies = [ dependencies = [
"cfg_aliases 0.2.1",
"libc", "libc",
"once_cell", "once_cell",
"socket2", "socket2",
"tracing", "tracing",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -6414,6 +6515,9 @@ name = "rustls-pki-types"
version = "1.8.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
dependencies = [
"web-time",
]
[[package]] [[package]]
name = "rustls-tokio-stream" name = "rustls-tokio-stream"
@ -6697,9 +6801,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_v8" name = "serde_v8"
version = "0.235.0" version = "0.236.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07afd8b67b4a442ecc2823038473ac0e9e5682de93c213323b60661afdd7eb4" checksum = "e23b3abce64010612f88f4ff689a959736f99eb3dc0dbf1c7903434b8bd8cda5"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"serde", "serde",
@ -6975,6 +7079,12 @@ dependencies = [
"der", "der",
] ]
[[package]]
name = "sptr"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
[[package]] [[package]]
name = "sqlformat" name = "sqlformat"
version = "0.3.2" version = "0.3.2"
@ -7570,6 +7680,19 @@ dependencies = [
"syn 2.0.87", "syn 2.0.87",
] ]
[[package]]
name = "sys_traits"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6683465f4e1d8fd75069cbc36c646258c05b7d8d6676bcb5d71968b99b7d5ae2"
dependencies = [
"filetime",
"getrandom",
"libc",
"parking_lot",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "tagptr" name = "tagptr"
version = "0.2.0" version = "0.2.0"
@ -7965,7 +8088,7 @@ dependencies = [
"socket2", "socket2",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tower", "tower 0.4.13",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing", "tracing",
@ -7991,6 +8114,21 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.6.1" version = "0.6.1"
@ -8019,9 +8157,9 @@ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]] [[package]]
name = "tracing" name = "tracing"
@ -8495,6 +8633,16 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "webpki-root-certs" name = "webpki-root-certs"
version = "0.26.6" version = "0.26.6"
@ -8522,7 +8670,7 @@ dependencies = [
"arrayvec", "arrayvec",
"bit-vec", "bit-vec",
"bitflags 2.6.0", "bitflags 2.6.0",
"cfg_aliases", "cfg_aliases 0.1.1",
"codespan-reporting", "codespan-reporting",
"document-features", "document-features",
"indexmap 2.3.0", "indexmap 2.3.0",
@ -8554,7 +8702,7 @@ dependencies = [
"bit-set", "bit-set",
"bitflags 2.6.0", "bitflags 2.6.0",
"block", "block",
"cfg_aliases", "cfg_aliases 0.1.1",
"core-graphics-types", "core-graphics-types",
"d3d12", "d3d12",
"glow", "glow",

View file

@ -48,19 +48,19 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "=0.44.0", features = ["transpiling"] } deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_core = { version = "0.326.0" } deno_core = { version = "0.327.0" }
deno_bench_util = { version = "0.176.0", path = "./bench_util" } deno_bench_util = { version = "0.178.0", path = "./bench_util" }
deno_config = { version = "=0.39.3", features = ["workspace", "sync"] } deno_config = { version = "=0.42.0", features = ["workspace", "sync"] }
deno_lockfile = "=0.23.2" deno_lockfile = "=0.24.0"
deno_media_type = { version = "0.2.0", features = ["module_specifier"] } deno_media_type = { version = "0.2.0", features = ["module_specifier"] }
deno_npm = "=0.26.0" deno_npm = "=0.27.0"
deno_path_util = "=0.2.1" deno_path_util = "=0.3.0"
deno_permissions = { version = "0.42.0", path = "./runtime/permissions" } deno_permissions = { version = "0.43.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.191.0", path = "./runtime" } deno_runtime = { version = "0.192.0", path = "./runtime" }
deno_semver = "=0.6.1" deno_semver = "=0.7.1"
deno_terminal = "0.2.0" deno_terminal = "0.2.0"
napi_sym = { version = "0.112.0", path = "./ext/napi/sym" } napi_sym = { version = "0.114.0", path = "./ext/napi/sym" }
test_util = { package = "test_server", path = "./tests/util/server" } test_util = { package = "test_server", path = "./tests/util/server" }
denokv_proto = "0.8.4" denokv_proto = "0.8.4"
@ -69,34 +69,34 @@ denokv_remote = "0.8.4"
denokv_sqlite = { default-features = false, version = "0.8.4" } denokv_sqlite = { default-features = false, version = "0.8.4" }
# exts # exts
deno_broadcast_channel = { version = "0.176.0", path = "./ext/broadcast_channel" } deno_broadcast_channel = { version = "0.178.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.114.0", path = "./ext/cache" } deno_cache = { version = "0.116.0", path = "./ext/cache" }
deno_canvas = { version = "0.51.0", path = "./ext/canvas" } deno_canvas = { version = "0.53.0", path = "./ext/canvas" }
deno_console = { version = "0.182.0", path = "./ext/console" } deno_console = { version = "0.184.0", path = "./ext/console" }
deno_cron = { version = "0.62.0", path = "./ext/cron" } deno_cron = { version = "0.64.0", path = "./ext/cron" }
deno_crypto = { version = "0.196.0", path = "./ext/crypto" } deno_crypto = { version = "0.198.0", path = "./ext/crypto" }
deno_fetch = { version = "0.206.0", path = "./ext/fetch" } deno_fetch = { version = "0.208.0", path = "./ext/fetch" }
deno_ffi = { version = "0.169.0", path = "./ext/ffi" } deno_ffi = { version = "0.171.0", path = "./ext/ffi" }
deno_fs = { version = "0.92.0", path = "./ext/fs" } deno_fs = { version = "0.94.0", path = "./ext/fs" }
deno_http = { version = "0.180.0", path = "./ext/http" } deno_http = { version = "0.182.0", path = "./ext/http" }
deno_io = { version = "0.92.0", path = "./ext/io" } deno_io = { version = "0.94.0", path = "./ext/io" }
deno_kv = { version = "0.90.0", path = "./ext/kv" } deno_kv = { version = "0.92.0", path = "./ext/kv" }
deno_napi = { version = "0.113.0", path = "./ext/napi" } deno_napi = { version = "0.115.0", path = "./ext/napi" }
deno_net = { version = "0.174.0", path = "./ext/net" } deno_net = { version = "0.176.0", path = "./ext/net" }
deno_node = { version = "0.119.0", path = "./ext/node" } deno_node = { version = "0.122.0", path = "./ext/node" }
deno_telemetry = { version = "0.4.0", path = "./ext/telemetry" } deno_telemetry = { version = "0.6.0", path = "./ext/telemetry" }
deno_tls = { version = "0.169.0", path = "./ext/tls" } deno_tls = { version = "0.171.0", path = "./ext/tls" }
deno_url = { version = "0.182.0", path = "./ext/url" } deno_url = { version = "0.184.0", path = "./ext/url" }
deno_web = { version = "0.213.0", path = "./ext/web" } deno_web = { version = "0.215.0", path = "./ext/web" }
deno_webgpu = { version = "0.149.0", path = "./ext/webgpu" } deno_webgpu = { version = "0.151.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.182.0", path = "./ext/webidl" } deno_webidl = { version = "0.184.0", path = "./ext/webidl" }
deno_websocket = { version = "0.187.0", path = "./ext/websocket" } deno_websocket = { version = "0.189.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.177.0", path = "./ext/webstorage" } deno_webstorage = { version = "0.179.0", path = "./ext/webstorage" }
# resolvers # resolvers
deno_npm_cache = { version = "0.2.0", path = "./resolvers/npm_cache" } deno_npm_cache = { version = "0.3.0", path = "./resolvers/npm_cache" }
deno_resolver = { version = "0.14.0", path = "./resolvers/deno" } deno_resolver = { version = "0.15.0", path = "./resolvers/deno" }
node_resolver = { version = "0.21.0", path = "./resolvers/node" } node_resolver = { version = "0.22.0", path = "./resolvers/node" }
aes = "=0.8.3" aes = "=0.8.3"
anyhow = "1.0.57" anyhow = "1.0.57"
@ -104,11 +104,11 @@ async-trait = "0.1.73"
base32 = "=0.5.1" base32 = "=0.5.1"
base64 = "0.21.7" base64 = "0.21.7"
bencher = "0.1" bencher = "0.1"
boxed_error = "0.2.2" boxed_error = "0.2.3"
brotli = "6.0.0" brotli = "6.0.0"
bytes = "1.4.0" bytes = "1.4.0"
cache_control = "=0.2.0" cache_control = "=0.2.0"
capacity_builder = "0.1.0" capacity_builder = "0.5.0"
cbc = { version = "=0.1.2", features = ["alloc"] } cbc = { version = "=0.1.2", features = ["alloc"] }
# Note: Do not use the "clock" feature of chrono, as it links us to CoreFoundation on macOS. # Note: Do not use the "clock" feature of chrono, as it links us to CoreFoundation on macOS.
# Instead use util::time::utc_now() # Instead use util::time::utc_now()
@ -117,9 +117,10 @@ color-print = "0.3.5"
console_static_text = "=0.8.1" console_static_text = "=0.8.1"
dashmap = "5.5.3" dashmap = "5.5.3"
data-encoding = "2.3.3" data-encoding = "2.3.3"
data-url = "=0.3.0" data-url = "=0.3.1"
deno_cache_dir = "=0.14.0" deno_cache_dir = "=0.16.0"
deno_package_json = { version = "0.2.1", default-features = false } deno_error = "=0.5.2"
deno_package_json = { version = "0.4.0", default-features = false }
deno_unsync = "0.4.2" deno_unsync = "0.4.2"
dlopen2 = "0.6.1" dlopen2 = "0.6.1"
ecb = "=0.1.2" ecb = "=0.1.2"
@ -148,7 +149,7 @@ indexmap = { version = "2", features = ["serde"] }
ipnet = "2.3" ipnet = "2.3"
jsonc-parser = { version = "=0.26.2", features = ["serde"] } jsonc-parser = { version = "=0.26.2", features = ["serde"] }
lazy-regex = "3" lazy-regex = "3"
libc = "0.2.126" libc = "0.2.168"
libz-sys = { version = "1.1.20", default-features = false } libz-sys = { version = "1.1.20", default-features = false }
log = { version = "0.4.20", features = ["kv"] } log = { version = "0.4.20", features = ["kv"] }
lsp-types = "=0.97.0" # used by tower-lsp and "proposed" feature is unstable in patch releases lsp-types = "=0.97.0" # used by tower-lsp and "proposed" feature is unstable in patch releases
@ -192,6 +193,7 @@ slab = "0.4"
smallvec = "1.8" smallvec = "1.8"
socket2 = { version = "0.5.3", features = ["all"] } socket2 = { version = "0.5.3", features = ["all"] }
spki = "0.7.2" spki = "0.7.2"
sys_traits = "=0.1.4"
tar = "=0.4.40" tar = "=0.4.40"
tempfile = "3.4.0" tempfile = "3.4.0"
termcolor = "1.1.3" termcolor = "1.1.3"
@ -201,7 +203,7 @@ tokio-metrics = { version = "0.3.0", features = ["rt"] }
tokio-rustls = { version = "0.26.0", default-features = false, features = ["ring", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["ring", "tls12"] }
tokio-socks = "0.5.1" tokio-socks = "0.5.1"
tokio-util = "0.7.4" tokio-util = "0.7.4"
tower = { version = "0.4.13", default-features = false, features = ["util"] } tower = { version = "0.5.2", default-features = false, features = ["retry", "util"] }
tower-http = { version = "0.6.1", features = ["decompression-br", "decompression-gzip"] } tower-http = { version = "0.6.1", features = ["decompression-br", "decompression-gzip"] }
tower-lsp = { package = "deno_tower_lsp", version = "0.1.0", features = ["proposed"] } tower-lsp = { package = "deno_tower_lsp", version = "0.1.0", features = ["proposed"] }
tower-service = "0.3.2" tower-service = "0.3.2"

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_bench_util" name = "deno_bench_util"
version = "0.176.0" version = "0.178.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -73,7 +73,8 @@ deno_cache_dir.workspace = true
deno_config.workspace = true deno_config.workspace = true
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "=0.161.3", features = ["rust", "comrak"] } deno_doc = { version = "=0.161.3", features = ["rust", "comrak"] }
deno_graph = { version = "=0.86.3" } deno_error.workspace = true
deno_graph = { version = "=0.86.6" }
deno_lint = { version = "=0.68.2", features = ["docs"] } deno_lint = { version = "=0.68.2", features = ["docs"] }
deno_lockfile.workspace = true deno_lockfile.workspace = true
deno_npm.workspace = true deno_npm.workspace = true
@ -93,8 +94,10 @@ anstream = "0.6.14"
async-trait.workspace = true async-trait.workspace = true
base64.workspace = true base64.workspace = true
bincode = "=1.3.3" bincode = "=1.3.3"
boxed_error.workspace = true
bytes.workspace = true bytes.workspace = true
cache_control.workspace = true cache_control.workspace = true
capacity_builder.workspace = true
chrono = { workspace = true, features = ["now"] } chrono = { workspace = true, features = ["now"] }
clap = { version = "=4.5.16", features = ["env", "string", "wrap_help", "error-context"] } clap = { version = "=4.5.16", features = ["env", "string", "wrap_help", "error-context"] }
clap_complete = "=4.5.24" clap_complete = "=4.5.24"
@ -155,6 +158,7 @@ shell-escape = "=0.1.5"
spki = { version = "0.7", features = ["pem"] } spki = { version = "0.7", features = ["pem"] }
sqlformat = "=0.3.2" sqlformat = "=0.3.2"
strsim = "0.11.1" strsim = "0.11.1"
sys_traits = { workspace = true, features = ["getrandom", "filetime", "libc", "real", "strip_unc", "winapi"] }
tar.workspace = true tar.workspace = true
tempfile.workspace = true tempfile.workspace = true
text-size = "=1.1.0" text-size = "=1.1.0"
@ -183,6 +187,7 @@ nix.workspace = true
[dev-dependencies] [dev-dependencies]
deno_bench_util.workspace = true deno_bench_util.workspace = true
pretty_assertions.workspace = true pretty_assertions.workspace = true
sys_traits = { workspace = true, features = ["memory"] }
test_util.workspace = true test_util.workspace = true
[package.metadata.winres] [package.metadata.winres]

View file

@ -8,62 +8,6 @@ use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
#[cfg(test)] // happens to only be used by the tests at the moment
pub struct DenoConfigFsAdapter<'a>(
pub &'a dyn deno_runtime::deno_fs::FileSystem,
);
#[cfg(test)]
impl<'a> deno_config::fs::DenoConfigFs for DenoConfigFsAdapter<'a> {
fn read_to_string_lossy(
&self,
path: &std::path::Path,
) -> Result<std::borrow::Cow<'static, str>, std::io::Error> {
self
.0
.read_text_file_lossy_sync(path, None)
.map_err(|err| err.into_io_error())
}
fn stat_sync(
&self,
path: &std::path::Path,
) -> Result<deno_config::fs::FsMetadata, std::io::Error> {
self
.0
.stat_sync(path)
.map(|stat| deno_config::fs::FsMetadata {
is_file: stat.is_file,
is_directory: stat.is_directory,
is_symlink: stat.is_symlink,
})
.map_err(|err| err.into_io_error())
}
fn read_dir(
&self,
path: &std::path::Path,
) -> Result<Vec<deno_config::fs::FsDirEntry>, std::io::Error> {
self
.0
.read_dir_sync(path)
.map_err(|err| err.into_io_error())
.map(|entries| {
entries
.into_iter()
.map(|e| deno_config::fs::FsDirEntry {
path: path.join(e.name),
metadata: deno_config::fs::FsMetadata {
is_file: e.is_file,
is_directory: e.is_directory,
is_symlink: e.is_symlink,
},
})
.collect()
})
}
}
pub fn import_map_deps( pub fn import_map_deps(
import_map: &serde_json::Value, import_map: &serde_json::Value,
) -> HashSet<JsrDepPackageReq> { ) -> HashSet<JsrDepPackageReq> {

View file

@ -1006,6 +1006,8 @@ impl Flags {
OtelConfig { OtelConfig {
tracing_enabled: !disabled tracing_enabled: !disabled
&& otel_var("OTEL_DENO_TRACING").unwrap_or(default), && otel_var("OTEL_DENO_TRACING").unwrap_or(default),
metrics_enabled: !disabled
&& otel_var("OTEL_DENO_METRICS").unwrap_or(default),
console: match std::env::var("OTEL_DENO_CONSOLE").as_deref() { console: match std::env::var("OTEL_DENO_CONSOLE").as_deref() {
Ok(_) if disabled => OtelConsoleConfig::Ignore, Ok(_) if disabled => OtelConsoleConfig::Ignore,
Ok("ignore") => OtelConsoleConfig::Ignore, Ok("ignore") => OtelConsoleConfig::Ignore,

View file

@ -4,21 +4,21 @@ use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url::Url; use deno_core::url::Url;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::TextDecodedFile;
pub async fn resolve_import_map_value_from_specifier( pub async fn resolve_import_map_value_from_specifier(
specifier: &Url, specifier: &Url,
file_fetcher: &FileFetcher, file_fetcher: &CliFileFetcher,
) -> Result<serde_json::Value, AnyError> { ) -> Result<serde_json::Value, AnyError> {
if specifier.scheme() == "data" { if specifier.scheme() == "data" {
let data_url_text = let data_url_text =
deno_graph::source::RawDataUrl::parse(specifier)?.decode()?; deno_graph::source::RawDataUrl::parse(specifier)?.decode()?;
Ok(serde_json::from_str(&data_url_text)?) Ok(serde_json::from_str(&data_url_text)?)
} else { } else {
let file = file_fetcher let file = TextDecodedFile::decode(
.fetch_bypass_permissions(specifier) file_fetcher.fetch_bypass_permissions(specifier).await?,
.await? )?;
.into_text_decoded()?;
Ok(serde_json::from_str(&file.source)?) Ok(serde_json::from_str(&file.source)?)
} }
} }

View file

@ -12,12 +12,13 @@ use deno_core::parking_lot::MutexGuard;
use deno_core::serde_json; use deno_core::serde_json;
use deno_lockfile::WorkspaceMemberConfig; use deno_lockfile::WorkspaceMemberConfig;
use deno_package_json::PackageJsonDepValue; use deno_package_json::PackageJsonDepValue;
use deno_path_util::fs::atomic_write_file_with_retries;
use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_node::PackageJson;
use deno_semver::jsr::JsrDepPackageReq; use deno_semver::jsr::JsrDepPackageReq;
use crate::args::deno_json::import_map_deps; use crate::args::deno_json::import_map_deps;
use crate::cache; use crate::cache;
use crate::util::fs::atomic_write_file_with_retries; use crate::sys::CliSys;
use crate::Flags; use crate::Flags;
use crate::args::DenoSubcommand; use crate::args::DenoSubcommand;
@ -35,6 +36,7 @@ pub struct CliLockfileReadFromPathOptions {
#[derive(Debug)] #[derive(Debug)]
pub struct CliLockfile { pub struct CliLockfile {
sys: CliSys,
lockfile: Mutex<Lockfile>, lockfile: Mutex<Lockfile>,
pub filename: PathBuf, pub filename: PathBuf,
frozen: bool, frozen: bool,
@ -91,8 +93,9 @@ impl CliLockfile {
// do an atomic write to reduce the chance of multiple deno // do an atomic write to reduce the chance of multiple deno
// processes corrupting the file // processes corrupting the file
atomic_write_file_with_retries( atomic_write_file_with_retries(
&self.sys,
&lockfile.filename, &lockfile.filename,
bytes, &bytes,
cache::CACHE_PERM, cache::CACHE_PERM,
) )
.context("Failed writing lockfile.")?; .context("Failed writing lockfile.")?;
@ -101,6 +104,7 @@ impl CliLockfile {
} }
pub fn discover( pub fn discover(
sys: &CliSys,
flags: &Flags, flags: &Flags,
workspace: &Workspace, workspace: &Workspace,
maybe_external_import_map: Option<&serde_json::Value>, maybe_external_import_map: Option<&serde_json::Value>,
@ -163,11 +167,14 @@ impl CliLockfile {
.unwrap_or(false) .unwrap_or(false)
}); });
let lockfile = Self::read_from_path(CliLockfileReadFromPathOptions { let lockfile = Self::read_from_path(
file_path, sys,
frozen, CliLockfileReadFromPathOptions {
skip_write: flags.internal.lockfile_skip_write, file_path,
})?; frozen,
skip_write: flags.internal.lockfile_skip_write,
},
)?;
// initialize the lockfile with the workspace's configuration // initialize the lockfile with the workspace's configuration
let root_url = workspace.root_dir(); let root_url = workspace.root_dir();
@ -223,6 +230,7 @@ impl CliLockfile {
} }
pub fn read_from_path( pub fn read_from_path(
sys: &CliSys,
opts: CliLockfileReadFromPathOptions, opts: CliLockfileReadFromPathOptions,
) -> Result<CliLockfile, AnyError> { ) -> Result<CliLockfile, AnyError> {
let lockfile = match std::fs::read_to_string(&opts.file_path) { let lockfile = match std::fs::read_to_string(&opts.file_path) {
@ -241,6 +249,7 @@ impl CliLockfile {
} }
}; };
Ok(CliLockfile { Ok(CliLockfile {
sys: sys.clone(),
filename: lockfile.filename.clone(), filename: lockfile.filename.clone(),
lockfile: Mutex::new(lockfile), lockfile: Mutex::new(lockfile),
frozen: opts.frozen, frozen: opts.frozen,

View file

@ -9,6 +9,7 @@ mod package_json;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::SourceMapOption; use deno_ast::SourceMapOption;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_config::deno_json::NodeModulesDirMode; use deno_config::deno_json::NodeModulesDirMode;
use deno_config::workspace::CreateResolverOptions; use deno_config::workspace::CreateResolverOptions;
use deno_config::workspace::FolderConfigs; use deno_config::workspace::FolderConfigs;
@ -23,13 +24,14 @@ use deno_config::workspace::WorkspaceLintConfig;
use deno_config::workspace::WorkspaceResolver; use deno_config::workspace::WorkspaceResolver;
use deno_core::resolve_url_or_path; use deno_core::resolve_url_or_path;
use deno_graph::GraphKind; use deno_graph::GraphKind;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_npm::npm_rc::NpmRc; use deno_npm::npm_rc::NpmRc;
use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_npm_cache::NpmCacheSetting;
use deno_path_util::normalize_path; use deno_path_util::normalize_path;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::StackString;
use deno_telemetry::OtelConfig; use deno_telemetry::OtelConfig;
use deno_telemetry::OtelRuntimeConfig; use deno_telemetry::OtelRuntimeConfig;
use import_map::resolve_import_map_value_from_specifier; use import_map::resolve_import_map_value_from_specifier;
@ -81,11 +83,12 @@ use std::num::NonZeroUsize;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use sys_traits::EnvHomeDir;
use thiserror::Error; use thiserror::Error;
use crate::cache;
use crate::cache::DenoDirProvider; use crate::cache::DenoDirProvider;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::sys::CliSys;
use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::version; use crate::version;
@ -217,52 +220,6 @@ pub fn ts_config_to_transpile_and_emit_options(
)) ))
} }
/// Indicates how cached source files should be handled.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CacheSetting {
/// Only the cached files should be used. Any files not in the cache will
/// error. This is the equivalent of `--cached-only` in the CLI.
Only,
/// No cached source files should be used, and all files should be reloaded.
/// This is the equivalent of `--reload` in the CLI.
ReloadAll,
/// Only some cached resources should be used. This is the equivalent of
/// `--reload=jsr:@std/http/file-server` or
/// `--reload=jsr:@std/http/file-server,jsr:@std/assert/assert-equals`.
ReloadSome(Vec<String>),
/// The usability of a cached value is determined by analyzing the cached
/// headers and other metadata associated with a cached response, reloading
/// any cached "non-fresh" cached responses.
RespectHeaders,
/// The cached source files should be used for local modules. This is the
/// default behavior of the CLI.
Use,
}
impl CacheSetting {
pub fn as_npm_cache_setting(&self) -> NpmCacheSetting {
match self {
CacheSetting::Only => NpmCacheSetting::Only,
CacheSetting::ReloadAll => NpmCacheSetting::ReloadAll,
CacheSetting::ReloadSome(values) => {
if values.iter().any(|v| v == "npm:") {
NpmCacheSetting::ReloadAll
} else {
NpmCacheSetting::ReloadSome {
npm_package_names: values
.iter()
.filter_map(|v| v.strip_prefix("npm:"))
.map(|n| n.to_string())
.collect(),
}
}
}
CacheSetting::RespectHeaders => unreachable!(), // not supported
CacheSetting::Use => NpmCacheSetting::Use,
}
}
}
pub struct WorkspaceBenchOptions { pub struct WorkspaceBenchOptions {
pub filter: Option<String>, pub filter: Option<String>,
pub json: bool, pub json: bool,
@ -616,7 +573,7 @@ fn discover_npmrc(
// TODO(bartlomieju): update to read both files - one in the project root and one and // TODO(bartlomieju): update to read both files - one in the project root and one and
// home dir and then merge them. // home dir and then merge them.
// 3. Try `.npmrc` in the user's home directory // 3. Try `.npmrc` in the user's home directory
if let Some(home_dir) = cache::home_dir() { if let Some(home_dir) = crate::sys::CliSys::default().env_home_dir() {
match try_to_read_npmrc(&home_dir) { match try_to_read_npmrc(&home_dir) {
Ok(Some((source, path))) => { Ok(Some((source, path))) => {
return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path))); return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path)));
@ -815,7 +772,9 @@ pub struct CliOptions {
} }
impl CliOptions { impl CliOptions {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
sys: &CliSys,
flags: Arc<Flags>, flags: Arc<Flags>,
initial_cwd: PathBuf, initial_cwd: PathBuf,
maybe_lockfile: Option<Arc<CliLockfile>>, maybe_lockfile: Option<Arc<CliLockfile>>,
@ -840,8 +799,10 @@ impl CliOptions {
} }
let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache); let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache);
let deno_dir_provider = let deno_dir_provider = Arc::new(DenoDirProvider::new(
Arc::new(DenoDirProvider::new(flags.internal.cache_path.clone())); sys.clone(),
flags.internal.cache_path.clone(),
));
let maybe_node_modules_folder = resolve_node_modules_folder( let maybe_node_modules_folder = resolve_node_modules_folder(
&initial_cwd, &initial_cwd,
&flags, &flags,
@ -866,7 +827,7 @@ impl CliOptions {
}) })
} }
pub fn from_flags(flags: Arc<Flags>) -> Result<Self, AnyError> { pub fn from_flags(sys: &CliSys, flags: Arc<Flags>) -> Result<Self, AnyError> {
let initial_cwd = let initial_cwd =
std::env::current_dir().with_context(|| "Failed getting cwd.")?; std::env::current_dir().with_context(|| "Failed getting cwd.")?;
let maybe_vendor_override = flags.vendor.map(|v| match v { let maybe_vendor_override = flags.vendor.map(|v| match v {
@ -889,7 +850,6 @@ impl CliOptions {
log::debug!("package.json auto-discovery is disabled"); log::debug!("package.json auto-discovery is disabled");
} }
WorkspaceDiscoverOptions { WorkspaceDiscoverOptions {
fs: Default::default(), // use real fs
deno_json_cache: None, deno_json_cache: None,
pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache), pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache),
workspace_cache: None, workspace_cache: None,
@ -911,6 +871,7 @@ impl CliOptions {
ConfigFlag::Discover => { ConfigFlag::Discover => {
if let Some(start_paths) = flags.config_path_args(&initial_cwd) { if let Some(start_paths) = flags.config_path_args(&initial_cwd) {
WorkspaceDirectory::discover( WorkspaceDirectory::discover(
sys,
WorkspaceDiscoverStart::Paths(&start_paths), WorkspaceDiscoverStart::Paths(&start_paths),
&resolve_workspace_discover_options(), &resolve_workspace_discover_options(),
)? )?
@ -921,6 +882,7 @@ impl CliOptions {
ConfigFlag::Path(path) => { ConfigFlag::Path(path) => {
let config_path = normalize_path(initial_cwd.join(path)); let config_path = normalize_path(initial_cwd.join(path));
WorkspaceDirectory::discover( WorkspaceDirectory::discover(
sys,
WorkspaceDiscoverStart::ConfigFile(&config_path), WorkspaceDiscoverStart::ConfigFile(&config_path),
&resolve_workspace_discover_options(), &resolve_workspace_discover_options(),
)? )?
@ -959,6 +921,7 @@ impl CliOptions {
}; };
let maybe_lock_file = CliLockfile::discover( let maybe_lock_file = CliLockfile::discover(
sys,
&flags, &flags,
&start_dir.workspace, &start_dir.workspace,
external_import_map.as_ref().map(|(_, v)| v), external_import_map.as_ref().map(|(_, v)| v),
@ -967,6 +930,7 @@ impl CliOptions {
log::debug!("Finished config loading."); log::debug!("Finished config loading.");
Self::new( Self::new(
sys,
flags, flags,
initial_cwd, initial_cwd,
maybe_lock_file.map(Arc::new), maybe_lock_file.map(Arc::new),
@ -1037,24 +1001,24 @@ impl CliOptions {
// https://nodejs.org/api/process.html // https://nodejs.org/api/process.html
match target.as_str() { match target.as_str() {
"aarch64-apple-darwin" => NpmSystemInfo { "aarch64-apple-darwin" => NpmSystemInfo {
os: "darwin".to_string(), os: "darwin".into(),
cpu: "arm64".to_string(), cpu: "arm64".into(),
}, },
"aarch64-unknown-linux-gnu" => NpmSystemInfo { "aarch64-unknown-linux-gnu" => NpmSystemInfo {
os: "linux".to_string(), os: "linux".into(),
cpu: "arm64".to_string(), cpu: "arm64".into(),
}, },
"x86_64-apple-darwin" => NpmSystemInfo { "x86_64-apple-darwin" => NpmSystemInfo {
os: "darwin".to_string(), os: "darwin".into(),
cpu: "x64".to_string(), cpu: "x64".into(),
}, },
"x86_64-unknown-linux-gnu" => NpmSystemInfo { "x86_64-unknown-linux-gnu" => NpmSystemInfo {
os: "linux".to_string(), os: "linux".into(),
cpu: "x64".to_string(), cpu: "x64".into(),
}, },
"x86_64-pc-windows-msvc" => NpmSystemInfo { "x86_64-pc-windows-msvc" => NpmSystemInfo {
os: "win32".to_string(), os: "win32".into(),
cpu: "x64".to_string(), cpu: "x64".into(),
}, },
value => { value => {
log::warn!( log::warn!(
@ -1091,7 +1055,7 @@ impl CliOptions {
pub async fn create_workspace_resolver( pub async fn create_workspace_resolver(
&self, &self,
file_fetcher: &FileFetcher, file_fetcher: &CliFileFetcher,
pkg_json_dep_resolution: PackageJsonDepResolution, pkg_json_dep_resolution: PackageJsonDepResolution,
) -> Result<WorkspaceResolver, AnyError> { ) -> Result<WorkspaceResolver, AnyError> {
let overrode_no_import_map: bool = self let overrode_no_import_map: bool = self
@ -1397,9 +1361,7 @@ impl CliOptions {
Ok(result) Ok(result)
} }
pub fn resolve_deno_lint_config( pub fn resolve_deno_lint_config(&self) -> Result<DenoLintConfig, AnyError> {
&self,
) -> Result<deno_lint::linter::LintConfig, AnyError> {
let ts_config_result = let ts_config_result =
self.resolve_ts_config_for_emit(TsConfigType::Emit)?; self.resolve_ts_config_for_emit(TsConfigType::Emit)?;
@ -1408,11 +1370,11 @@ impl CliOptions {
ts_config_result.ts_config, ts_config_result.ts_config,
)?; )?;
Ok(deno_lint::linter::LintConfig { Ok(DenoLintConfig {
default_jsx_factory: (!transpile_options.jsx_automatic) default_jsx_factory: (!transpile_options.jsx_automatic)
.then(|| transpile_options.jsx_factory.clone()), .then_some(transpile_options.jsx_factory),
default_jsx_fragment_factory: (!transpile_options.jsx_automatic) default_jsx_fragment_factory: (!transpile_options.jsx_automatic)
.then(|| transpile_options.jsx_fragment_factory.clone()), .then_some(transpile_options.jsx_fragment_factory),
}) })
} }
@ -1993,15 +1955,17 @@ pub fn has_flag_env_var(name: &str) -> bool {
pub fn npm_pkg_req_ref_to_binary_command( pub fn npm_pkg_req_ref_to_binary_command(
req_ref: &NpmPackageReqReference, req_ref: &NpmPackageReqReference,
) -> String { ) -> String {
let binary_name = req_ref.sub_path().unwrap_or(req_ref.req().name.as_str()); req_ref
binary_name.to_string() .sub_path()
.map(|s| s.to_string())
.unwrap_or_else(|| req_ref.req().name.to_string())
} }
pub fn config_to_deno_graph_workspace_member( pub fn config_to_deno_graph_workspace_member(
config: &ConfigFile, config: &ConfigFile,
) -> Result<deno_graph::WorkspaceMember, AnyError> { ) -> Result<deno_graph::WorkspaceMember, AnyError> {
let name = match &config.json.name { let name: StackString = match &config.json.name {
Some(name) => name.clone(), Some(name) => name.as_str().into(),
None => bail!("Missing 'name' field in config file."), None => bail!("Missing 'name' field in config file."),
}; };
let version = match &config.json.version { let version = match &config.json.version {

View file

@ -11,19 +11,20 @@ use deno_package_json::PackageJsonDepValueParseError;
use deno_package_json::PackageJsonDepWorkspaceReq; use deno_package_json::PackageJsonDepWorkspaceReq;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use thiserror::Error; use thiserror::Error;
#[derive(Debug)] #[derive(Debug)]
pub struct InstallNpmRemotePkg { pub struct InstallNpmRemotePkg {
pub alias: Option<String>, pub alias: Option<StackString>,
pub base_dir: PathBuf, pub base_dir: PathBuf,
pub req: PackageReq, pub req: PackageReq,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct InstallNpmWorkspacePkg { pub struct InstallNpmWorkspacePkg {
pub alias: Option<String>, pub alias: Option<StackString>,
pub target_dir: PathBuf, pub target_dir: PathBuf,
} }
@ -31,7 +32,7 @@ pub struct InstallNpmWorkspacePkg {
#[error("Failed to install '{}'\n at {}", alias, location)] #[error("Failed to install '{}'\n at {}", alias, location)]
pub struct PackageJsonDepValueParseWithLocationError { pub struct PackageJsonDepValueParseWithLocationError {
pub location: Url, pub location: Url,
pub alias: String, pub alias: StackString,
#[source] #[source]
pub source: PackageJsonDepValueParseError, pub source: PackageJsonDepValueParseError,
} }
@ -100,10 +101,8 @@ impl NpmInstallDepsProvider {
let mut pkg_pkgs = Vec::with_capacity( let mut pkg_pkgs = Vec::with_capacity(
deps.dependencies.len() + deps.dev_dependencies.len(), deps.dependencies.len() + deps.dev_dependencies.len(),
); );
for (alias, dep) in deps for (alias, dep) in
.dependencies deps.dependencies.iter().chain(deps.dev_dependencies.iter())
.into_iter()
.chain(deps.dev_dependencies.into_iter())
{ {
let dep = match dep { let dep = match dep {
Ok(dep) => dep, Ok(dep) => dep,
@ -111,8 +110,8 @@ impl NpmInstallDepsProvider {
pkg_json_dep_errors.push( pkg_json_dep_errors.push(
PackageJsonDepValueParseWithLocationError { PackageJsonDepValueParseWithLocationError {
location: pkg_json.specifier(), location: pkg_json.specifier(),
alias, alias: alias.clone(),
source: err, source: err.clone(),
}, },
); );
continue; continue;
@ -121,28 +120,28 @@ impl NpmInstallDepsProvider {
match dep { match dep {
PackageJsonDepValue::Req(pkg_req) => { PackageJsonDepValue::Req(pkg_req) => {
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| { let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
pkg.matches_req(&pkg_req) pkg.matches_req(pkg_req)
// do not resolve to the current package // do not resolve to the current package
&& pkg.pkg_json.path != pkg_json.path && pkg.pkg_json.path != pkg_json.path
}); });
if let Some(pkg) = workspace_pkg { if let Some(pkg) = workspace_pkg {
workspace_pkgs.push(InstallNpmWorkspacePkg { workspace_pkgs.push(InstallNpmWorkspacePkg {
alias: Some(alias), alias: Some(alias.clone()),
target_dir: pkg.pkg_json.dir_path().to_path_buf(), target_dir: pkg.pkg_json.dir_path().to_path_buf(),
}); });
} else { } else {
pkg_pkgs.push(InstallNpmRemotePkg { pkg_pkgs.push(InstallNpmRemotePkg {
alias: Some(alias), alias: Some(alias.clone()),
base_dir: pkg_json.dir_path().to_path_buf(), base_dir: pkg_json.dir_path().to_path_buf(),
req: pkg_req, req: pkg_req.clone(),
}); });
} }
} }
PackageJsonDepValue::Workspace(workspace_version_req) => { PackageJsonDepValue::Workspace(workspace_version_req) => {
let version_req = match workspace_version_req { let version_req = match workspace_version_req {
PackageJsonDepWorkspaceReq::VersionReq(version_req) => { PackageJsonDepWorkspaceReq::VersionReq(version_req) => {
version_req version_req.clone()
} }
PackageJsonDepWorkspaceReq::Tilde PackageJsonDepWorkspaceReq::Tilde
| PackageJsonDepWorkspaceReq::Caret => { | PackageJsonDepWorkspaceReq::Caret => {
@ -150,10 +149,10 @@ impl NpmInstallDepsProvider {
} }
}; };
if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| { if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| {
pkg.matches_name_and_version_req(&alias, &version_req) pkg.matches_name_and_version_req(alias, &version_req)
}) { }) {
workspace_pkgs.push(InstallNpmWorkspacePkg { workspace_pkgs.push(InstallNpmWorkspacePkg {
alias: Some(alias), alias: Some(alias.clone()),
target_dir: pkg.pkg_json.dir_path().to_path_buf(), target_dir: pkg.pkg_json.dir_path().to_path_buf(),
}); });
} }

View file

@ -1,369 +0,0 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use deno_core::ModuleSpecifier;
use log::debug;
use log::error;
use std::borrow::Cow;
use std::fmt;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
use std::net::SocketAddr;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthTokenData {
Bearer(String),
Basic { username: String, password: String },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AuthToken {
host: AuthDomain,
token: AuthTokenData,
}
impl fmt::Display for AuthToken {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.token {
AuthTokenData::Bearer(token) => write!(f, "Bearer {token}"),
AuthTokenData::Basic { username, password } => {
let credentials = format!("{username}:{password}");
write!(f, "Basic {}", BASE64_STANDARD.encode(credentials))
}
}
}
}
/// A structure which contains bearer tokens that can be used when sending
/// requests to websites, intended to authorize access to private resources
/// such as remote modules.
#[derive(Debug, Clone)]
pub struct AuthTokens(Vec<AuthToken>);
/// An authorization domain, either an exact or suffix match.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthDomain {
Ip(IpAddr),
IpPort(SocketAddr),
/// Suffix match, no dot. May include a port.
Suffix(Cow<'static, str>),
}
impl<T: ToString> From<T> for AuthDomain {
fn from(value: T) -> Self {
let s = value.to_string().to_lowercase();
if let Ok(ip) = SocketAddr::from_str(&s) {
return AuthDomain::IpPort(ip);
};
if s.starts_with('[') && s.ends_with(']') {
if let Ok(ip) = Ipv6Addr::from_str(&s[1..s.len() - 1]) {
return AuthDomain::Ip(ip.into());
}
} else if let Ok(ip) = Ipv4Addr::from_str(&s) {
return AuthDomain::Ip(ip.into());
}
if let Some(s) = s.strip_prefix('.') {
AuthDomain::Suffix(Cow::Owned(s.to_owned()))
} else {
AuthDomain::Suffix(Cow::Owned(s))
}
}
}
impl AuthDomain {
pub fn matches(&self, specifier: &ModuleSpecifier) -> bool {
let Some(host) = specifier.host_str() else {
return false;
};
match *self {
Self::Ip(ip) => {
let AuthDomain::Ip(parsed) = AuthDomain::from(host) else {
return false;
};
ip == parsed && specifier.port().is_none()
}
Self::IpPort(ip) => {
let AuthDomain::Ip(parsed) = AuthDomain::from(host) else {
return false;
};
ip.ip() == parsed && specifier.port() == Some(ip.port())
}
Self::Suffix(ref suffix) => {
let hostname = if let Some(port) = specifier.port() {
Cow::Owned(format!("{}:{}", host, port))
} else {
Cow::Borrowed(host)
};
if suffix.len() == hostname.len() {
return suffix == &hostname;
}
// If it's a suffix match, ensure a dot
if hostname.ends_with(suffix.as_ref())
&& hostname.ends_with(&format!(".{suffix}"))
{
return true;
}
false
}
}
}
}
impl AuthTokens {
/// Create a new set of tokens based on the provided string. It is intended
/// that the string be the value of an environment variable and the string is
/// parsed for token values. The string is expected to be a semi-colon
/// separated string, where each value is `{token}@{hostname}`.
pub fn new(maybe_tokens_str: Option<String>) -> Self {
let mut tokens = Vec::new();
if let Some(tokens_str) = maybe_tokens_str {
for token_str in tokens_str.trim().split(';') {
if token_str.contains('@') {
let mut iter = token_str.rsplitn(2, '@');
let host = AuthDomain::from(iter.next().unwrap());
let token = iter.next().unwrap();
if token.contains(':') {
let mut iter = token.rsplitn(2, ':');
let password = iter.next().unwrap().to_owned();
let username = iter.next().unwrap().to_owned();
tokens.push(AuthToken {
host,
token: AuthTokenData::Basic { username, password },
});
} else {
tokens.push(AuthToken {
host,
token: AuthTokenData::Bearer(token.to_string()),
});
}
} else {
error!("Badly formed auth token discarded.");
}
}
debug!("Parsed {} auth token(s).", tokens.len());
}
Self(tokens)
}
/// Attempt to match the provided specifier to the tokens in the set. The
/// matching occurs from the right of the hostname plus port, irrespective of
/// scheme. For example `https://www.deno.land:8080/` would match a token
/// with a host value of `deno.land:8080` but not match `www.deno.land`. The
/// matching is case insensitive.
pub fn get(&self, specifier: &ModuleSpecifier) -> Option<AuthToken> {
self.0.iter().find_map(|t| {
if t.host.matches(specifier) {
Some(t.clone())
} else {
None
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use deno_core::resolve_url;
#[test]
fn test_auth_token() {
let auth_tokens = AuthTokens::new(Some("abc123@deno.land".to_string()));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123"
);
let fixture = resolve_url("https://www.deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123".to_string()
);
let fixture = resolve_url("http://127.0.0.1:8080/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
let fixture =
resolve_url("https://deno.land.example.com/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
let fixture = resolve_url("https://deno.land:8080/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
}
#[test]
fn test_auth_tokens_multiple() {
let auth_tokens =
AuthTokens::new(Some("abc123@deno.land;def456@example.com".to_string()));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123".to_string()
);
let fixture = resolve_url("http://example.com/a/file.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer def456".to_string()
);
}
#[test]
fn test_auth_tokens_space() {
let auth_tokens = AuthTokens::new(Some(
" abc123@deno.land;def456@example.com\t".to_string(),
));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123".to_string()
);
let fixture = resolve_url("http://example.com/a/file.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer def456".to_string()
);
}
#[test]
fn test_auth_tokens_newline() {
let auth_tokens = AuthTokens::new(Some(
"\nabc123@deno.land;def456@example.com\n".to_string(),
));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123".to_string()
);
let fixture = resolve_url("http://example.com/a/file.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer def456".to_string()
);
}
#[test]
fn test_auth_tokens_port() {
let auth_tokens =
AuthTokens::new(Some("abc123@deno.land:8080".to_string()));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
let fixture = resolve_url("http://deno.land:8080/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc123".to_string()
);
}
#[test]
fn test_auth_tokens_contain_at() {
let auth_tokens = AuthTokens::new(Some("abc@123@deno.land".to_string()));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Bearer abc@123".to_string()
);
}
#[test]
fn test_auth_token_basic() {
let auth_tokens = AuthTokens::new(Some("abc:123@deno.land".to_string()));
let fixture = resolve_url("https://deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Basic YWJjOjEyMw=="
);
let fixture = resolve_url("https://www.deno.land/x/mod.ts").unwrap();
assert_eq!(
auth_tokens.get(&fixture).unwrap().to_string(),
"Basic YWJjOjEyMw==".to_string()
);
let fixture = resolve_url("http://127.0.0.1:8080/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
let fixture =
resolve_url("https://deno.land.example.com/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
let fixture = resolve_url("https://deno.land:8080/x/mod.ts").unwrap();
assert_eq!(auth_tokens.get(&fixture), None);
}
#[test]
fn test_parse_ip() {
let ip = AuthDomain::from("[2001:db8:a::123]");
assert_eq!("Ip(2001:db8:a::123)", format!("{ip:?}"));
let ip = AuthDomain::from("[2001:db8:a::123]:8080");
assert_eq!("IpPort([2001:db8:a::123]:8080)", format!("{ip:?}"));
let ip = AuthDomain::from("1.1.1.1");
assert_eq!("Ip(1.1.1.1)", format!("{ip:?}"));
}
#[test]
fn test_case_insensitive() {
let domain = AuthDomain::from("EXAMPLE.com");
assert!(
domain.matches(&ModuleSpecifier::parse("http://example.com").unwrap())
);
assert!(
domain.matches(&ModuleSpecifier::parse("http://example.COM").unwrap())
);
}
#[test]
fn test_matches() {
let candidates = [
"example.com",
"www.example.com",
"1.1.1.1",
"[2001:db8:a::123]",
// These will never match
"example.com.evil.com",
"1.1.1.1.evil.com",
"notexample.com",
"www.notexample.com",
];
let domains = [
("example.com", vec!["example.com", "www.example.com"]),
(".example.com", vec!["example.com", "www.example.com"]),
("www.example.com", vec!["www.example.com"]),
("1.1.1.1", vec!["1.1.1.1"]),
("[2001:db8:a::123]", vec!["[2001:db8:a::123]"]),
];
let url = |c: &str| ModuleSpecifier::parse(&format!("http://{c}")).unwrap();
let url_port =
|c: &str| ModuleSpecifier::parse(&format!("http://{c}:8080")).unwrap();
// Generate each candidate with and without a port
let candidates = candidates
.into_iter()
.flat_map(|c| [url(c), url_port(c)])
.collect::<Vec<_>>();
for (domain, expected_domain) in domains {
// Test without a port -- all candidates return without a port
let auth_domain = AuthDomain::from(domain);
let actual = candidates
.iter()
.filter(|c| auth_domain.matches(c))
.cloned()
.collect::<Vec<_>>();
let expected = expected_domain.iter().map(|u| url(u)).collect::<Vec<_>>();
assert_eq!(actual, expected);
// Test with a port, all candidates return with a port
let auth_domain = AuthDomain::from(&format!("{domain}:8080"));
let actual = candidates
.iter()
.filter(|c| auth_domain.matches(c))
.cloned()
.collect::<Vec<_>>();
let expected = expected_domain
.iter()
.map(|u| url_port(u))
.collect::<Vec<_>>();
assert_eq!(actual, expected);
}
}
}

166
cli/cache/deno_dir.rs vendored
View file

@ -1,7 +1,10 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_cache_dir::DenoDirResolutionError;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use crate::sys::CliSys;
use super::DiskCache; use super::DiskCache;
use std::env; use std::env;
@ -10,24 +13,37 @@ use std::path::PathBuf;
/// Lazily creates the deno dir which might be useful in scenarios /// Lazily creates the deno dir which might be useful in scenarios
/// where functionality wants to continue if the DENO_DIR can't be created. /// where functionality wants to continue if the DENO_DIR can't be created.
pub struct DenoDirProvider { pub struct DenoDirProvider {
sys: CliSys,
maybe_custom_root: Option<PathBuf>, maybe_custom_root: Option<PathBuf>,
deno_dir: OnceCell<std::io::Result<DenoDir>>, deno_dir: OnceCell<Result<DenoDir, DenoDirResolutionError>>,
} }
impl DenoDirProvider { impl DenoDirProvider {
pub fn new(maybe_custom_root: Option<PathBuf>) -> Self { pub fn new(sys: CliSys, maybe_custom_root: Option<PathBuf>) -> Self {
Self { Self {
sys,
maybe_custom_root, maybe_custom_root,
deno_dir: Default::default(), deno_dir: Default::default(),
} }
} }
pub fn get_or_create(&self) -> Result<&DenoDir, std::io::Error> { pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> {
self self
.deno_dir .deno_dir
.get_or_init(|| DenoDir::new(self.maybe_custom_root.clone())) .get_or_init(|| {
DenoDir::new(self.sys.clone(), self.maybe_custom_root.clone())
})
.as_ref() .as_ref()
.map_err(|err| std::io::Error::new(err.kind(), err.to_string())) .map_err(|err| match err {
DenoDirResolutionError::NoCacheOrHomeDir => {
DenoDirResolutionError::NoCacheOrHomeDir
}
DenoDirResolutionError::FailedCwd { source } => {
DenoDirResolutionError::FailedCwd {
source: std::io::Error::new(source.kind(), source.to_string()),
}
}
})
} }
} }
@ -42,33 +58,20 @@ pub struct DenoDir {
} }
impl DenoDir { impl DenoDir {
pub fn new(maybe_custom_root: Option<PathBuf>) -> std::io::Result<Self> { pub fn new(
let maybe_custom_root = sys: CliSys,
maybe_custom_root.or_else(|| env::var("DENO_DIR").map(String::into).ok()); maybe_custom_root: Option<PathBuf>,
let root: PathBuf = if let Some(root) = maybe_custom_root { ) -> Result<Self, deno_cache_dir::DenoDirResolutionError> {
root let root = deno_cache_dir::resolve_deno_dir(
} else if let Some(cache_dir) = dirs::cache_dir() { &sys_traits::impls::RealSys,
// We use the OS cache dir because all files deno writes are cache files maybe_custom_root,
// Once that changes we need to start using different roots if DENO_DIR )?;
// is not set, and keep a single one if it is.
cache_dir.join("deno")
} else if let Some(home_dir) = dirs::home_dir() {
// fallback path
home_dir.join(".deno")
} else {
panic!("Could not set the Deno root directory")
};
let root = if root.is_absolute() {
root
} else {
std::env::current_dir()?.join(root)
};
assert!(root.is_absolute()); assert!(root.is_absolute());
let gen_path = root.join("gen"); let gen_path = root.join("gen");
let deno_dir = Self { let deno_dir = Self {
root, root,
gen_cache: DiskCache::new(&gen_path), gen_cache: DiskCache::new(sys, &gen_path),
}; };
Ok(deno_dir) Ok(deno_dir)
@ -166,112 +169,3 @@ impl DenoDir {
self.root.join("dl") self.root.join("dl")
} }
} }
/// To avoid the poorly managed dirs crate
#[cfg(not(windows))]
pub mod dirs {
use std::path::PathBuf;
pub fn cache_dir() -> Option<PathBuf> {
if cfg!(target_os = "macos") {
home_dir().map(|h| h.join("Library/Caches"))
} else {
std::env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.or_else(|| home_dir().map(|h| h.join(".cache")))
}
}
pub fn home_dir() -> Option<PathBuf> {
std::env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
fallback()
}
})
.map(PathBuf::from)
}
// This piece of code is taken from the deprecated home_dir() function in Rust's standard library: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/os.rs#L579
// The same code is used by the dirs crate
unsafe fn fallback() -> Option<std::ffi::OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512_usize,
n => n as usize,
};
let mut buf = Vec::with_capacity(amt);
let mut passwd: libc::passwd = std::mem::zeroed();
let mut result = std::ptr::null_mut();
match libc::getpwuid_r(
libc::getuid(),
&mut passwd,
buf.as_mut_ptr(),
buf.capacity(),
&mut result,
) {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = std::ffi::CStr::from_ptr(ptr).to_bytes().to_vec();
Some(std::os::unix::ffi::OsStringExt::from_vec(bytes))
}
_ => None,
}
}
}
/// To avoid the poorly managed dirs crate
// Copied from
// https://github.com/dirs-dev/dirs-sys-rs/blob/ec7cee0b3e8685573d847f0a0f60aae3d9e07fa2/src/lib.rs#L140-L164
// MIT license. Copyright (c) 2018-2019 dirs-rs contributors
#[cfg(windows)]
pub mod dirs {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use winapi::shared::winerror;
use winapi::um::combaseapi;
use winapi::um::knownfolders;
use winapi::um::shlobj;
use winapi::um::shtypes;
use winapi::um::winbase;
use winapi::um::winnt;
fn known_folder(folder_id: shtypes::REFKNOWNFOLDERID) -> Option<PathBuf> {
// SAFETY: winapi calls
unsafe {
let mut path_ptr: winnt::PWSTR = std::ptr::null_mut();
let result = shlobj::SHGetKnownFolderPath(
folder_id,
0,
std::ptr::null_mut(),
&mut path_ptr,
);
if result == winerror::S_OK {
let len = winbase::lstrlenW(path_ptr) as usize;
let path = std::slice::from_raw_parts(path_ptr, len);
let ostr: OsString = OsStringExt::from_wide(path);
combaseapi::CoTaskMemFree(path_ptr as *mut winapi::ctypes::c_void);
Some(PathBuf::from(ostr))
} else {
None
}
}
}
pub fn cache_dir() -> Option<PathBuf> {
known_folder(&knownfolders::FOLDERID_LocalAppData)
}
pub fn home_dir() -> Option<PathBuf> {
if let Some(userprofile) = std::env::var_os("USERPROFILE") {
if !userprofile.is_empty() {
return Some(PathBuf::from(userprofile));
}
}
known_folder(&knownfolders::FOLDERID_Profile)
}
}

View file

@ -1,11 +1,13 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::sys::CliSys;
use super::CACHE_PERM; use super::CACHE_PERM;
use crate::util::fs::atomic_write_file_with_retries;
use deno_cache_dir::url_to_filename; use deno_cache_dir::url_to_filename;
use deno_core::url::Host; use deno_core::url::Host;
use deno_core::url::Url; use deno_core::url::Url;
use deno_path_util::fs::atomic_write_file_with_retries;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs; use std::fs;
use std::path::Component; use std::path::Component;
@ -16,14 +18,16 @@ use std::str;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DiskCache { pub struct DiskCache {
sys: CliSys,
pub location: PathBuf, pub location: PathBuf,
} }
impl DiskCache { impl DiskCache {
/// `location` must be an absolute path. /// `location` must be an absolute path.
pub fn new(location: &Path) -> Self { pub fn new(sys: CliSys, location: &Path) -> Self {
assert!(location.is_absolute()); assert!(location.is_absolute());
Self { Self {
sys,
location: location.to_owned(), location: location.to_owned(),
} }
} }
@ -120,7 +124,7 @@ impl DiskCache {
pub fn set(&self, filename: &Path, data: &[u8]) -> std::io::Result<()> { pub fn set(&self, filename: &Path, data: &[u8]) -> std::io::Result<()> {
let path = self.location.join(filename); let path = self.location.join(filename);
atomic_write_file_with_retries(&path, data, CACHE_PERM) atomic_write_file_with_retries(&self.sys, &path, data, CACHE_PERM)
} }
} }
@ -133,7 +137,7 @@ mod tests {
fn test_set_get_cache_file() { fn test_set_get_cache_file() {
let temp_dir = TempDir::new(); let temp_dir = TempDir::new();
let sub_dir = temp_dir.path().join("sub_dir"); let sub_dir = temp_dir.path().join("sub_dir");
let cache = DiskCache::new(&sub_dir.to_path_buf()); let cache = DiskCache::new(CliSys::default(), &sub_dir.to_path_buf());
let path = PathBuf::from("foo/bar.txt"); let path = PathBuf::from("foo/bar.txt");
cache.set(&path, b"hello").unwrap(); cache.set(&path, b"hello").unwrap();
assert_eq!(cache.get(&path).unwrap(), b"hello"); assert_eq!(cache.get(&path).unwrap(), b"hello");
@ -147,7 +151,7 @@ mod tests {
PathBuf::from("/deno_dir/") PathBuf::from("/deno_dir/")
}; };
let cache = DiskCache::new(&cache_location); let cache = DiskCache::new(CliSys::default(), &cache_location);
let mut test_cases = vec![ let mut test_cases = vec![
( (
@ -203,7 +207,7 @@ mod tests {
} else { } else {
"/foo" "/foo"
}; };
let cache = DiskCache::new(&PathBuf::from(p)); let cache = DiskCache::new(CliSys::default(), &PathBuf::from(p));
let mut test_cases = vec![ let mut test_cases = vec![
( (
@ -251,7 +255,7 @@ mod tests {
PathBuf::from("/deno_dir/") PathBuf::from("/deno_dir/")
}; };
let cache = DiskCache::new(&cache_location); let cache = DiskCache::new(CliSys::default(), &cache_location);
let mut test_cases = vec!["unknown://localhost/test.ts"]; let mut test_cases = vec!["unknown://localhost/test.ts"];

5
cli/cache/emit.rs vendored
View file

@ -159,12 +159,15 @@ impl EmitFileSerializer {
mod test { mod test {
use test_util::TempDir; use test_util::TempDir;
use crate::sys::CliSys;
use super::*; use super::*;
#[test] #[test]
pub fn emit_cache_general_use() { pub fn emit_cache_general_use() {
let temp_dir = TempDir::new(); let temp_dir = TempDir::new();
let disk_cache = DiskCache::new(temp_dir.path().as_path()); let disk_cache =
DiskCache::new(CliSys::default(), temp_dir.path().as_path());
let cache = EmitCache { let cache = EmitCache {
disk_cache: disk_cache.clone(), disk_cache: disk_cache.clone(),
file_serializer: EmitFileSerializer { file_serializer: EmitFileSerializer {

231
cli/cache/mod.rs vendored
View file

@ -1,18 +1,17 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::args::jsr_url; use crate::args::jsr_url;
use crate::args::CacheSetting; use crate::file_fetcher::CliFetchNoFollowErrorKind;
use crate::errors::get_error_class_name; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::FetchNoFollowOptions; use crate::file_fetcher::FetchNoFollowOptions;
use crate::file_fetcher::FetchOptions;
use crate::file_fetcher::FetchPermissionsOptionRef; use crate::file_fetcher::FetchPermissionsOptionRef;
use crate::file_fetcher::FileFetcher; use crate::sys::CliSys;
use crate::file_fetcher::FileOrRedirect;
use crate::util::fs::atomic_write_file_with_retries;
use crate::util::fs::atomic_write_file_with_retries_and_fs;
use crate::util::fs::AtomicWriteFileFsAdapter;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind;
use deno_cache_dir::file_fetcher::FileOrRedirect;
use deno_core::error::AnyError;
use deno_core::futures; use deno_core::futures;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
@ -20,15 +19,11 @@ use deno_graph::source::CacheInfo;
use deno_graph::source::LoadFuture; use deno_graph::source::LoadFuture;
use deno_graph::source::LoadResponse; use deno_graph::source::LoadResponse;
use deno_graph::source::Loader; use deno_graph::source::Loader;
use deno_runtime::deno_fs;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime;
mod cache_db; mod cache_db;
mod caches; mod caches;
@ -49,7 +44,6 @@ pub use caches::Caches;
pub use check::TypeCheckCache; pub use check::TypeCheckCache;
pub use code_cache::CodeCache; pub use code_cache::CodeCache;
pub use common::FastInsecureHasher; pub use common::FastInsecureHasher;
pub use deno_dir::dirs::home_dir;
pub use deno_dir::DenoDir; pub use deno_dir::DenoDir;
pub use deno_dir::DenoDirProvider; pub use deno_dir::DenoDirProvider;
pub use disk_cache::DiskCache; pub use disk_cache::DiskCache;
@ -62,121 +56,11 @@ pub use parsed_source::LazyGraphSourceParser;
pub use parsed_source::ParsedSourceCache; pub use parsed_source::ParsedSourceCache;
/// Permissions used to save a file in the disk caches. /// Permissions used to save a file in the disk caches.
pub const CACHE_PERM: u32 = 0o644; pub use deno_cache_dir::CACHE_PERM;
#[derive(Debug, Clone)] pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<CliSys>;
pub struct RealDenoCacheEnv; pub type LocalHttpCache = deno_cache_dir::LocalHttpCache<CliSys>;
pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>;
impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv {
fn read_file_bytes(
&self,
path: &Path,
) -> std::io::Result<Cow<'static, [u8]>> {
std::fs::read(path).map(Cow::Owned)
}
fn atomic_write_file(
&self,
path: &Path,
bytes: &[u8],
) -> std::io::Result<()> {
atomic_write_file_with_retries(path, bytes, CACHE_PERM)
}
fn canonicalize_path(&self, path: &Path) -> std::io::Result<PathBuf> {
crate::util::fs::canonicalize_path(path)
}
fn create_dir_all(&self, path: &Path) -> std::io::Result<()> {
std::fs::create_dir_all(path)
}
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
match std::fs::metadata(path) {
Ok(metadata) => Ok(Some(
metadata.modified().unwrap_or_else(|_| SystemTime::now()),
)),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err),
}
}
fn is_file(&self, path: &Path) -> bool {
path.is_file()
}
fn time_now(&self) -> SystemTime {
SystemTime::now()
}
}
#[derive(Debug, Clone)]
pub struct DenoCacheEnvFsAdapter<'a>(
pub &'a dyn deno_runtime::deno_fs::FileSystem,
);
impl<'a> deno_cache_dir::DenoCacheEnv for DenoCacheEnvFsAdapter<'a> {
fn read_file_bytes(
&self,
path: &Path,
) -> std::io::Result<Cow<'static, [u8]>> {
self
.0
.read_file_sync(path, None)
.map_err(|err| err.into_io_error())
}
fn atomic_write_file(
&self,
path: &Path,
bytes: &[u8],
) -> std::io::Result<()> {
atomic_write_file_with_retries_and_fs(
&AtomicWriteFileFsAdapter {
fs: self.0,
write_mode: CACHE_PERM,
},
path,
bytes,
)
}
fn canonicalize_path(&self, path: &Path) -> std::io::Result<PathBuf> {
self.0.realpath_sync(path).map_err(|e| e.into_io_error())
}
fn create_dir_all(&self, path: &Path) -> std::io::Result<()> {
self
.0
.mkdir_sync(path, true, None)
.map_err(|e| e.into_io_error())
}
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
self
.0
.stat_sync(path)
.map(|stat| {
stat
.mtime
.map(|ts| SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(ts))
})
.map_err(|e| e.into_io_error())
}
fn is_file(&self, path: &Path) -> bool {
self.0.is_file_sync(path)
}
fn time_now(&self) -> SystemTime {
SystemTime::now()
}
}
pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<RealDenoCacheEnv>;
pub type LocalHttpCache = deno_cache_dir::LocalHttpCache<RealDenoCacheEnv>;
pub type LocalLspHttpCache =
deno_cache_dir::LocalLspHttpCache<RealDenoCacheEnv>;
pub use deno_cache_dir::HttpCache; pub use deno_cache_dir::HttpCache;
pub struct FetchCacherOptions { pub struct FetchCacherOptions {
@ -190,31 +74,31 @@ pub struct FetchCacherOptions {
/// a concise interface to the DENO_DIR when building module graphs. /// a concise interface to the DENO_DIR when building module graphs.
pub struct FetchCacher { pub struct FetchCacher {
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>, pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
fs: Arc<dyn deno_fs::FileSystem>,
global_http_cache: Arc<GlobalHttpCache>, global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
module_info_cache: Arc<ModuleInfoCache>, module_info_cache: Arc<ModuleInfoCache>,
permissions: PermissionsContainer, permissions: PermissionsContainer,
sys: CliSys,
is_deno_publish: bool, is_deno_publish: bool,
cache_info_enabled: bool, cache_info_enabled: bool,
} }
impl FetchCacher { impl FetchCacher {
pub fn new( pub fn new(
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
fs: Arc<dyn deno_fs::FileSystem>,
global_http_cache: Arc<GlobalHttpCache>, global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
module_info_cache: Arc<ModuleInfoCache>, module_info_cache: Arc<ModuleInfoCache>,
sys: CliSys,
options: FetchCacherOptions, options: FetchCacherOptions,
) -> Self { ) -> Self {
Self { Self {
file_fetcher, file_fetcher,
fs,
global_http_cache, global_http_cache,
in_npm_pkg_checker, in_npm_pkg_checker,
module_info_cache, module_info_cache,
sys,
file_header_overrides: options.file_header_overrides, file_header_overrides: options.file_header_overrides,
permissions: options.permissions, permissions: options.permissions,
is_deno_publish: options.is_deno_publish, is_deno_publish: options.is_deno_publish,
@ -276,9 +160,8 @@ impl Loader for FetchCacher {
// symlinked to `/my-project-2/node_modules`), so first we checked if the path // symlinked to `/my-project-2/node_modules`), so first we checked if the path
// is in a node_modules dir to avoid needlessly canonicalizing, then now compare // is in a node_modules dir to avoid needlessly canonicalizing, then now compare
// against the canonicalized specifier. // against the canonicalized specifier.
let specifier = crate::node::resolve_specifier_into_node_modules( let specifier = node_resolver::resolve_specifier_into_node_modules(
specifier, &self.sys, specifier,
self.fs.as_ref(),
); );
if self.in_npm_pkg_checker.in_npm_package(&specifier) { if self.in_npm_pkg_checker.in_npm_package(&specifier) {
return Box::pin(futures::future::ready(Ok(Some( return Box::pin(futures::future::ready(Ok(Some(
@ -320,18 +203,18 @@ impl Loader for FetchCacher {
LoaderCacheSetting::Only => Some(CacheSetting::Only), LoaderCacheSetting::Only => Some(CacheSetting::Only),
}; };
file_fetcher file_fetcher
.fetch_no_follow_with_options(FetchNoFollowOptions { .fetch_no_follow(
fetch_options: FetchOptions { &specifier,
specifier: &specifier, FetchPermissionsOptionRef::Restricted(&permissions,
permissions: if is_statically_analyzable { if is_statically_analyzable {
FetchPermissionsOptionRef::StaticContainer(&permissions) deno_runtime::deno_permissions::CheckSpecifierKind::Static
} else { } else {
FetchPermissionsOptionRef::DynamicContainer(&permissions) deno_runtime::deno_permissions::CheckSpecifierKind::Dynamic
}, }),
maybe_auth: None, FetchNoFollowOptions {
maybe_accept: None, maybe_auth: None,
maybe_cache_setting: maybe_cache_setting.as_ref(), maybe_accept: None,
}, maybe_cache_setting: maybe_cache_setting.as_ref(),
maybe_checksum: options.maybe_checksum.as_ref(), maybe_checksum: options.maybe_checksum.as_ref(),
}) })
.await .await
@ -348,7 +231,7 @@ impl Loader for FetchCacher {
(None, None) => None, (None, None) => None,
}; };
Ok(Some(LoadResponse::Module { Ok(Some(LoadResponse::Module {
specifier: file.specifier, specifier: file.url,
maybe_headers, maybe_headers,
content: file.source, content: file.source,
})) }))
@ -361,18 +244,46 @@ impl Loader for FetchCacher {
} }
}) })
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
if let Some(io_err) = err.downcast_ref::<std::io::Error>() { let err = err.into_kind();
if io_err.kind() == std::io::ErrorKind::NotFound { match err {
return Ok(None); CliFetchNoFollowErrorKind::FetchNoFollow(err) => {
} else { let err = err.into_kind();
return Err(err); match err {
} FetchNoFollowErrorKind::NotFound(_) => Ok(None),
} FetchNoFollowErrorKind::UrlToFilePath { .. } |
let error_class_name = get_error_class_name(&err); FetchNoFollowErrorKind::ReadingBlobUrl { .. } |
match error_class_name { FetchNoFollowErrorKind::ReadingFile { .. } |
"NotFound" => Ok(None), FetchNoFollowErrorKind::FetchingRemote { .. } |
"NotCached" if options.cache_setting == LoaderCacheSetting::Only => Ok(None), FetchNoFollowErrorKind::ClientError { .. } |
_ => Err(err), FetchNoFollowErrorKind::NoRemote { .. } |
FetchNoFollowErrorKind::DataUrlDecode { .. } |
FetchNoFollowErrorKind::RedirectResolution { .. } |
FetchNoFollowErrorKind::CacheRead { .. } |
FetchNoFollowErrorKind::CacheSave { .. } |
FetchNoFollowErrorKind::UnsupportedScheme { .. } |
FetchNoFollowErrorKind::RedirectHeaderParse { .. } |
FetchNoFollowErrorKind::InvalidHeader { .. } => Err(AnyError::from(err)),
FetchNoFollowErrorKind::NotCached { .. } => {
if options.cache_setting == LoaderCacheSetting::Only {
Ok(None)
} else {
Err(AnyError::from(err))
}
},
FetchNoFollowErrorKind::ChecksumIntegrity(err) => {
// convert to the equivalent deno_graph error so that it
// enhances it if this is passed to deno_graph
Err(
deno_graph::source::ChecksumIntegrityError {
actual: err.actual,
expected: err.expected,
}
.into(),
)
}
}
},
CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(AnyError::from(permission_check_error)),
} }
}) })
} }

View file

@ -4,6 +4,7 @@ disallowed-methods = [
] ]
disallowed-types = [ disallowed-types = [
{ path = "reqwest::Client", reason = "use crate::http_util::HttpClient instead" }, { path = "reqwest::Client", reason = "use crate::http_util::HttpClient instead" },
{ path = "sys_traits::impls::RealSys", reason = "use crate::sys::CliSys instead" },
] ]
ignore-interior-mutability = [ ignore-interior-mutability = [
"lsp_types::Uri", "lsp_types::Uri",

View file

@ -5,6 +5,7 @@ use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use deno_ast::EmittedSourceText;
use deno_ast::ModuleKind; use deno_ast::ModuleKind;
use deno_ast::SourceMapOption; use deno_ast::SourceMapOption;
use deno_ast::SourceRange; use deno_ast::SourceRange;
@ -132,6 +133,7 @@ impl Emitter {
&transpile_and_emit_options.0, &transpile_and_emit_options.0,
&transpile_and_emit_options.1, &transpile_and_emit_options.1,
) )
.map(|r| r.text)
} }
}) })
.await .await
@ -166,7 +168,8 @@ impl Emitter {
source.clone(), source.clone(),
&self.transpile_and_emit_options.0, &self.transpile_and_emit_options.0,
&self.transpile_and_emit_options.1, &self.transpile_and_emit_options.1,
)?; )?
.text;
helper.post_emit_parsed_source( helper.post_emit_parsed_source(
specifier, specifier,
&transpiled_source, &transpiled_source,
@ -177,6 +180,31 @@ impl Emitter {
} }
} }
pub fn emit_parsed_source_for_deno_compile(
&self,
specifier: &ModuleSpecifier,
media_type: MediaType,
module_kind: deno_ast::ModuleKind,
source: &Arc<str>,
) -> Result<(String, String), AnyError> {
let mut emit_options = self.transpile_and_emit_options.1.clone();
emit_options.inline_sources = false;
emit_options.source_map = SourceMapOption::Separate;
// strip off the path to have more deterministic builds as we don't care
// about the source name because we manually provide the source map to v8
emit_options.source_map_base = Some(deno_path_util::url_parent(specifier));
let source = EmitParsedSourceHelper::transpile(
&self.parsed_source_cache,
specifier,
media_type,
module_kind,
source.clone(),
&self.transpile_and_emit_options.0,
&emit_options,
)?;
Ok((source.text, source.source_map.unwrap()))
}
/// Expects a file URL, panics otherwise. /// Expects a file URL, panics otherwise.
pub async fn load_and_emit_for_hmr( pub async fn load_and_emit_for_hmr(
&self, &self,
@ -282,7 +310,7 @@ impl<'a> EmitParsedSourceHelper<'a> {
source: Arc<str>, source: Arc<str>,
transpile_options: &deno_ast::TranspileOptions, transpile_options: &deno_ast::TranspileOptions,
emit_options: &deno_ast::EmitOptions, emit_options: &deno_ast::EmitOptions,
) -> Result<String, AnyError> { ) -> Result<EmittedSourceText, AnyError> {
// nothing else needs the parsed source at this point, so remove from // nothing else needs the parsed source at this point, so remove from
// the cache in order to not transpile owned // the cache in order to not transpile owned
let parsed_source = parsed_source_cache let parsed_source = parsed_source_cache
@ -302,8 +330,7 @@ impl<'a> EmitParsedSourceHelper<'a> {
source source
} }
}; };
debug_assert!(transpiled_source.source_map.is_none()); Ok(transpiled_source)
Ok(transpiled_source.text)
} }
pub fn post_emit_parsed_source( pub fn post_emit_parsed_source(

View file

@ -11,7 +11,6 @@ use crate::args::StorageKeyResolver;
use crate::args::TsConfigType; use crate::args::TsConfigType;
use crate::cache::Caches; use crate::cache::Caches;
use crate::cache::CodeCache; use crate::cache::CodeCache;
use crate::cache::DenoCacheEnvFsAdapter;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::cache::DenoDirProvider; use crate::cache::DenoDirProvider;
use crate::cache::EmitCache; use crate::cache::EmitCache;
@ -22,7 +21,7 @@ use crate::cache::ModuleInfoCache;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::emit::Emitter; use crate::emit::Emitter;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::graph_container::MainModuleGraphContainer; use crate::graph_container::MainModuleGraphContainer;
use crate::graph_util::FileWatcherReporter; use crate::graph_util::FileWatcherReporter;
use crate::graph_util::ModuleGraphBuilder; use crate::graph_util::ModuleGraphBuilder;
@ -32,6 +31,8 @@ use crate::module_loader::CliModuleLoaderFactory;
use crate::module_loader::ModuleLoadPreparer; use crate::module_loader::ModuleLoadPreparer;
use crate::node::CliCjsCodeAnalyzer; use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver; use crate::npm::create_cli_npm_resolver;
use crate::npm::create_in_npm_pkg_checker; use crate::npm::create_in_npm_pkg_checker;
use crate::npm::CliByonmNpmResolverCreateOptions; use crate::npm::CliByonmNpmResolverCreateOptions;
@ -43,14 +44,14 @@ use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions; use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::resolver::CliDenoResolver; use crate::resolver::CliDenoResolver;
use crate::resolver::CliDenoResolverFs;
use crate::resolver::CliNpmReqResolver; use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::resolver::CliResolverOptions; use crate::resolver::CliResolverOptions;
use crate::resolver::CliSloppyImportsResolver; use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::NpmModuleLoader; use crate::resolver::NpmModuleLoader;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::standalone::DenoCompileBinaryWriter; use crate::standalone::binary::DenoCompileBinaryWriter;
use crate::sys::CliSys;
use crate::tools::check::TypeChecker; use crate::tools::check::TypeChecker;
use crate::tools::coverage::CoverageCollector; use crate::tools::coverage::CoverageCollector;
use crate::tools::lint::LintRuleProvider; use crate::tools::lint::LintRuleProvider;
@ -76,9 +77,8 @@ use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions; use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmReqResolver; use deno_resolver::NodeAndNpmReqResolver;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_node::DenoFsNodeResolverEnv; use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use deno_runtime::deno_node::PackageJsonResolver;
use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::rustls::RootCertStore;
@ -185,7 +185,7 @@ struct CliFactoryServices {
emit_cache: Deferred<Arc<EmitCache>>, emit_cache: Deferred<Arc<EmitCache>>,
emitter: Deferred<Arc<Emitter>>, emitter: Deferred<Arc<Emitter>>,
feature_checker: Deferred<Arc<FeatureChecker>>, feature_checker: Deferred<Arc<FeatureChecker>>,
file_fetcher: Deferred<Arc<FileFetcher>>, file_fetcher: Deferred<Arc<CliFileFetcher>>,
fs: Deferred<Arc<dyn deno_fs::FileSystem>>, fs: Deferred<Arc<dyn deno_fs::FileSystem>>,
global_http_cache: Deferred<Arc<GlobalHttpCache>>, global_http_cache: Deferred<Arc<GlobalHttpCache>>,
http_cache: Deferred<Arc<dyn HttpCache>>, http_cache: Deferred<Arc<dyn HttpCache>>,
@ -199,13 +199,14 @@ struct CliFactoryServices {
module_info_cache: Deferred<Arc<ModuleInfoCache>>, module_info_cache: Deferred<Arc<ModuleInfoCache>>,
module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>, module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>,
node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>, node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>,
node_resolver: Deferred<Arc<NodeResolver>>, node_resolver: Deferred<Arc<CliNodeResolver>>,
npm_cache_dir: Deferred<Arc<NpmCacheDir>>, npm_cache_dir: Deferred<Arc<NpmCacheDir>>,
npm_req_resolver: Deferred<Arc<CliNpmReqResolver>>, npm_req_resolver: Deferred<Arc<CliNpmReqResolver>>,
npm_resolver: Deferred<Arc<dyn CliNpmResolver>>, npm_resolver: Deferred<Arc<dyn CliNpmResolver>>,
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>, parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>, permission_desc_parser:
pkg_json_resolver: Deferred<Arc<PackageJsonResolver>>, Deferred<Arc<RuntimePermissionDescriptorParser<CliSys>>>,
pkg_json_resolver: Deferred<Arc<CliPackageJsonResolver>>,
resolver: Deferred<Arc<CliResolver>>, resolver: Deferred<Arc<CliResolver>>,
root_cert_store_provider: Deferred<Arc<dyn RootCertStoreProvider>>, root_cert_store_provider: Deferred<Arc<dyn RootCertStoreProvider>>,
root_permissions_container: Deferred<PermissionsContainer>, root_permissions_container: Deferred<PermissionsContainer>,
@ -255,7 +256,7 @@ impl CliFactory {
pub fn cli_options(&self) -> Result<&Arc<CliOptions>, AnyError> { pub fn cli_options(&self) -> Result<&Arc<CliOptions>, AnyError> {
self.services.cli_options.get_or_try_init(|| { self.services.cli_options.get_or_try_init(|| {
CliOptions::from_flags(self.flags.clone()).map(Arc::new) CliOptions::from_flags(&self.sys(), self.flags.clone()).map(Arc::new)
}) })
} }
@ -318,8 +319,8 @@ impl CliFactory {
pub fn global_http_cache(&self) -> Result<&Arc<GlobalHttpCache>, AnyError> { pub fn global_http_cache(&self) -> Result<&Arc<GlobalHttpCache>, AnyError> {
self.services.global_http_cache.get_or_try_init(|| { self.services.global_http_cache.get_or_try_init(|| {
Ok(Arc::new(GlobalHttpCache::new( Ok(Arc::new(GlobalHttpCache::new(
self.sys(),
self.deno_dir()?.remote_folder_path(), self.deno_dir()?.remote_folder_path(),
crate::cache::RealDenoCacheEnv,
))) )))
}) })
} }
@ -350,22 +351,28 @@ impl CliFactory {
}) })
} }
pub fn file_fetcher(&self) -> Result<&Arc<FileFetcher>, AnyError> { pub fn file_fetcher(&self) -> Result<&Arc<CliFileFetcher>, AnyError> {
self.services.file_fetcher.get_or_try_init(|| { self.services.file_fetcher.get_or_try_init(|| {
let cli_options = self.cli_options()?; let cli_options = self.cli_options()?;
Ok(Arc::new(FileFetcher::new( Ok(Arc::new(CliFileFetcher::new(
self.http_cache()?.clone(), self.http_cache()?.clone(),
cli_options.cache_setting(),
!cli_options.no_remote(),
self.http_client_provider().clone(), self.http_client_provider().clone(),
self.sys(),
self.blob_store().clone(), self.blob_store().clone(),
Some(self.text_only_progress_bar().clone()), Some(self.text_only_progress_bar().clone()),
!cli_options.no_remote(),
cli_options.cache_setting(),
log::Level::Info,
))) )))
}) })
} }
pub fn fs(&self) -> &Arc<dyn deno_fs::FileSystem> { pub fn fs(&self) -> &Arc<dyn deno_fs::FileSystem> {
self.services.fs.get_or_init(|| Arc::new(deno_fs::RealFs)) self.services.fs.get_or_init(|| Arc::new(RealFs))
}
pub fn sys(&self) -> CliSys {
CliSys::default() // very cheap to make
} }
pub fn in_npm_pkg_checker( pub fn in_npm_pkg_checker(
@ -391,11 +398,10 @@ impl CliFactory {
pub fn npm_cache_dir(&self) -> Result<&Arc<NpmCacheDir>, AnyError> { pub fn npm_cache_dir(&self) -> Result<&Arc<NpmCacheDir>, AnyError> {
self.services.npm_cache_dir.get_or_try_init(|| { self.services.npm_cache_dir.get_or_try_init(|| {
let fs = self.fs();
let global_path = self.deno_dir()?.npm_folder_path(); let global_path = self.deno_dir()?.npm_folder_path();
let cli_options = self.cli_options()?; let cli_options = self.cli_options()?;
Ok(Arc::new(NpmCacheDir::new( Ok(Arc::new(NpmCacheDir::new(
&DenoCacheEnvFsAdapter(fs.as_ref()), &self.sys(),
global_path, global_path,
cli_options.npmrc().get_all_known_registries_urls(), cli_options.npmrc().get_all_known_registries_urls(),
))) )))
@ -410,12 +416,11 @@ impl CliFactory {
.npm_resolver .npm_resolver
.get_or_try_init_async( .get_or_try_init_async(
async { async {
let fs = self.fs();
let cli_options = self.cli_options()?; let cli_options = self.cli_options()?;
create_cli_npm_resolver(if cli_options.use_byonm() { create_cli_npm_resolver(if cli_options.use_byonm() {
CliNpmResolverCreateOptions::Byonm( CliNpmResolverCreateOptions::Byonm(
CliByonmNpmResolverCreateOptions { CliByonmNpmResolverCreateOptions {
fs: CliDenoResolverFs(fs.clone()), sys: self.sys(),
pkg_json_resolver: self.pkg_json_resolver().clone(), pkg_json_resolver: self.pkg_json_resolver().clone(),
root_node_modules_dir: Some( root_node_modules_dir: Some(
match cli_options.node_modules_dir_path() { match cli_options.node_modules_dir_path() {
@ -433,6 +438,13 @@ impl CliFactory {
} else { } else {
CliNpmResolverCreateOptions::Managed( CliNpmResolverCreateOptions::Managed(
CliManagedNpmResolverCreateOptions { CliManagedNpmResolverCreateOptions {
http_client_provider: self.http_client_provider().clone(),
npm_install_deps_provider: Arc::new(
NpmInstallDepsProvider::from_workspace(
cli_options.workspace(),
),
),
sys: self.sys(),
snapshot: match cli_options.resolve_npm_resolution_snapshot()? { snapshot: match cli_options.resolve_npm_resolution_snapshot()? {
Some(snapshot) => { Some(snapshot) => {
CliNpmResolverManagedSnapshotOption::Specified(Some( CliNpmResolverManagedSnapshotOption::Specified(Some(
@ -451,19 +463,12 @@ impl CliFactory {
}, },
}, },
maybe_lockfile: cli_options.maybe_lockfile().cloned(), maybe_lockfile: cli_options.maybe_lockfile().cloned(),
fs: fs.clone(),
http_client_provider: self.http_client_provider().clone(),
npm_cache_dir: self.npm_cache_dir()?.clone(), npm_cache_dir: self.npm_cache_dir()?.clone(),
cache_setting: cli_options.cache_setting(), cache_setting: cli_options.cache_setting(),
text_only_progress_bar: self.text_only_progress_bar().clone(), text_only_progress_bar: self.text_only_progress_bar().clone(),
maybe_node_modules_path: cli_options maybe_node_modules_path: cli_options
.node_modules_dir_path() .node_modules_dir_path()
.cloned(), .cloned(),
npm_install_deps_provider: Arc::new(
NpmInstallDepsProvider::from_workspace(
cli_options.workspace(),
),
),
npm_system_info: cli_options.npm_system_info(), npm_system_info: cli_options.npm_system_info(),
npmrc: cli_options.npmrc().clone(), npmrc: cli_options.npmrc().clone(),
lifecycle_scripts: cli_options.lifecycle_scripts_config(), lifecycle_scripts: cli_options.lifecycle_scripts_config(),
@ -486,7 +491,7 @@ impl CliFactory {
.get_or_try_init(|| { .get_or_try_init(|| {
Ok(self.cli_options()?.unstable_sloppy_imports().then(|| { Ok(self.cli_options()?.unstable_sloppy_imports().then(|| {
Arc::new(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new( Arc::new(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(
self.fs().clone(), self.sys(),
))) )))
})) }))
}) })
@ -647,21 +652,22 @@ impl CliFactory {
)) ))
} }
pub async fn node_resolver(&self) -> Result<&Arc<NodeResolver>, AnyError> { pub async fn node_resolver(&self) -> Result<&Arc<CliNodeResolver>, AnyError> {
self self
.services .services
.node_resolver .node_resolver
.get_or_try_init_async( .get_or_try_init_async(
async { async {
Ok(Arc::new(NodeResolver::new( Ok(Arc::new(CliNodeResolver::new(
DenoFsNodeResolverEnv::new(self.fs().clone()),
self.in_npm_pkg_checker()?.clone(), self.in_npm_pkg_checker()?.clone(),
RealIsBuiltInNodeModuleChecker,
self self
.npm_resolver() .npm_resolver()
.await? .await?
.clone() .clone()
.into_npm_pkg_folder_resolver(), .into_npm_pkg_folder_resolver(),
self.pkg_json_resolver().clone(), self.pkg_json_resolver().clone(),
self.sys(),
))) )))
} }
.boxed_local(), .boxed_local(),
@ -689,7 +695,6 @@ impl CliFactory {
Ok(Arc::new(NodeCodeTranslator::new( Ok(Arc::new(NodeCodeTranslator::new(
cjs_esm_analyzer, cjs_esm_analyzer,
DenoFsNodeResolverEnv::new(self.fs().clone()),
self.in_npm_pkg_checker()?.clone(), self.in_npm_pkg_checker()?.clone(),
node_resolver, node_resolver,
self self
@ -698,6 +703,7 @@ impl CliFactory {
.clone() .clone()
.into_npm_pkg_folder_resolver(), .into_npm_pkg_folder_resolver(),
self.pkg_json_resolver().clone(), self.pkg_json_resolver().clone(),
self.sys(),
))) )))
}) })
.await .await
@ -713,7 +719,7 @@ impl CliFactory {
let npm_resolver = self.npm_resolver().await?; let npm_resolver = self.npm_resolver().await?;
Ok(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { Ok(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions {
byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(),
fs: CliDenoResolverFs(self.fs().clone()), sys: self.sys(),
in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(), in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(),
node_resolver: self.node_resolver().await?.clone(), node_resolver: self.node_resolver().await?.clone(),
npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(),
@ -722,12 +728,11 @@ impl CliFactory {
.await .await
} }
pub fn pkg_json_resolver(&self) -> &Arc<PackageJsonResolver> { pub fn pkg_json_resolver(&self) -> &Arc<CliPackageJsonResolver> {
self.services.pkg_json_resolver.get_or_init(|| { self
Arc::new(PackageJsonResolver::new(DenoFsNodeResolverEnv::new( .services
self.fs().clone(), .pkg_json_resolver
))) .get_or_init(|| Arc::new(CliPackageJsonResolver::new(self.sys())))
})
} }
pub async fn type_checker(&self) -> Result<&Arc<TypeChecker>, AnyError> { pub async fn type_checker(&self) -> Result<&Arc<TypeChecker>, AnyError> {
@ -764,7 +769,6 @@ impl CliFactory {
self.cjs_tracker()?.clone(), self.cjs_tracker()?.clone(),
cli_options.clone(), cli_options.clone(),
self.file_fetcher()?.clone(), self.file_fetcher()?.clone(),
self.fs().clone(),
self.global_http_cache()?.clone(), self.global_http_cache()?.clone(),
self.in_npm_pkg_checker()?.clone(), self.in_npm_pkg_checker()?.clone(),
cli_options.maybe_lockfile().cloned(), cli_options.maybe_lockfile().cloned(),
@ -774,6 +778,7 @@ impl CliFactory {
self.parsed_source_cache().clone(), self.parsed_source_cache().clone(),
self.resolver().await?.clone(), self.resolver().await?.clone(),
self.root_permissions_container()?.clone(), self.root_permissions_container()?.clone(),
self.sys(),
))) )))
}) })
.await .await
@ -863,10 +868,9 @@ impl CliFactory {
pub fn permission_desc_parser( pub fn permission_desc_parser(
&self, &self,
) -> Result<&Arc<RuntimePermissionDescriptorParser>, AnyError> { ) -> Result<&Arc<RuntimePermissionDescriptorParser<CliSys>>, AnyError> {
self.services.permission_desc_parser.get_or_try_init(|| { self.services.permission_desc_parser.get_or_try_init(|| {
let fs = self.fs().clone(); Ok(Arc::new(RuntimePermissionDescriptorParser::new(self.sys())))
Ok(Arc::new(RuntimePermissionDescriptorParser::new(fs)))
}) })
} }
@ -959,7 +963,6 @@ impl CliFactory {
None None
}, },
self.emitter()?.clone(), self.emitter()?.clone(),
fs.clone(),
in_npm_pkg_checker.clone(), in_npm_pkg_checker.clone(),
self.main_module_graph_container().await?.clone(), self.main_module_graph_container().await?.clone(),
self.module_load_preparer().await?.clone(), self.module_load_preparer().await?.clone(),
@ -974,6 +977,7 @@ impl CliFactory {
), ),
self.parsed_source_cache().clone(), self.parsed_source_cache().clone(),
self.resolver().await?.clone(), self.resolver().await?.clone(),
self.sys(),
)), )),
node_resolver.clone(), node_resolver.clone(),
npm_resolver.clone(), npm_resolver.clone(),
@ -981,6 +985,7 @@ impl CliFactory {
self.root_cert_store_provider().clone(), self.root_cert_store_provider().clone(),
self.root_permissions_container()?.clone(), self.root_permissions_container()?.clone(),
StorageKeyResolver::from_options(cli_options), StorageKeyResolver::from_options(cli_options),
self.sys(),
cli_options.sub_command().clone(), cli_options.sub_command().clone(),
self.create_cli_main_worker_options()?, self.create_cli_main_worker_options()?,
self.cli_options()?.otel_config(), self.cli_options()?.otel_config(),

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,42 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::collections::HashSet;
use std::error::Error;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier;
use deno_graph::source::Loader;
use deno_graph::source::LoaderChecksum;
use deno_graph::source::ResolutionKind;
use deno_graph::source::ResolveError;
use deno_graph::FillFromLockfileOptions;
use deno_graph::GraphKind;
use deno_graph::JsrLoadError;
use deno_graph::ModuleError;
use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::ModuleLoadError;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_graph::WorkspaceFastCheckOption;
use deno_path_util::url_to_file_path;
use deno_resolver::sloppy_imports::SloppyImportsResolutionKind;
use deno_runtime::deno_node;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv;
use deno_semver::SmallStackString;
use import_map::ImportMapError;
use node_resolver::InNpmPackageChecker;
use crate::args::config_to_deno_graph_workspace_member; use crate::args::config_to_deno_graph_workspace_member;
use crate::args::jsr_url; use crate::args::jsr_url;
use crate::args::CliLockfile; use crate::args::CliLockfile;
@ -13,52 +50,17 @@ use crate::cache::ModuleInfoCache;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::colors; use crate::colors;
use crate::errors::get_error_class_name; use crate::errors::get_error_class_name;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::resolver::CliSloppyImportsResolver; use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::sys::CliSys;
use crate::tools::check; use crate::tools::check;
use crate::tools::check::TypeChecker; use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail;
use deno_graph::source::LoaderChecksum;
use deno_graph::source::ResolutionKind;
use deno_graph::FillFromLockfileOptions;
use deno_graph::JsrLoadError;
use deno_graph::ModuleLoadError;
use deno_graph::WorkspaceFastCheckOption;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier;
use deno_graph::source::Loader;
use deno_graph::source::ResolveError;
use deno_graph::GraphKind;
use deno_graph::ModuleError;
use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_path_util::url_to_file_path;
use deno_resolver::sloppy_imports::SloppyImportsResolutionKind;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv;
use import_map::ImportMapError;
use node_resolver::InNpmPackageChecker;
use std::collections::HashSet;
use std::error::Error;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Clone)] #[derive(Clone)]
pub struct GraphValidOptions { pub struct GraphValidOptions {
@ -79,7 +81,7 @@ pub struct GraphValidOptions {
/// for the CLI. /// for the CLI.
pub fn graph_valid( pub fn graph_valid(
graph: &ModuleGraph, graph: &ModuleGraph,
fs: &Arc<dyn FileSystem>, sys: &CliSys,
roots: &[ModuleSpecifier], roots: &[ModuleSpecifier],
options: GraphValidOptions, options: GraphValidOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
@ -89,7 +91,7 @@ pub fn graph_valid(
let mut errors = graph_walk_errors( let mut errors = graph_walk_errors(
graph, graph,
fs, sys,
roots, roots,
GraphWalkErrorsOptions { GraphWalkErrorsOptions {
check_js: options.check_js, check_js: options.check_js,
@ -139,7 +141,7 @@ pub struct GraphWalkErrorsOptions {
/// and enhances them with CLI information. /// and enhances them with CLI information.
pub fn graph_walk_errors<'a>( pub fn graph_walk_errors<'a>(
graph: &'a ModuleGraph, graph: &'a ModuleGraph,
fs: &'a Arc<dyn FileSystem>, sys: &'a CliSys,
roots: &'a [ModuleSpecifier], roots: &'a [ModuleSpecifier],
options: GraphWalkErrorsOptions, options: GraphWalkErrorsOptions,
) -> impl Iterator<Item = AnyError> + 'a { ) -> impl Iterator<Item = AnyError> + 'a {
@ -174,7 +176,7 @@ pub fn graph_walk_errors<'a>(
} }
ModuleGraphError::ModuleError(error) => { ModuleGraphError::ModuleError(error) => {
enhanced_integrity_error_message(error) enhanced_integrity_error_message(error)
.or_else(|| enhanced_sloppy_imports_error_message(fs, error)) .or_else(|| enhanced_sloppy_imports_error_message(sys, error))
.unwrap_or_else(|| format_deno_graph_error(error)) .unwrap_or_else(|| format_deno_graph_error(error))
} }
}; };
@ -431,8 +433,7 @@ pub struct ModuleGraphBuilder {
caches: Arc<cache::Caches>, caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
fs: Arc<dyn FileSystem>,
global_http_cache: Arc<GlobalHttpCache>, global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
lockfile: Option<Arc<CliLockfile>>, lockfile: Option<Arc<CliLockfile>>,
@ -442,6 +443,7 @@ pub struct ModuleGraphBuilder {
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer, root_permissions_container: PermissionsContainer,
sys: CliSys,
} }
impl ModuleGraphBuilder { impl ModuleGraphBuilder {
@ -450,8 +452,7 @@ impl ModuleGraphBuilder {
caches: Arc<cache::Caches>, caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
fs: Arc<dyn FileSystem>,
global_http_cache: Arc<GlobalHttpCache>, global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
lockfile: Option<Arc<CliLockfile>>, lockfile: Option<Arc<CliLockfile>>,
@ -461,13 +462,13 @@ impl ModuleGraphBuilder {
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer, root_permissions_container: PermissionsContainer,
sys: CliSys,
) -> Self { ) -> Self {
Self { Self {
caches, caches,
cjs_tracker, cjs_tracker,
cli_options, cli_options,
file_fetcher, file_fetcher,
fs,
global_http_cache, global_http_cache,
in_npm_pkg_checker, in_npm_pkg_checker,
lockfile, lockfile,
@ -477,6 +478,7 @@ impl ModuleGraphBuilder {
parsed_source_cache, parsed_source_cache,
resolver, resolver,
root_permissions_container, root_permissions_container,
sys,
} }
} }
@ -592,7 +594,7 @@ impl ModuleGraphBuilder {
is_dynamic: options.is_dynamic, is_dynamic: options.is_dynamic,
passthrough_jsr_specifiers: false, passthrough_jsr_specifiers: false,
executor: Default::default(), executor: Default::default(),
file_system: &DenoGraphFsAdapter(self.fs.as_ref()), file_system: &self.sys,
jsr_url_provider: &CliJsrUrlProvider, jsr_url_provider: &CliJsrUrlProvider,
npm_resolver: Some(&graph_npm_resolver), npm_resolver: Some(&graph_npm_resolver),
module_analyzer: &analyzer, module_analyzer: &analyzer,
@ -680,7 +682,7 @@ impl ModuleGraphBuilder {
for (from, to) in graph.packages.mappings() { for (from, to) in graph.packages.mappings() {
lockfile.insert_package_specifier( lockfile.insert_package_specifier(
JsrDepPackageReq::jsr(from.clone()), JsrDepPackageReq::jsr(from.clone()),
to.version.to_string(), to.version.to_custom_string::<SmallStackString>(),
); );
} }
} }
@ -746,10 +748,10 @@ impl ModuleGraphBuilder {
) -> cache::FetchCacher { ) -> cache::FetchCacher {
cache::FetchCacher::new( cache::FetchCacher::new(
self.file_fetcher.clone(), self.file_fetcher.clone(),
self.fs.clone(),
self.global_http_cache.clone(), self.global_http_cache.clone(),
self.in_npm_pkg_checker.clone(), self.in_npm_pkg_checker.clone(),
self.module_info_cache.clone(), self.module_info_cache.clone(),
self.sys.clone(),
cache::FetchCacherOptions { cache::FetchCacherOptions {
file_header_overrides: self.cli_options.resolve_file_header_overrides(), file_header_overrides: self.cli_options.resolve_file_header_overrides(),
permissions, permissions,
@ -778,7 +780,7 @@ impl ModuleGraphBuilder {
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
graph_valid( graph_valid(
graph, graph,
&self.fs, &self.sys,
roots, roots,
GraphValidOptions { GraphValidOptions {
kind: if self.cli_options.type_check_mode().is_true() { kind: if self.cli_options.type_check_mode().is_true() {
@ -834,13 +836,13 @@ pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
} }
fn enhanced_sloppy_imports_error_message( fn enhanced_sloppy_imports_error_message(
fs: &Arc<dyn FileSystem>, sys: &CliSys,
error: &ModuleError, error: &ModuleError,
) -> Option<String> { ) -> Option<String> {
match error { match error {
ModuleError::LoadingErr(specifier, _, ModuleLoadError::Loader(_)) // ex. "Is a directory" error ModuleError::LoadingErr(specifier, _, ModuleLoadError::Loader(_)) // ex. "Is a directory" error
| ModuleError::Missing(specifier, _) => { | ModuleError::Missing(specifier, _) => {
let additional_message = CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(fs.clone())) let additional_message = CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(sys.clone()))
.resolve(specifier, SloppyImportsResolutionKind::Execution)? .resolve(specifier, SloppyImportsResolutionKind::Execution)?
.as_suggestion_message(); .as_suggestion_message();
Some(format!( Some(format!(
@ -1081,71 +1083,6 @@ impl deno_graph::source::Reporter for FileWatcherReporter {
} }
} }
pub struct DenoGraphFsAdapter<'a>(
pub &'a dyn deno_runtime::deno_fs::FileSystem,
);
impl<'a> deno_graph::source::FileSystem for DenoGraphFsAdapter<'a> {
fn read_dir(
&self,
dir_url: &deno_graph::ModuleSpecifier,
) -> Vec<deno_graph::source::DirEntry> {
use deno_core::anyhow;
use deno_graph::source::DirEntry;
use deno_graph::source::DirEntryKind;
let dir_path = match dir_url.to_file_path() {
Ok(path) => path,
// ignore, treat as non-analyzable
Err(()) => return vec![],
};
let entries = match self.0.read_dir_sync(&dir_path) {
Ok(dir) => dir,
Err(err)
if matches!(
err.kind(),
std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::NotFound
) =>
{
return vec![];
}
Err(err) => {
return vec![DirEntry {
kind: DirEntryKind::Error(
anyhow::Error::from(err)
.context("Failed to read directory.".to_string()),
),
url: dir_url.clone(),
}];
}
};
let mut dir_entries = Vec::with_capacity(entries.len());
for entry in entries {
let entry_path = dir_path.join(&entry.name);
dir_entries.push(if entry.is_directory {
DirEntry {
kind: DirEntryKind::Dir,
url: ModuleSpecifier::from_directory_path(&entry_path).unwrap(),
}
} else if entry.is_file {
DirEntry {
kind: DirEntryKind::File,
url: ModuleSpecifier::from_file_path(&entry_path).unwrap(),
}
} else if entry.is_symlink {
DirEntry {
kind: DirEntryKind::Symlink,
url: ModuleSpecifier::from_file_path(&entry_path).unwrap(),
}
} else {
continue;
});
}
dir_entries
}
}
pub fn format_range_with_colors(referrer: &deno_graph::Range) -> String { pub fn format_range_with_colors(referrer: &deno_graph::Range) -> String {
format!( format!(
"{}:{}:{}", "{}:{}:{}",

File diff suppressed because it is too large Load diff

1122
cli/js/40_lint.js Normal file

File diff suppressed because it is too large Load diff

1014
cli/js/40_lint_selector.js Normal file

File diff suppressed because it is too large Load diff

132
cli/js/40_lint_types.d.ts vendored Normal file
View file

@ -0,0 +1,132 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
export interface NodeFacade {
type: string;
range: [number, number];
[key: string]: unknown;
}
export interface AstContext {
buf: Uint8Array;
strTable: Map<number, string>;
strTableOffset: number;
rootOffset: number;
nodes: Map<number, NodeFacade>;
strByType: number[];
strByProp: number[];
typeByStr: Map<string, number>;
propByStr: Map<string, number>;
matcher: MatchContext;
}
// TODO(@marvinhagemeister) Remove once we land "official" types
export interface RuleContext {
id: string;
}
// TODO(@marvinhagemeister) Remove once we land "official" types
export interface LintRule {
create(ctx: RuleContext): Record<string, (node: unknown) => void>;
destroy?(ctx: RuleContext): void;
}
// TODO(@marvinhagemeister) Remove once we land "official" types
export interface LintPlugin {
name: string;
rules: Record<string, LintRule>;
}
export interface LintState {
plugins: LintPlugin[];
installedPlugins: Set<string>;
}
export type VisitorFn = (node: unknown) => void;
export interface CompiledVisitor {
matcher: (ctx: MatchContext, offset: number) => boolean;
info: { enter: VisitorFn; exit: VisitorFn };
}
export interface AttrExists {
type: 3;
prop: number[];
}
export interface AttrBin {
type: 4;
prop: number[];
op: number;
// deno-lint-ignore no-explicit-any
value: any;
}
export type AttrSelector = AttrExists | AttrBin;
export interface ElemSelector {
type: 1;
wildcard: boolean;
elem: number;
}
export interface PseudoNthChild {
type: 5;
op: string | null;
step: number;
stepOffset: number;
of: Selector | null;
repeat: boolean;
}
export interface PseudoHas {
type: 6;
selectors: Selector[];
}
export interface PseudoNot {
type: 7;
selectors: Selector[];
}
export interface PseudoFirstChild {
type: 8;
}
export interface PseudoLastChild {
type: 9;
}
export interface Relation {
type: 2;
op: number;
}
export type Selector = Array<
| ElemSelector
| Relation
| AttrExists
| AttrBin
| PseudoNthChild
| PseudoNot
| PseudoHas
| PseudoFirstChild
| PseudoLastChild
>;
export interface SelectorParseCtx {
root: Selector;
current: Selector;
}
export interface MatchContext {
getFirstChild(id: number): number;
getLastChild(id: number): number;
getSiblings(id: number): number[];
getParent(id: number): number;
getType(id: number): number;
hasAttrPath(id: number, propIds: number[], idx: number): boolean;
getAttrPathValue(id: number, propIds: number[], idx: number): unknown;
}
export type NextFn = (ctx: MatchContext, id: number) => boolean;
export type MatcherFn = (ctx: MatchContext, id: number) => boolean;
export type TransformFn = (value: string) => number;
export {};

View file

@ -1,7 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::args::jsr_url; use crate::args::jsr_url;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use dashmap::DashMap; use dashmap::DashMap;
use deno_core::serde_json; use deno_core::serde_json;
use deno_graph::packages::JsrPackageInfo; use deno_graph::packages::JsrPackageInfo;
@ -19,11 +19,11 @@ pub struct JsrFetchResolver {
/// It can be large and we don't want to store it. /// It can be large and we don't want to store it.
info_by_nv: DashMap<PackageNv, Option<Arc<JsrPackageVersionInfo>>>, info_by_nv: DashMap<PackageNv, Option<Arc<JsrPackageVersionInfo>>>,
info_by_name: DashMap<String, Option<Arc<JsrPackageInfo>>>, info_by_name: DashMap<String, Option<Arc<JsrPackageInfo>>>,
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
} }
impl JsrFetchResolver { impl JsrFetchResolver {
pub fn new(file_fetcher: Arc<FileFetcher>) -> Self { pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
Self { Self {
nv_by_req: Default::default(), nv_by_req: Default::default(),
info_by_nv: Default::default(), info_by_nv: Default::default(),

View file

@ -36,6 +36,8 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageNvReference; use deno_semver::package::PackageNvReference;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::package::PackageReqReference; use deno_semver::package::PackageReqReference;
use deno_semver::SmallStackString;
use deno_semver::StackString;
use deno_semver::Version; use deno_semver::Version;
use import_map::ImportMap; use import_map::ImportMap;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
@ -270,13 +272,24 @@ impl<'a> TsResponseImportMapper<'a> {
} }
} }
if specifier.scheme() == "node" {
return Some(specifier.to_string());
}
if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str()) if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str())
{ {
let mut segments = jsr_path.split('/'); let mut segments = jsr_path.split('/');
let name = if jsr_path.starts_with('@') { let name = if jsr_path.starts_with('@') {
format!("{}/{}", segments.next()?, segments.next()?) let scope = segments.next()?;
let name = segments.next()?;
capacity_builder::StringBuilder::<StackString>::build(|builder| {
builder.append(scope);
builder.append("/");
builder.append(name);
})
.unwrap()
} else { } else {
segments.next()?.to_string() StackString::from(segments.next()?)
}; };
let version = Version::parse_standard(segments.next()?).ok()?; let version = Version::parse_standard(segments.next()?).ok()?;
let nv = PackageNv { name, version }; let nv = PackageNv { name, version };
@ -286,7 +299,9 @@ impl<'a> TsResponseImportMapper<'a> {
&path, &path,
Some(&self.file_referrer), Some(&self.file_referrer),
)?; )?;
let sub_path = (export != ".").then_some(export); let sub_path = (export != ".")
.then_some(export)
.map(SmallStackString::from_string);
let mut req = None; let mut req = None;
req = req.or_else(|| { req = req.or_else(|| {
let import_map = self.maybe_import_map?; let import_map = self.maybe_import_map?;
@ -599,18 +614,24 @@ fn try_reverse_map_package_json_exports(
/// For a set of tsc changes, can them for any that contain something that looks /// For a set of tsc changes, can them for any that contain something that looks
/// like an import and rewrite the import specifier to include the extension /// like an import and rewrite the import specifier to include the extension
pub fn fix_ts_import_changes( pub fn fix_ts_import_changes(
referrer: &ModuleSpecifier,
resolution_mode: ResolutionMode,
changes: &[tsc::FileTextChanges], changes: &[tsc::FileTextChanges],
language_server: &language_server::Inner, language_server: &language_server::Inner,
) -> Result<Vec<tsc::FileTextChanges>, AnyError> { ) -> Result<Vec<tsc::FileTextChanges>, AnyError> {
let import_mapper = language_server.get_ts_response_import_mapper(referrer);
let mut r = Vec::new(); let mut r = Vec::new();
for change in changes { for change in changes {
let Ok(referrer) = ModuleSpecifier::parse(&change.file_name) else {
continue;
};
let referrer_doc = language_server.get_asset_or_document(&referrer).ok();
let resolution_mode = referrer_doc
.as_ref()
.map(|d| d.resolution_mode())
.unwrap_or(ResolutionMode::Import);
let import_mapper =
language_server.get_ts_response_import_mapper(&referrer);
let mut text_changes = Vec::new(); let mut text_changes = Vec::new();
for text_change in &change.text_changes { for text_change in &change.text_changes {
let lines = text_change.new_text.split('\n'); let lines = text_change.new_text.split('\n');
let new_lines: Vec<String> = lines let new_lines: Vec<String> = lines
.map(|line| { .map(|line| {
// This assumes that there's only one import per line. // This assumes that there's only one import per line.
@ -618,7 +639,7 @@ pub fn fix_ts_import_changes(
let specifier = let specifier =
captures.iter().skip(1).find_map(|s| s).unwrap().as_str(); captures.iter().skip(1).find_map(|s| s).unwrap().as_str();
if let Some(new_specifier) = import_mapper if let Some(new_specifier) = import_mapper
.check_unresolved_specifier(specifier, referrer, resolution_mode) .check_unresolved_specifier(specifier, &referrer, resolution_mode)
{ {
line.replace(specifier, &new_specifier) line.replace(specifier, &new_specifier)
} else { } else {

View file

@ -7,6 +7,7 @@ use crate::cache::LocalLspHttpCache;
use crate::lsp::config::Config; use crate::lsp::config::Config;
use crate::lsp::logging::lsp_log; use crate::lsp::logging::lsp_log;
use crate::lsp::logging::lsp_warn; use crate::lsp::logging::lsp_warn;
use crate::sys::CliSys;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
@ -91,12 +92,11 @@ impl LspCache {
}) })
.ok() .ok()
}); });
let deno_dir = DenoDir::new(global_cache_path) let sys = CliSys::default();
let deno_dir = DenoDir::new(sys.clone(), global_cache_path)
.expect("should be infallible with absolute custom root"); .expect("should be infallible with absolute custom root");
let global = Arc::new(GlobalHttpCache::new( let global =
deno_dir.remote_folder_path(), Arc::new(GlobalHttpCache::new(sys, deno_dir.remote_folder_path()));
crate::cache::RealDenoCacheEnv,
));
Self { Self {
deno_dir, deno_dir,
global, global,

View file

@ -9,8 +9,6 @@ use deno_config::deno_json::LintConfig;
use deno_config::deno_json::NodeModulesDirMode; use deno_config::deno_json::NodeModulesDirMode;
use deno_config::deno_json::TestConfig; use deno_config::deno_json::TestConfig;
use deno_config::deno_json::TsConfig; use deno_config::deno_json::TsConfig;
use deno_config::fs::DenoConfigFs;
use deno_config::fs::RealDenoConfigFs;
use deno_config::glob::FilePatterns; use deno_config::glob::FilePatterns;
use deno_config::glob::PathOrPatternSet; use deno_config::glob::PathOrPatternSet;
use deno_config::workspace::CreateResolverOptions; use deno_config::workspace::CreateResolverOptions;
@ -41,7 +39,6 @@ use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_node::PackageJson;
use indexmap::IndexSet; use indexmap::IndexSet;
use lsp_types::ClientCapabilities; use lsp_types::ClientCapabilities;
use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::collections::HashMap; use std::collections::HashMap;
@ -63,10 +60,11 @@ use crate::args::ConfigFile;
use crate::args::LintFlags; use crate::args::LintFlags;
use crate::args::LintOptions; use crate::args::LintOptions;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::lsp::logging::lsp_warn; use crate::lsp::logging::lsp_warn;
use crate::resolver::CliSloppyImportsResolver; use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::sys::CliSys;
use crate::tools::lint::CliLinter; use crate::tools::lint::CliLinter;
use crate::tools::lint::CliLinterOptions; use crate::tools::lint::CliLinterOptions;
use crate::tools::lint::LintRuleProvider; use crate::tools::lint::LintRuleProvider;
@ -459,6 +457,19 @@ impl Default for LanguagePreferences {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct SuggestionActionsSettings {
#[serde(default = "is_true")]
pub enabled: bool,
}
impl Default for SuggestionActionsSettings {
fn default() -> Self {
SuggestionActionsSettings { enabled: true }
}
}
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)] #[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateImportsOnFileMoveOptions { pub struct UpdateImportsOnFileMoveOptions {
@ -490,6 +501,8 @@ pub struct LanguageWorkspaceSettings {
#[serde(default)] #[serde(default)]
pub suggest: CompletionSettings, pub suggest: CompletionSettings,
#[serde(default)] #[serde(default)]
pub suggestion_actions: SuggestionActionsSettings,
#[serde(default)]
pub update_imports_on_file_move: UpdateImportsOnFileMoveOptions, pub update_imports_on_file_move: UpdateImportsOnFileMoveOptions,
} }
@ -1203,9 +1216,8 @@ impl ConfigData {
specified_config: Option<&Path>, specified_config: Option<&Path>,
scope: &ModuleSpecifier, scope: &ModuleSpecifier,
settings: &Settings, settings: &Settings,
file_fetcher: &Arc<FileFetcher>, file_fetcher: &Arc<CliFileFetcher>,
// sync requirement is because the lsp requires sync // sync requirement is because the lsp requires sync
cached_deno_config_fs: &(dyn DenoConfigFs + Sync),
deno_json_cache: &(dyn DenoJsonCache + Sync), deno_json_cache: &(dyn DenoJsonCache + Sync),
pkg_json_cache: &(dyn PackageJsonCache + Sync), pkg_json_cache: &(dyn PackageJsonCache + Sync),
workspace_cache: &(dyn WorkspaceCache + Sync), workspace_cache: &(dyn WorkspaceCache + Sync),
@ -1215,6 +1227,7 @@ impl ConfigData {
Ok(scope_dir_path) => { Ok(scope_dir_path) => {
let paths = [scope_dir_path]; let paths = [scope_dir_path];
WorkspaceDirectory::discover( WorkspaceDirectory::discover(
&CliSys::default(),
match specified_config { match specified_config {
Some(config_path) => { Some(config_path) => {
deno_config::workspace::WorkspaceDiscoverStart::ConfigFile( deno_config::workspace::WorkspaceDiscoverStart::ConfigFile(
@ -1226,7 +1239,6 @@ impl ConfigData {
} }
}, },
&WorkspaceDiscoverOptions { &WorkspaceDiscoverOptions {
fs: cached_deno_config_fs,
additional_config_file_names: &[], additional_config_file_names: &[],
deno_json_cache: Some(deno_json_cache), deno_json_cache: Some(deno_json_cache),
pkg_json_cache: Some(pkg_json_cache), pkg_json_cache: Some(pkg_json_cache),
@ -1298,7 +1310,7 @@ impl ConfigData {
member_dir: Arc<WorkspaceDirectory>, member_dir: Arc<WorkspaceDirectory>,
scope: Arc<ModuleSpecifier>, scope: Arc<ModuleSpecifier>,
settings: &Settings, settings: &Settings,
file_fetcher: Option<&Arc<FileFetcher>>, file_fetcher: Option<&Arc<CliFileFetcher>>,
) -> Self { ) -> Self {
let (settings, workspace_folder) = settings.get_for_specifier(&scope); let (settings, workspace_folder) = settings.get_for_specifier(&scope);
let mut watched_files = HashMap::with_capacity(10); let mut watched_files = HashMap::with_capacity(10);
@ -1603,9 +1615,7 @@ impl ConfigData {
|| unstable.contains("sloppy-imports"); || unstable.contains("sloppy-imports");
let sloppy_imports_resolver = unstable_sloppy_imports.then(|| { let sloppy_imports_resolver = unstable_sloppy_imports.then(|| {
Arc::new(CliSloppyImportsResolver::new( Arc::new(CliSloppyImportsResolver::new(
SloppyImportsCachedFs::new_without_stat_cache(Arc::new( SloppyImportsCachedFs::new_without_stat_cache(CliSys::default()),
deno_runtime::deno_fs::RealFs,
)),
)) ))
}); });
let resolver = Arc::new(resolver); let resolver = Arc::new(resolver);
@ -1819,13 +1829,12 @@ impl ConfigTree {
&mut self, &mut self,
settings: &Settings, settings: &Settings,
workspace_files: &IndexSet<ModuleSpecifier>, workspace_files: &IndexSet<ModuleSpecifier>,
file_fetcher: &Arc<FileFetcher>, file_fetcher: &Arc<CliFileFetcher>,
) { ) {
lsp_log!("Refreshing configuration tree..."); lsp_log!("Refreshing configuration tree...");
// since we're resolving a workspace multiple times in different // since we're resolving a workspace multiple times in different
// folders, we want to cache all the lookups and config files across // folders, we want to cache all the lookups and config files across
// ConfigData::load calls // ConfigData::load calls
let cached_fs = CachedDenoConfigFs::default();
let deno_json_cache = DenoJsonMemCache::default(); let deno_json_cache = DenoJsonMemCache::default();
let pkg_json_cache = PackageJsonMemCache::default(); let pkg_json_cache = PackageJsonMemCache::default();
let workspace_cache = WorkspaceMemCache::default(); let workspace_cache = WorkspaceMemCache::default();
@ -1850,7 +1859,6 @@ impl ConfigTree {
folder_uri, folder_uri,
settings, settings,
file_fetcher, file_fetcher,
&cached_fs,
&deno_json_cache, &deno_json_cache,
&pkg_json_cache, &pkg_json_cache,
&workspace_cache, &workspace_cache,
@ -1881,7 +1889,6 @@ impl ConfigTree {
&scope, &scope,
settings, settings,
file_fetcher, file_fetcher,
&cached_fs,
&deno_json_cache, &deno_json_cache,
&pkg_json_cache, &pkg_json_cache,
&workspace_cache, &workspace_cache,
@ -1898,7 +1905,6 @@ impl ConfigTree {
member_scope, member_scope,
settings, settings,
file_fetcher, file_fetcher,
&cached_fs,
&deno_json_cache, &deno_json_cache,
&pkg_json_cache, &pkg_json_cache,
&workspace_cache, &workspace_cache,
@ -1913,21 +1919,24 @@ impl ConfigTree {
#[cfg(test)] #[cfg(test)]
pub async fn inject_config_file(&mut self, config_file: ConfigFile) { pub async fn inject_config_file(&mut self, config_file: ConfigFile) {
use sys_traits::FsCreateDirAll;
use sys_traits::FsWrite;
let scope = config_file.specifier.join(".").unwrap(); let scope = config_file.specifier.join(".").unwrap();
let json_text = serde_json::to_string(&config_file.json).unwrap(); let json_text = serde_json::to_string(&config_file.json).unwrap();
let test_fs = deno_runtime::deno_fs::InMemoryFs::default(); let memory_sys = sys_traits::impls::InMemorySys::default();
let config_path = url_to_file_path(&config_file.specifier).unwrap(); let config_path = url_to_file_path(&config_file.specifier).unwrap();
test_fs.setup_text_files(vec![( memory_sys
config_path.to_string_lossy().to_string(), .fs_create_dir_all(config_path.parent().unwrap())
json_text, .unwrap();
)]); memory_sys.fs_write(&config_path, json_text).unwrap();
let workspace_dir = Arc::new( let workspace_dir = Arc::new(
WorkspaceDirectory::discover( WorkspaceDirectory::discover(
&memory_sys,
deno_config::workspace::WorkspaceDiscoverStart::ConfigFile( deno_config::workspace::WorkspaceDiscoverStart::ConfigFile(
&config_path, &config_path,
), ),
&deno_config::workspace::WorkspaceDiscoverOptions { &deno_config::workspace::WorkspaceDiscoverOptions {
fs: &crate::args::deno_json::DenoConfigFsAdapter(&test_fs),
..Default::default() ..Default::default()
}, },
) )
@ -2000,11 +2009,14 @@ fn resolve_lockfile_from_path(
lockfile_path: PathBuf, lockfile_path: PathBuf,
frozen: bool, frozen: bool,
) -> Option<CliLockfile> { ) -> Option<CliLockfile> {
match CliLockfile::read_from_path(CliLockfileReadFromPathOptions { match CliLockfile::read_from_path(
file_path: lockfile_path, &CliSys::default(),
frozen, CliLockfileReadFromPathOptions {
skip_write: false, file_path: lockfile_path,
}) { frozen,
skip_write: false,
},
) {
Ok(value) => { Ok(value) => {
if value.filename.exists() { if value.filename.exists() {
if let Ok(specifier) = ModuleSpecifier::from_file_path(&value.filename) if let Ok(specifier) = ModuleSpecifier::from_file_path(&value.filename)
@ -2061,78 +2073,6 @@ impl deno_config::workspace::WorkspaceCache for WorkspaceMemCache {
} }
} }
#[derive(Default)]
struct CachedFsItems<T: Clone> {
items: HashMap<PathBuf, Result<T, std::io::Error>>,
}
impl<T: Clone> CachedFsItems<T> {
pub fn get(
&mut self,
path: &Path,
action: impl FnOnce(&Path) -> Result<T, std::io::Error>,
) -> Result<T, std::io::Error> {
let value = if let Some(value) = self.items.get(path) {
value
} else {
let value = action(path);
// just in case this gets really large for some reason
if self.items.len() == 16_384 {
return value;
}
self.items.insert(path.to_owned(), value);
self.items.get(path).unwrap()
};
value
.as_ref()
.map(|v| (*v).clone())
.map_err(|e| std::io::Error::new(e.kind(), e.to_string()))
}
}
#[derive(Default)]
struct InnerData {
stat_calls: CachedFsItems<deno_config::fs::FsMetadata>,
read_to_string_calls: CachedFsItems<Cow<'static, str>>,
}
#[derive(Default)]
struct CachedDenoConfigFs(Mutex<InnerData>);
impl DenoConfigFs for CachedDenoConfigFs {
fn stat_sync(
&self,
path: &Path,
) -> Result<deno_config::fs::FsMetadata, std::io::Error> {
self
.0
.lock()
.stat_calls
.get(path, |path| RealDenoConfigFs.stat_sync(path))
}
fn read_to_string_lossy(
&self,
path: &Path,
) -> Result<Cow<'static, str>, std::io::Error> {
self
.0
.lock()
.read_to_string_calls
.get(path, |path| RealDenoConfigFs.read_to_string_lossy(path))
}
fn read_dir(
&self,
path: &Path,
) -> Result<Vec<deno_config::fs::FsDirEntry>, std::io::Error> {
// no need to cache these because the workspace cache will ensure
// we only do read_dir calls once (read_dirs are only used for
// npm workspace resolution)
RealDenoConfigFs.read_dir(path)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use deno_config::deno_json::ConfigParseOptions; use deno_config::deno_json::ConfigParseOptions;
@ -2292,6 +2232,7 @@ mod tests {
enabled: true, enabled: true,
}, },
}, },
suggestion_actions: SuggestionActionsSettings { enabled: true },
update_imports_on_file_move: UpdateImportsOnFileMoveOptions { update_imports_on_file_move: UpdateImportsOnFileMoveOptions {
enabled: UpdateImportsOnFileMoveEnabled::Prompt enabled: UpdateImportsOnFileMoveEnabled::Prompt
} }
@ -2338,6 +2279,7 @@ mod tests {
enabled: true, enabled: true,
}, },
}, },
suggestion_actions: SuggestionActionsSettings { enabled: true },
update_imports_on_file_move: UpdateImportsOnFileMoveOptions { update_imports_on_file_move: UpdateImportsOnFileMoveOptions {
enabled: UpdateImportsOnFileMoveEnabled::Prompt enabled: UpdateImportsOnFileMoveEnabled::Prompt
} }

View file

@ -21,9 +21,11 @@ use crate::graph_util::enhanced_resolution_error_message;
use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams; use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams;
use crate::resolver::CliSloppyImportsResolver; use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::sys::CliSys;
use crate::tools::lint::CliLinter; use crate::tools::lint::CliLinter;
use crate::tools::lint::CliLinterOptions; use crate::tools::lint::CliLinterOptions;
use crate::tools::lint::LintRuleProvider; use crate::tools::lint::LintRuleProvider;
use crate::tsc::DiagnosticCategory;
use crate::util::path::to_percent_decoded_str; use crate::util::path::to_percent_decoded_str;
use deno_ast::MediaType; use deno_ast::MediaType;
@ -44,9 +46,9 @@ use deno_graph::source::ResolveError;
use deno_graph::Resolution; use deno_graph::Resolution;
use deno_graph::ResolutionError; use deno_graph::ResolutionError;
use deno_graph::SpecifierError; use deno_graph::SpecifierError;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_resolver::sloppy_imports::SloppyImportsResolution; use deno_resolver::sloppy_imports::SloppyImportsResolution;
use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind;
use deno_runtime::deno_fs;
use deno_runtime::deno_node; use deno_runtime::deno_node;
use deno_runtime::tokio_util::create_basic_runtime; use deno_runtime::tokio_util::create_basic_runtime;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
@ -833,7 +835,7 @@ fn generate_lint_diagnostics(
lint_rule_provider.resolve_lint_rules(Default::default(), None) lint_rule_provider.resolve_lint_rules(Default::default(), None)
}, },
fix: false, fix: false,
deno_lint_config: deno_lint::linter::LintConfig { deno_lint_config: DenoLintConfig {
default_jsx_factory: None, default_jsx_factory: None,
default_jsx_fragment_factory: None, default_jsx_fragment_factory: None,
}, },
@ -906,8 +908,22 @@ async fn generate_ts_diagnostics(
} else { } else {
Default::default() Default::default()
}; };
for (specifier_str, ts_json_diagnostics) in ts_diagnostics_map { for (specifier_str, mut ts_json_diagnostics) in ts_diagnostics_map {
let specifier = resolve_url(&specifier_str)?; let specifier = resolve_url(&specifier_str)?;
let suggestion_actions_settings = snapshot
.config
.language_settings_for_specifier(&specifier)
.map(|s| s.suggestion_actions.clone())
.unwrap_or_default();
if !suggestion_actions_settings.enabled {
ts_json_diagnostics.retain(|d| {
d.category != DiagnosticCategory::Suggestion
// Still show deprecated and unused diagnostics.
// https://github.com/microsoft/vscode/blob/ce50bd4876af457f64d83cfd956bc916535285f4/extensions/typescript-language-features/src/languageFeatures/diagnostics.ts#L113-L114
|| d.reports_deprecated == Some(true)
|| d.reports_unnecessary == Some(true)
});
}
let version = snapshot let version = snapshot
.documents .documents
.get(&specifier) .get(&specifier)
@ -1265,7 +1281,7 @@ impl DenoDiagnostic {
Self::NotInstalledNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("npm package \"{pkg_req}\" is not installed or doesn't exist."), Some(json!({ "specifier": specifier }))), Self::NotInstalledNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("npm package \"{pkg_req}\" is not installed or doesn't exist."), Some(json!({ "specifier": specifier }))),
Self::NoLocal(specifier) => { Self::NoLocal(specifier) => {
let maybe_sloppy_resolution = CliSloppyImportsResolver::new( let maybe_sloppy_resolution = CliSloppyImportsResolver::new(
SloppyImportsCachedFs::new(Arc::new(deno_fs::RealFs)) SloppyImportsCachedFs::new(CliSys::default())
).resolve(specifier, SloppyImportsResolutionKind::Execution); ).resolve(specifier, SloppyImportsResolutionKind::Execution);
let data = maybe_sloppy_resolution.as_ref().map(|res| { let data = maybe_sloppy_resolution.as_ref().map(|res| {
json!({ json!({

View file

@ -251,6 +251,13 @@ impl AssetOrDocument {
pub fn document_lsp_version(&self) -> Option<i32> { pub fn document_lsp_version(&self) -> Option<i32> {
self.document().and_then(|d| d.maybe_lsp_version()) self.document().and_then(|d| d.maybe_lsp_version())
} }
pub fn resolution_mode(&self) -> ResolutionMode {
match self {
AssetOrDocument::Asset(_) => ResolutionMode::Import,
AssetOrDocument::Document(d) => d.resolution_mode(),
}
}
} }
type ModuleResult = Result<deno_graph::JsModule, deno_graph::ModuleGraphError>; type ModuleResult = Result<deno_graph::JsModule, deno_graph::ModuleGraphError>;

View file

@ -2,7 +2,8 @@
use crate::args::jsr_api_url; use crate::args::jsr_api_url;
use crate::args::jsr_url; use crate::args::jsr_url;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::TextDecodedFile;
use crate::jsr::partial_jsr_package_version_info_from_slice; use crate::jsr::partial_jsr_package_version_info_from_slice;
use crate::jsr::JsrFetchResolver; use crate::jsr::JsrFetchResolver;
use dashmap::DashMap; use dashmap::DashMap;
@ -17,6 +18,7 @@ use deno_graph::ModuleSpecifier;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::Version; use deno_semver::Version;
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
@ -32,8 +34,8 @@ pub struct JsrCacheResolver {
/// The `module_graph` fields of the version infos should be forcibly absent. /// The `module_graph` fields of the version infos should be forcibly absent.
/// It can be large and we don't want to store it. /// It can be large and we don't want to store it.
info_by_nv: DashMap<PackageNv, Option<Arc<JsrPackageVersionInfo>>>, info_by_nv: DashMap<PackageNv, Option<Arc<JsrPackageVersionInfo>>>,
info_by_name: DashMap<String, Option<Arc<JsrPackageInfo>>>, info_by_name: DashMap<StackString, Option<Arc<JsrPackageInfo>>>,
workspace_scope_by_name: HashMap<String, ModuleSpecifier>, workspace_scope_by_name: HashMap<StackString, ModuleSpecifier>,
cache: Arc<dyn HttpCache>, cache: Arc<dyn HttpCache>,
} }
@ -58,7 +60,7 @@ impl JsrCacheResolver {
continue; continue;
}; };
let nv = PackageNv { let nv = PackageNv {
name: jsr_pkg_config.name.clone(), name: jsr_pkg_config.name.as_str().into(),
version: version.clone(), version: version.clone(),
}; };
info_by_name.insert( info_by_name.insert(
@ -124,8 +126,8 @@ impl JsrCacheResolver {
return nv.value().clone(); return nv.value().clone();
} }
let maybe_get_nv = || { let maybe_get_nv = || {
let name = req.name.clone(); let name = &req.name;
let package_info = self.package_info(&name)?; let package_info = self.package_info(name)?;
// Find the first matching version of the package which is cached. // Find the first matching version of the package which is cached.
let mut versions = package_info.versions.keys().collect::<Vec<_>>(); let mut versions = package_info.versions.keys().collect::<Vec<_>>();
versions.sort(); versions.sort();
@ -143,7 +145,10 @@ impl JsrCacheResolver {
self.package_version_info(&nv).is_some() self.package_version_info(&nv).is_some()
}) })
.cloned()?; .cloned()?;
Some(PackageNv { name, version }) Some(PackageNv {
name: name.clone(),
version,
})
}; };
let nv = maybe_get_nv(); let nv = maybe_get_nv();
self.nv_by_req.insert(req.clone(), nv.clone()); self.nv_by_req.insert(req.clone(), nv.clone());
@ -215,7 +220,10 @@ impl JsrCacheResolver {
None None
} }
pub fn package_info(&self, name: &str) -> Option<Arc<JsrPackageInfo>> { pub fn package_info(
&self,
name: &StackString,
) -> Option<Arc<JsrPackageInfo>> {
if let Some(info) = self.info_by_name.get(name) { if let Some(info) = self.info_by_name.get(name) {
return info.value().clone(); return info.value().clone();
} }
@ -225,7 +233,7 @@ impl JsrCacheResolver {
serde_json::from_slice::<JsrPackageInfo>(&meta_bytes).ok() serde_json::from_slice::<JsrPackageInfo>(&meta_bytes).ok()
}; };
let info = read_cached_package_info().map(Arc::new); let info = read_cached_package_info().map(Arc::new);
self.info_by_name.insert(name.to_string(), info.clone()); self.info_by_name.insert(name.clone(), info.clone());
info info
} }
@ -267,7 +275,7 @@ fn read_cached_url(
#[derive(Debug)] #[derive(Debug)]
pub struct CliJsrSearchApi { pub struct CliJsrSearchApi {
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
resolver: JsrFetchResolver, resolver: JsrFetchResolver,
search_cache: DashMap<String, Arc<Vec<String>>>, search_cache: DashMap<String, Arc<Vec<String>>>,
versions_cache: DashMap<String, Arc<Vec<Version>>>, versions_cache: DashMap<String, Arc<Vec<Version>>>,
@ -275,7 +283,7 @@ pub struct CliJsrSearchApi {
} }
impl CliJsrSearchApi { impl CliJsrSearchApi {
pub fn new(file_fetcher: Arc<FileFetcher>) -> Self { pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
let resolver = JsrFetchResolver::new(file_fetcher.clone()); let resolver = JsrFetchResolver::new(file_fetcher.clone());
Self { Self {
file_fetcher, file_fetcher,
@ -309,10 +317,8 @@ impl PackageSearchApi for CliJsrSearchApi {
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
// spawn due to the lsp's `Send` requirement // spawn due to the lsp's `Send` requirement
let file = deno_core::unsync::spawn(async move { let file = deno_core::unsync::spawn(async move {
file_fetcher let file = file_fetcher.fetch_bypass_permissions(&search_url).await?;
.fetch_bypass_permissions(&search_url) TextDecodedFile::decode(file)
.await?
.into_text_decoded()
}) })
.await??; .await??;
let names = Arc::new(parse_jsr_search_response(&file.source)?); let names = Arc::new(parse_jsr_search_response(&file.source)?);

View file

@ -1,6 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_config::workspace::WorkspaceDirectory; use deno_config::workspace::WorkspaceDirectory;
use deno_config::workspace::WorkspaceDiscoverOptions; use deno_config::workspace::WorkspaceDiscoverOptions;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
@ -95,19 +96,19 @@ use crate::args::create_default_npmrc;
use crate::args::get_root_cert_store; use crate::args::get_root_cert_store;
use crate::args::has_flag_env_var; use crate::args::has_flag_env_var;
use crate::args::CaData; use crate::args::CaData;
use crate::args::CacheSetting;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::InternalFlags; use crate::args::InternalFlags;
use crate::args::UnstableFmtOptions; use crate::args::UnstableFmtOptions;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::graph_util; use crate::graph_util;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::lsp::config::ConfigWatchedFileType; use crate::lsp::config::ConfigWatchedFileType;
use crate::lsp::logging::init_log_file; use crate::lsp::logging::init_log_file;
use crate::lsp::tsc::file_text_changes_to_workspace_edit; use crate::lsp::tsc::file_text_changes_to_workspace_edit;
use crate::lsp::urls::LspUrlKind; use crate::lsp::urls::LspUrlKind;
use crate::sys::CliSys;
use crate::tools::fmt::format_file; use crate::tools::fmt::format_file;
use crate::tools::fmt::format_parsed_source; use crate::tools::fmt::format_parsed_source;
use crate::tools::upgrade::check_for_upgrades_for_lsp; use crate::tools::upgrade::check_for_upgrades_for_lsp;
@ -279,7 +280,7 @@ impl LanguageServer {
.await?; .await?;
graph_util::graph_valid( graph_util::graph_valid(
&graph, &graph,
factory.fs(), &CliSys::default(),
&roots, &roots,
graph_util::GraphValidOptions { graph_util::GraphValidOptions {
kind: GraphKind::All, kind: GraphKind::All,
@ -958,15 +959,16 @@ impl Inner {
} }
async fn refresh_config_tree(&mut self) { async fn refresh_config_tree(&mut self) {
let mut file_fetcher = FileFetcher::new( let file_fetcher = CliFileFetcher::new(
self.cache.global().clone(), self.cache.global().clone(),
CacheSetting::RespectHeaders,
true,
self.http_client_provider.clone(), self.http_client_provider.clone(),
CliSys::default(),
Default::default(), Default::default(),
None, None,
true,
CacheSetting::RespectHeaders,
super::logging::lsp_log_level(),
); );
file_fetcher.set_download_log_level(super::logging::lsp_log_level());
let file_fetcher = Arc::new(file_fetcher); let file_fetcher = Arc::new(file_fetcher);
self self
.config .config
@ -1855,20 +1857,12 @@ impl Inner {
} }
let changes = if code_action_data.fix_id == "fixMissingImport" { let changes = if code_action_data.fix_id == "fixMissingImport" {
fix_ts_import_changes( fix_ts_import_changes(&combined_code_actions.changes, self).map_err(
&code_action_data.specifier, |err| {
maybe_asset_or_doc error!("Unable to remap changes: {:#}", err);
.as_ref() LspError::internal_error()
.and_then(|d| d.document()) },
.map(|d| d.resolution_mode()) )?
.unwrap_or(ResolutionMode::Import),
&combined_code_actions.changes,
self,
)
.map_err(|err| {
error!("Unable to remap changes: {:#}", err);
LspError::internal_error()
})?
} else { } else {
combined_code_actions.changes combined_code_actions.changes
}; };
@ -1912,20 +1906,16 @@ impl Inner {
asset_or_doc.scope().cloned(), asset_or_doc.scope().cloned(),
) )
.await?; .await?;
if kind_suffix == ".rewrite.function.returnType" { if kind_suffix == ".rewrite.function.returnType"
refactor_edit_info.edits = fix_ts_import_changes( || kind_suffix == ".move.newFile"
&action_data.specifier, {
asset_or_doc refactor_edit_info.edits =
.document() fix_ts_import_changes(&refactor_edit_info.edits, self).map_err(
.map(|d| d.resolution_mode()) |err| {
.unwrap_or(ResolutionMode::Import), error!("Unable to remap changes: {:#}", err);
&refactor_edit_info.edits, LspError::internal_error()
self, },
) )?
.map_err(|err| {
error!("Unable to remap changes: {:#}", err);
LspError::internal_error()
})?
} }
code_action.edit = refactor_edit_info.to_workspace_edit(self)?; code_action.edit = refactor_edit_info.to_workspace_edit(self)?;
code_action code_action
@ -3624,11 +3614,11 @@ impl Inner {
let workspace = match config_data { let workspace = match config_data {
Some(d) => d.member_dir.clone(), Some(d) => d.member_dir.clone(),
None => Arc::new(WorkspaceDirectory::discover( None => Arc::new(WorkspaceDirectory::discover(
&CliSys::default(),
deno_config::workspace::WorkspaceDiscoverStart::Paths(&[ deno_config::workspace::WorkspaceDiscoverStart::Paths(&[
initial_cwd.clone() initial_cwd.clone()
]), ]),
&WorkspaceDiscoverOptions { &WorkspaceDiscoverOptions {
fs: Default::default(), // use real fs,
deno_json_cache: None, deno_json_cache: None,
pkg_json_cache: None, pkg_json_cache: None,
workspace_cache: None, workspace_cache: None,
@ -3645,6 +3635,7 @@ impl Inner {
)?), )?),
}; };
let cli_options = CliOptions::new( let cli_options = CliOptions::new(
&CliSys::default(),
Arc::new(Flags { Arc::new(Flags {
internal: InternalFlags { internal: InternalFlags {
cache_path: Some(self.cache.deno_dir().root.clone()), cache_path: Some(self.cache.deno_dir().root.clone()),
@ -3793,7 +3784,7 @@ impl Inner {
for (name, command) in scripts { for (name, command) in scripts {
result.push(TaskDefinition { result.push(TaskDefinition {
name: name.clone(), name: name.clone(),
command: command.clone(), command: Some(command.clone()),
source_uri: url_to_uri(&package_json.specifier()) source_uri: url_to_uri(&package_json.specifier())
.map_err(|_| LspError::internal_error())?, .map_err(|_| LspError::internal_error())?,
}); });

View file

@ -14,7 +14,7 @@ pub const LATEST_DIAGNOSTIC_BATCH_INDEX: &str =
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TaskDefinition { pub struct TaskDefinition {
pub name: String, pub name: String,
pub command: String, pub command: Option<String>,
pub source_uri: lsp::Uri, pub source_uri: lsp::Uri,
} }

View file

@ -11,21 +11,22 @@ use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;
use crate::args::npm_registry_url; use crate::args::npm_registry_url;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::TextDecodedFile;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
use super::search::PackageSearchApi; use super::search::PackageSearchApi;
#[derive(Debug)] #[derive(Debug)]
pub struct CliNpmSearchApi { pub struct CliNpmSearchApi {
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
resolver: NpmFetchResolver, resolver: NpmFetchResolver,
search_cache: DashMap<String, Arc<Vec<String>>>, search_cache: DashMap<String, Arc<Vec<String>>>,
versions_cache: DashMap<String, Arc<Vec<Version>>>, versions_cache: DashMap<String, Arc<Vec<Version>>>,
} }
impl CliNpmSearchApi { impl CliNpmSearchApi {
pub fn new(file_fetcher: Arc<FileFetcher>) -> Self { pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
let resolver = NpmFetchResolver::new( let resolver = NpmFetchResolver::new(
file_fetcher.clone(), file_fetcher.clone(),
Arc::new(NpmRc::default().as_resolved(npm_registry_url()).unwrap()), Arc::new(NpmRc::default().as_resolved(npm_registry_url()).unwrap()),
@ -57,10 +58,8 @@ impl PackageSearchApi for CliNpmSearchApi {
.append_pair("text", &format!("{} boost-exact:false", query)); .append_pair("text", &format!("{} boost-exact:false", query));
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
let file = deno_core::unsync::spawn(async move { let file = deno_core::unsync::spawn(async move {
file_fetcher let file = file_fetcher.fetch_bypass_permissions(&search_url).await?;
.fetch_bypass_permissions(&search_url) TextDecodedFile::decode(file)
.await?
.into_text_decoded()
}) })
.await??; .await??;
let names = Arc::new(parse_npm_search_response(&file.source)?); let names = Arc::new(parse_npm_search_response(&file.source)?);

View file

@ -12,14 +12,16 @@ use super::path_to_regex::StringOrNumber;
use super::path_to_regex::StringOrVec; use super::path_to_regex::StringOrVec;
use super::path_to_regex::Token; use super::path_to_regex::Token;
use crate::args::CacheSetting;
use crate::cache::GlobalHttpCache; use crate::cache::GlobalHttpCache;
use crate::cache::HttpCache; use crate::cache::HttpCache;
use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::FetchOptions; use crate::file_fetcher::FetchOptions;
use crate::file_fetcher::FetchPermissionsOptionRef; use crate::file_fetcher::FetchPermissionsOptionRef;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::TextDecodedFile;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::sys::CliSys;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
@ -418,7 +420,7 @@ enum VariableItems {
pub struct ModuleRegistry { pub struct ModuleRegistry {
origins: HashMap<String, Vec<RegistryConfiguration>>, origins: HashMap<String, Vec<RegistryConfiguration>>,
pub location: PathBuf, pub location: PathBuf,
pub file_fetcher: Arc<FileFetcher>, pub file_fetcher: Arc<CliFileFetcher>,
http_cache: Arc<GlobalHttpCache>, http_cache: Arc<GlobalHttpCache>,
} }
@ -428,19 +430,18 @@ impl ModuleRegistry {
http_client_provider: Arc<HttpClientProvider>, http_client_provider: Arc<HttpClientProvider>,
) -> Self { ) -> Self {
// the http cache should always be the global one for registry completions // the http cache should always be the global one for registry completions
let http_cache = Arc::new(GlobalHttpCache::new( let http_cache =
location.clone(), Arc::new(GlobalHttpCache::new(CliSys::default(), location.clone()));
crate::cache::RealDenoCacheEnv, let file_fetcher = CliFileFetcher::new(
));
let mut file_fetcher = FileFetcher::new(
http_cache.clone(), http_cache.clone(),
CacheSetting::RespectHeaders,
true,
http_client_provider, http_client_provider,
CliSys::default(),
Default::default(), Default::default(),
None, None,
true,
CacheSetting::RespectHeaders,
super::logging::lsp_log_level(),
); );
file_fetcher.set_download_log_level(super::logging::lsp_log_level());
Self { Self {
origins: HashMap::new(), origins: HashMap::new(),
@ -479,13 +480,15 @@ impl ModuleRegistry {
let specifier = specifier.clone(); let specifier = specifier.clone();
async move { async move {
file_fetcher file_fetcher
.fetch_with_options(FetchOptions { .fetch_with_options(
specifier: &specifier, &specifier,
permissions: FetchPermissionsOptionRef::AllowAll, FetchPermissionsOptionRef::AllowAll,
maybe_auth: None, FetchOptions {
maybe_accept: Some("application/vnd.deno.reg.v2+json, application/vnd.deno.reg.v1+json;q=0.9, application/json;q=0.8"), maybe_auth: None,
maybe_cache_setting: None, maybe_accept: Some("application/vnd.deno.reg.v2+json, application/vnd.deno.reg.v1+json;q=0.9, application/json;q=0.8"),
}) maybe_cache_setting: None,
}
)
.await .await
} }
}).await?; }).await?;
@ -500,7 +503,7 @@ impl ModuleRegistry {
); );
self.http_cache.set(specifier, headers_map, &[])?; self.http_cache.set(specifier, headers_map, &[])?;
} }
let file = fetch_result?.into_text_decoded()?; let file = TextDecodedFile::decode(fetch_result?)?;
let config: RegistryConfigurationJson = serde_json::from_str(&file.source)?; let config: RegistryConfigurationJson = serde_json::from_str(&file.source)?;
validate_config(&config)?; validate_config(&config)?;
Ok(config.registries) Ok(config.registries)
@ -584,12 +587,11 @@ impl ModuleRegistry {
// spawn due to the lsp's `Send` requirement // spawn due to the lsp's `Send` requirement
let file = deno_core::unsync::spawn({ let file = deno_core::unsync::spawn({
async move { async move {
file_fetcher let file = file_fetcher
.fetch_bypass_permissions(&endpoint) .fetch_bypass_permissions(&endpoint)
.await .await
.ok()? .ok()?;
.into_text_decoded() TextDecodedFile::decode(file).ok()
.ok()
} }
}) })
.await .await
@ -983,12 +985,11 @@ impl ModuleRegistry {
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
// spawn due to the lsp's `Send` requirement // spawn due to the lsp's `Send` requirement
let file = deno_core::unsync::spawn(async move { let file = deno_core::unsync::spawn(async move {
file_fetcher let file = file_fetcher
.fetch_bypass_permissions(&specifier) .fetch_bypass_permissions(&specifier)
.await .await
.ok()? .ok()?;
.into_text_decoded() TextDecodedFile::decode(file).ok()
.ok()
}) })
.await .await
.ok()??; .ok()??;
@ -1049,7 +1050,7 @@ impl ModuleRegistry {
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
let specifier = specifier.clone(); let specifier = specifier.clone();
async move { async move {
file_fetcher let file = file_fetcher
.fetch_bypass_permissions(&specifier) .fetch_bypass_permissions(&specifier)
.await .await
.map_err(|err| { .map_err(|err| {
@ -1058,9 +1059,8 @@ impl ModuleRegistry {
specifier, err specifier, err
); );
}) })
.ok()? .ok()?;
.into_text_decoded() TextDecodedFile::decode(file).ok()
.ok()
} }
}) })
.await .await
@ -1095,7 +1095,7 @@ impl ModuleRegistry {
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
let specifier = specifier.clone(); let specifier = specifier.clone();
async move { async move {
file_fetcher let file = file_fetcher
.fetch_bypass_permissions(&specifier) .fetch_bypass_permissions(&specifier)
.await .await
.map_err(|err| { .map_err(|err| {
@ -1104,9 +1104,8 @@ impl ModuleRegistry {
specifier, err specifier, err
); );
}) })
.ok()? .ok()?;
.into_text_decoded() TextDecodedFile::decode(file).ok()
.ok()
} }
}) })
.await .await

View file

@ -2,6 +2,7 @@
use dashmap::DashMap; use dashmap::DashMap;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::npm::NpmCacheDir; use deno_cache_dir::npm::NpmCacheDir;
use deno_cache_dir::HttpCache; use deno_cache_dir::HttpCache;
use deno_config::deno_json::JsxImportSourceConfig; use deno_config::deno_json::JsxImportSourceConfig;
@ -18,9 +19,7 @@ use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions; use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmReqResolver; use deno_resolver::NodeAndNpmReqResolver;
use deno_runtime::deno_fs; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_node::PackageJsonResolver;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
@ -39,10 +38,8 @@ use std::sync::Arc;
use super::cache::LspCache; use super::cache::LspCache;
use super::jsr::JsrCacheResolver; use super::jsr::JsrCacheResolver;
use crate::args::create_default_npmrc; use crate::args::create_default_npmrc;
use crate::args::CacheSetting;
use crate::args::CliLockfile; use crate::args::CliLockfile;
use crate::args::NpmInstallDepsProvider; use crate::args::NpmInstallDepsProvider;
use crate::cache::DenoCacheEnvFsAdapter;
use crate::factory::Deferred; use crate::factory::Deferred;
use crate::graph_util::to_node_resolution_kind; use crate::graph_util::to_node_resolution_kind;
use crate::graph_util::to_node_resolution_mode; use crate::graph_util::to_node_resolution_mode;
@ -51,6 +48,8 @@ use crate::http_util::HttpClientProvider;
use crate::lsp::config::Config; use crate::lsp::config::Config;
use crate::lsp::config::ConfigData; use crate::lsp::config::ConfigData;
use crate::lsp::logging::lsp_warn; use crate::lsp::logging::lsp_warn;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver_for_lsp; use crate::npm::create_cli_npm_resolver_for_lsp;
use crate::npm::CliByonmNpmResolverCreateOptions; use crate::npm::CliByonmNpmResolverCreateOptions;
use crate::npm::CliManagedInNpmPkgCheckerCreateOptions; use crate::npm::CliManagedInNpmPkgCheckerCreateOptions;
@ -61,12 +60,12 @@ use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions; use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::npm::ManagedCliNpmResolver; use crate::npm::ManagedCliNpmResolver;
use crate::resolver::CliDenoResolver; use crate::resolver::CliDenoResolver;
use crate::resolver::CliDenoResolverFs;
use crate::resolver::CliNpmReqResolver; use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::resolver::CliResolverOptions; use crate::resolver::CliResolverOptions;
use crate::resolver::IsCjsResolver; use crate::resolver::IsCjsResolver;
use crate::resolver::WorkerCliNpmGraphResolver; use crate::resolver::WorkerCliNpmGraphResolver;
use crate::sys::CliSys;
use crate::tsc::into_specifier_and_media_type; use crate::tsc::into_specifier_and_media_type;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
@ -78,9 +77,9 @@ struct LspScopeResolver {
is_cjs_resolver: Arc<IsCjsResolver>, is_cjs_resolver: Arc<IsCjsResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>, jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>, npm_resolver: Option<Arc<dyn CliNpmResolver>>,
node_resolver: Option<Arc<NodeResolver>>, node_resolver: Option<Arc<CliNodeResolver>>,
npm_pkg_req_resolver: Option<Arc<CliNpmReqResolver>>, npm_pkg_req_resolver: Option<Arc<CliNpmReqResolver>>,
pkg_json_resolver: Arc<PackageJsonResolver>, pkg_json_resolver: Arc<CliPackageJsonResolver>,
redirect_resolver: Option<Arc<RedirectResolver>>, redirect_resolver: Option<Arc<RedirectResolver>>,
graph_imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>, graph_imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>,
dep_info: Arc<Mutex<Arc<ScopeDepInfo>>>, dep_info: Arc<Mutex<Arc<ScopeDepInfo>>>,
@ -384,7 +383,7 @@ impl LspResolver {
pub fn pkg_json_resolver( pub fn pkg_json_resolver(
&self, &self,
referrer: &ModuleSpecifier, referrer: &ModuleSpecifier,
) -> &Arc<PackageJsonResolver> { ) -> &Arc<CliPackageJsonResolver> {
let resolver = self.get_scope_resolver(Some(referrer)); let resolver = self.get_scope_resolver(Some(referrer));
&resolver.pkg_json_resolver &resolver.pkg_json_resolver
} }
@ -592,28 +591,26 @@ struct ResolverFactoryServices {
cli_resolver: Deferred<Arc<CliResolver>>, cli_resolver: Deferred<Arc<CliResolver>>,
in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>, in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>,
is_cjs_resolver: Deferred<Arc<IsCjsResolver>>, is_cjs_resolver: Deferred<Arc<IsCjsResolver>>,
node_resolver: Deferred<Option<Arc<NodeResolver>>>, node_resolver: Deferred<Option<Arc<CliNodeResolver>>>,
npm_pkg_req_resolver: Deferred<Option<Arc<CliNpmReqResolver>>>, npm_pkg_req_resolver: Deferred<Option<Arc<CliNpmReqResolver>>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>, npm_resolver: Option<Arc<dyn CliNpmResolver>>,
} }
struct ResolverFactory<'a> { struct ResolverFactory<'a> {
config_data: Option<&'a Arc<ConfigData>>, config_data: Option<&'a Arc<ConfigData>>,
fs: Arc<dyn deno_fs::FileSystem>, pkg_json_resolver: Arc<CliPackageJsonResolver>,
pkg_json_resolver: Arc<PackageJsonResolver>, sys: CliSys,
services: ResolverFactoryServices, services: ResolverFactoryServices,
} }
impl<'a> ResolverFactory<'a> { impl<'a> ResolverFactory<'a> {
pub fn new(config_data: Option<&'a Arc<ConfigData>>) -> Self { pub fn new(config_data: Option<&'a Arc<ConfigData>>) -> Self {
let fs = Arc::new(deno_fs::RealFs); let sys = CliSys::default();
let pkg_json_resolver = Arc::new(PackageJsonResolver::new( let pkg_json_resolver = Arc::new(CliPackageJsonResolver::new(sys.clone()));
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
));
Self { Self {
config_data, config_data,
fs,
pkg_json_resolver, pkg_json_resolver,
sys,
services: Default::default(), services: Default::default(),
} }
} }
@ -624,9 +621,10 @@ impl<'a> ResolverFactory<'a> {
cache: &LspCache, cache: &LspCache,
) { ) {
let enable_byonm = self.config_data.map(|d| d.byonm).unwrap_or(false); let enable_byonm = self.config_data.map(|d| d.byonm).unwrap_or(false);
let sys = CliSys::default();
let options = if enable_byonm { let options = if enable_byonm {
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
fs: CliDenoResolverFs(Arc::new(deno_fs::RealFs)), sys,
pkg_json_resolver: self.pkg_json_resolver.clone(), pkg_json_resolver: self.pkg_json_resolver.clone(),
root_node_modules_dir: self.config_data.and_then(|config_data| { root_node_modules_dir: self.config_data.and_then(|config_data| {
config_data.node_modules_dir.clone().or_else(|| { config_data.node_modules_dir.clone().or_else(|| {
@ -642,12 +640,14 @@ impl<'a> ResolverFactory<'a> {
.and_then(|d| d.npmrc.clone()) .and_then(|d| d.npmrc.clone())
.unwrap_or_else(create_default_npmrc); .unwrap_or_else(create_default_npmrc);
let npm_cache_dir = Arc::new(NpmCacheDir::new( let npm_cache_dir = Arc::new(NpmCacheDir::new(
&DenoCacheEnvFsAdapter(self.fs.as_ref()), &sys,
cache.deno_dir().npm_folder_path(), cache.deno_dir().npm_folder_path(),
npmrc.get_all_known_registries_urls(), npmrc.get_all_known_registries_urls(),
)); ));
CliNpmResolverCreateOptions::Managed(CliManagedNpmResolverCreateOptions { CliNpmResolverCreateOptions::Managed(CliManagedNpmResolverCreateOptions {
http_client_provider: http_client_provider.clone(), http_client_provider: http_client_provider.clone(),
// only used for top level install, so we can ignore this
npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::empty()),
snapshot: match self.config_data.and_then(|d| d.lockfile.as_ref()) { snapshot: match self.config_data.and_then(|d| d.lockfile.as_ref()) {
Some(lockfile) => { Some(lockfile) => {
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile( CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
@ -656,10 +656,7 @@ impl<'a> ResolverFactory<'a> {
} }
None => CliNpmResolverManagedSnapshotOption::Specified(None), None => CliNpmResolverManagedSnapshotOption::Specified(None),
}, },
// Don't provide the lockfile. We don't want these resolvers sys: CliSys::default(),
// updating it. Only the cache request should update the lockfile.
maybe_lockfile: None,
fs: Arc::new(deno_fs::RealFs),
npm_cache_dir, npm_cache_dir,
// Use an "only" cache setting in order to make the // Use an "only" cache setting in order to make the
// user do an explicit "cache" command and prevent // user do an explicit "cache" command and prevent
@ -667,11 +664,12 @@ impl<'a> ResolverFactory<'a> {
// the user is typing. // the user is typing.
cache_setting: CacheSetting::Only, cache_setting: CacheSetting::Only,
text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly), text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly),
// Don't provide the lockfile. We don't want these resolvers
// updating it. Only the cache request should update the lockfile.
maybe_lockfile: None,
maybe_node_modules_path: self maybe_node_modules_path: self
.config_data .config_data
.and_then(|d| d.node_modules_dir.clone()), .and_then(|d| d.node_modules_dir.clone()),
// only used for top level install, so we can ignore this
npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::empty()),
npmrc, npmrc,
npm_system_info: NpmSystemInfo::default(), npm_system_info: NpmSystemInfo::default(),
lifecycle_scripts: Default::default(), lifecycle_scripts: Default::default(),
@ -731,7 +729,7 @@ impl<'a> ResolverFactory<'a> {
}) })
} }
pub fn pkg_json_resolver(&self) -> &Arc<PackageJsonResolver> { pub fn pkg_json_resolver(&self) -> &Arc<CliPackageJsonResolver> {
&self.pkg_json_resolver &self.pkg_json_resolver
} }
@ -772,17 +770,18 @@ impl<'a> ResolverFactory<'a> {
}) })
} }
pub fn node_resolver(&self) -> Option<&Arc<NodeResolver>> { pub fn node_resolver(&self) -> Option<&Arc<CliNodeResolver>> {
self self
.services .services
.node_resolver .node_resolver
.get_or_init(|| { .get_or_init(|| {
let npm_resolver = self.services.npm_resolver.as_ref()?; let npm_resolver = self.services.npm_resolver.as_ref()?;
Some(Arc::new(NodeResolver::new( Some(Arc::new(CliNodeResolver::new(
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(self.fs.clone()),
self.in_npm_pkg_checker().clone(), self.in_npm_pkg_checker().clone(),
RealIsBuiltInNodeModuleChecker,
npm_resolver.clone().into_npm_pkg_folder_resolver(), npm_resolver.clone().into_npm_pkg_folder_resolver(),
self.pkg_json_resolver.clone(), self.pkg_json_resolver.clone(),
self.sys.clone(),
))) )))
}) })
.as_ref() .as_ref()
@ -797,10 +796,10 @@ impl<'a> ResolverFactory<'a> {
let npm_resolver = self.npm_resolver()?; let npm_resolver = self.npm_resolver()?;
Some(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { Some(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions {
byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(),
fs: CliDenoResolverFs(self.fs.clone()),
in_npm_pkg_checker: self.in_npm_pkg_checker().clone(), in_npm_pkg_checker: self.in_npm_pkg_checker().clone(),
node_resolver: node_resolver.clone(), node_resolver: node_resolver.clone(),
npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(),
sys: self.sys.clone(),
}))) })))
}) })
.as_ref() .as_ref()

View file

@ -67,7 +67,9 @@ pub mod tests {
&self, &self,
nv: &PackageNv, nv: &PackageNv,
) -> Result<Arc<Vec<String>>, AnyError> { ) -> Result<Arc<Vec<String>>, AnyError> {
let Some(exports_by_version) = self.package_versions.get(&nv.name) else { let Some(exports_by_version) =
self.package_versions.get(nv.name.as_str())
else {
return Err(anyhow!("Package not found.")); return Err(anyhow!("Package not found."));
}; };
let Some(exports) = exports_by_version.get(&nv.version) else { let Some(exports) = exports_by_version.get(&nv.version) else {

View file

@ -64,6 +64,7 @@ use deno_core::OpState;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions; use deno_core::RuntimeOptions;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
use deno_runtime::inspector_server::InspectorServer; use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::tokio_util::create_basic_runtime; use deno_runtime::tokio_util::create_basic_runtime;
use indexmap::IndexMap; use indexmap::IndexMap;
@ -3411,10 +3412,18 @@ fn parse_code_actions(
additional_text_edits.extend(change.text_changes.iter().map(|tc| { additional_text_edits.extend(change.text_changes.iter().map(|tc| {
let mut text_edit = tc.as_text_edit(asset_or_doc.line_index()); let mut text_edit = tc.as_text_edit(asset_or_doc.line_index());
if let Some(specifier_rewrite) = &data.specifier_rewrite { if let Some(specifier_rewrite) = &data.specifier_rewrite {
text_edit.new_text = text_edit.new_text.replace( let specifier_index = text_edit
&specifier_rewrite.old_specifier, .new_text
&specifier_rewrite.new_specifier, .char_indices()
); .find_map(|(b, c)| (c == '\'' || c == '"').then_some(b));
if let Some(i) = specifier_index {
let mut specifier_part = text_edit.new_text.split_off(i);
specifier_part = specifier_part.replace(
&specifier_rewrite.old_specifier,
&specifier_rewrite.new_specifier,
);
text_edit.new_text.push_str(&specifier_part);
}
if let Some(deno_types_specifier) = if let Some(deno_types_specifier) =
&specifier_rewrite.new_deno_types_specifier &specifier_rewrite.new_deno_types_specifier
{ {
@ -3587,10 +3596,17 @@ impl CompletionEntryDetails {
&mut insert_replace_edit.new_text &mut insert_replace_edit.new_text
} }
}; };
*new_text = new_text.replace( let specifier_index = new_text
&specifier_rewrite.old_specifier, .char_indices()
&specifier_rewrite.new_specifier, .find_map(|(b, c)| (c == '\'' || c == '"').then_some(b));
); if let Some(i) = specifier_index {
let mut specifier_part = new_text.split_off(i);
specifier_part = specifier_part.replace(
&specifier_rewrite.old_specifier,
&specifier_rewrite.new_specifier,
);
new_text.push_str(&specifier_part);
}
if let Some(deno_types_specifier) = if let Some(deno_types_specifier) =
&specifier_rewrite.new_deno_types_specifier &specifier_rewrite.new_deno_types_specifier
{ {
@ -3729,7 +3745,7 @@ pub struct CompletionItemData {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct CompletionEntryDataAutoImport { struct CompletionEntryDataAutoImport {
module_specifier: String, module_specifier: String,
file_name: String, file_name: Option<String>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -3786,9 +3802,20 @@ impl CompletionEntry {
else { else {
return; return;
}; };
if let Ok(normalized) = specifier_map.normalize(&raw.file_name) { if let Some(file_name) = &raw.file_name {
self.auto_import_data = if let Ok(normalized) = specifier_map.normalize(file_name) {
Some(CompletionNormalizedAutoImportData { raw, normalized }); self.auto_import_data =
Some(CompletionNormalizedAutoImportData { raw, normalized });
}
} else if SUPPORTED_BUILTIN_NODE_MODULES
.contains(&raw.module_specifier.as_str())
{
if let Ok(normalized) =
resolve_url(&format!("node:{}", &raw.module_specifier))
{
self.auto_import_data =
Some(CompletionNormalizedAutoImportData { raw, normalized });
}
} }
} }
@ -5516,7 +5543,6 @@ impl TscRequest {
mod tests { mod tests {
use super::*; use super::*;
use crate::cache::HttpCache; use crate::cache::HttpCache;
use crate::http_util::HeadersMap;
use crate::lsp::cache::LspCache; use crate::lsp::cache::LspCache;
use crate::lsp::config::Config; use crate::lsp::config::Config;
use crate::lsp::config::WorkspaceSettings; use crate::lsp::config::WorkspaceSettings;
@ -5746,6 +5772,7 @@ mod tests {
"sourceLine": " import { A } from \".\";", "sourceLine": " import { A } from \".\";",
"category": 2, "category": 2,
"code": 6133, "code": 6133,
"reportsUnnecessary": true,
}] }]
}) })
); );
@ -5828,6 +5855,7 @@ mod tests {
"sourceLine": " import {", "sourceLine": " import {",
"category": 2, "category": 2,
"code": 6192, "code": 6192,
"reportsUnnecessary": true,
}, { }, {
"start": { "start": {
"line": 8, "line": 8,
@ -5951,7 +5979,7 @@ mod tests {
.global() .global()
.set( .set(
&specifier_dep, &specifier_dep,
HeadersMap::default(), Default::default(),
b"export const b = \"b\";\n", b"export const b = \"b\";\n",
) )
.unwrap(); .unwrap();
@ -5990,7 +6018,7 @@ mod tests {
.global() .global()
.set( .set(
&specifier_dep, &specifier_dep,
HeadersMap::default(), Default::default(),
b"export const b = \"b\";\n\nexport const a = \"b\";\n", b"export const b = \"b\";\n\nexport const a = \"b\";\n",
) )
.unwrap(); .unwrap();

View file

@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
mod args; mod args;
mod auth_tokens;
mod cache; mod cache;
mod cdp; mod cdp;
mod emit; mod emit;
@ -21,6 +20,7 @@ mod ops;
mod resolver; mod resolver;
mod shared; mod shared;
mod standalone; mod standalone;
mod sys;
mod task_runner; mod task_runner;
mod tools; mod tools;
mod tsc; mod tsc;

View file

@ -8,7 +8,6 @@
mod standalone; mod standalone;
mod args; mod args;
mod auth_tokens;
mod cache; mod cache;
mod emit; mod emit;
mod errors; mod errors;
@ -19,6 +18,7 @@ mod node;
mod npm; mod npm;
mod resolver; mod resolver;
mod shared; mod shared;
mod sys;
mod task_runner; mod task_runner;
mod util; mod util;
mod version; mod version;
@ -32,11 +32,13 @@ use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS; pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
use deno_terminal::colors; use deno_terminal::colors;
use indexmap::IndexMap; use indexmap::IndexMap;
use standalone::DenoCompileFileSystem;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::env::current_exe; use std::env::current_exe;
use std::sync::Arc;
use crate::args::Flags; use crate::args::Flags;
@ -93,7 +95,9 @@ fn main() {
Some(data.metadata.otel_config.clone()), Some(data.metadata.otel_config.clone()),
); );
load_env_vars(&data.metadata.env_vars_from_env_file); load_env_vars(&data.metadata.env_vars_from_env_file);
let exit_code = standalone::run(data).await?; let fs = DenoCompileFileSystem::new(data.vfs.clone());
let sys = crate::sys::CliSys::DenoCompile(fs.clone());
let exit_code = standalone::run(Arc::new(fs), sys, data).await?;
deno_runtime::exit(exit_code); deno_runtime::exit(exit_code);
} }
Ok(None) => Ok(()), Ok(None) => Ok(()),

View file

@ -11,36 +11,8 @@ use std::sync::atomic::AtomicU16;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use crate::args::jsr_url; use crate::node::CliNodeResolver;
use crate::args::CliLockfile; use crate::sys::CliSys;
use crate::args::CliOptions;
use crate::args::DenoSubcommand;
use crate::args::TsTypeLib;
use crate::cache::CodeCache;
use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
use crate::graph_util::CreateGraphOptions;
use crate::graph_util::ModuleGraphBuilder;
use crate::node;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
use crate::resolver::ModuleCodeStringSource;
use crate::resolver::NotSupportedKindInNpmError;
use crate::resolver::NpmModuleLoader;
use crate::tools::check;
use crate::tools::check::TypeChecker;
use crate::util::progress_bar::ProgressBar;
use crate::util::text_encoding::code_without_source_map;
use crate::util::text_encoding::source_map_from_code;
use crate::worker::CreateModuleLoaderResult;
use crate::worker::ModuleLoaderFactory;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleKind; use deno_ast::ModuleKind;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
@ -69,16 +41,45 @@ use deno_graph::ModuleGraph;
use deno_graph::Resolution; use deno_graph::Resolution;
use deno_graph::WasmModule; use deno_graph::WasmModule;
use deno_runtime::code_cache; use deno_runtime::code_cache;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use node_resolver::errors::ClosestPkgJsonError; use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use sys_traits::FsRead;
use crate::args::jsr_url;
use crate::args::CliLockfile;
use crate::args::CliOptions;
use crate::args::DenoSubcommand;
use crate::args::TsTypeLib;
use crate::cache::CodeCache;
use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
use crate::graph_util::CreateGraphOptions;
use crate::graph_util::ModuleGraphBuilder;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
use crate::resolver::ModuleCodeStringSource;
use crate::resolver::NotSupportedKindInNpmError;
use crate::resolver::NpmModuleLoader;
use crate::tools::check;
use crate::tools::check::TypeChecker;
use crate::util::progress_bar::ProgressBar;
use crate::util::text_encoding::code_without_source_map;
use crate::util::text_encoding::source_map_from_code;
use crate::worker::CreateModuleLoaderResult;
use crate::worker::ModuleLoaderFactory;
pub struct ModuleLoadPreparer { pub struct ModuleLoadPreparer {
options: Arc<CliOptions>, options: Arc<CliOptions>,
@ -215,17 +216,17 @@ struct SharedCliModuleLoaderState {
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
code_cache: Option<Arc<CodeCache>>, code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>, emitter: Arc<Emitter>,
fs: Arc<dyn FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
main_module_graph_container: Arc<MainModuleGraphContainer>, main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>, module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>, node_code_translator: Arc<CliNodeCodeTranslator>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_req_resolver: Arc<CliNpmReqResolver>, npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
npm_module_loader: NpmModuleLoader, npm_module_loader: NpmModuleLoader,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
sys: CliSys,
in_flight_loads_tracker: InFlightModuleLoadsTracker, in_flight_loads_tracker: InFlightModuleLoadsTracker,
} }
@ -275,17 +276,17 @@ impl CliModuleLoaderFactory {
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
code_cache: Option<Arc<CodeCache>>, code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>, emitter: Arc<Emitter>,
fs: Arc<dyn FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
main_module_graph_container: Arc<MainModuleGraphContainer>, main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>, module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>, node_code_translator: Arc<CliNodeCodeTranslator>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_req_resolver: Arc<CliNpmReqResolver>, npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
npm_module_loader: NpmModuleLoader, npm_module_loader: NpmModuleLoader,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
sys: CliSys,
) -> Self { ) -> Self {
Self { Self {
shared: Arc::new(SharedCliModuleLoaderState { shared: Arc::new(SharedCliModuleLoaderState {
@ -301,7 +302,6 @@ impl CliModuleLoaderFactory {
cjs_tracker, cjs_tracker,
code_cache, code_cache,
emitter, emitter,
fs,
in_npm_pkg_checker, in_npm_pkg_checker,
main_module_graph_container, main_module_graph_container,
module_load_preparer, module_load_preparer,
@ -312,6 +312,7 @@ impl CliModuleLoaderFactory {
npm_module_loader, npm_module_loader,
parsed_source_cache, parsed_source_cache,
resolver, resolver,
sys,
in_flight_loads_tracker: InFlightModuleLoadsTracker { in_flight_loads_tracker: InFlightModuleLoadsTracker {
loads_number: Arc::new(AtomicU16::new(0)), loads_number: Arc::new(AtomicU16::new(0)),
cleanup_task_timeout: 10_000, cleanup_task_timeout: 10_000,
@ -344,7 +345,7 @@ impl CliModuleLoaderFactory {
let node_require_loader = Rc::new(CliNodeRequireLoader { let node_require_loader = Rc::new(CliNodeRequireLoader {
cjs_tracker: self.shared.cjs_tracker.clone(), cjs_tracker: self.shared.cjs_tracker.clone(),
emitter: self.shared.emitter.clone(), emitter: self.shared.emitter.clone(),
fs: self.shared.fs.clone(), sys: self.shared.sys.clone(),
graph_container, graph_container,
in_npm_pkg_checker: self.shared.in_npm_pkg_checker.clone(), in_npm_pkg_checker: self.shared.in_npm_pkg_checker.clone(),
npm_resolver: self.shared.npm_resolver.clone(), npm_resolver: self.shared.npm_resolver.clone(),
@ -593,9 +594,9 @@ impl<TGraphContainer: ModuleGraphContainer>
Some(Module::Json(module)) => module.specifier.clone(), Some(Module::Json(module)) => module.specifier.clone(),
Some(Module::Wasm(module)) => module.specifier.clone(), Some(Module::Wasm(module)) => module.specifier.clone(),
Some(Module::External(module)) => { Some(Module::External(module)) => {
node::resolve_specifier_into_node_modules( node_resolver::resolve_specifier_into_node_modules(
&self.shared.sys,
&module.specifier, &module.specifier,
self.shared.fs.as_ref(),
) )
} }
None => specifier.into_owned(), None => specifier.into_owned(),
@ -996,7 +997,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
std::future::ready(()).boxed_local() std::future::ready(()).boxed_local()
} }
fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> { fn get_source_map(&self, file_name: &str) -> Option<Cow<[u8]>> {
let specifier = resolve_url(file_name).ok()?; let specifier = resolve_url(file_name).ok()?;
match specifier.scheme() { match specifier.scheme() {
// we should only be looking for emits for schemes that denote external // we should only be looking for emits for schemes that denote external
@ -1008,7 +1009,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
.0 .0
.load_prepared_module_for_source_map_sync(&specifier) .load_prepared_module_for_source_map_sync(&specifier)
.ok()??; .ok()??;
source_map_from_code(source.code.as_bytes()) source_map_from_code(source.code.as_bytes()).map(Cow::Owned)
} }
fn get_source_mapped_source_line( fn get_source_mapped_source_line(
@ -1091,7 +1092,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> { struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
emitter: Arc<Emitter>, emitter: Arc<Emitter>,
fs: Arc<dyn FileSystem>, sys: CliSys,
graph_container: TGraphContainer, graph_container: TGraphContainer,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
@ -1120,7 +1121,7 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
) -> Result<Cow<'static, str>, AnyError> { ) -> Result<Cow<'static, str>, AnyError> {
// todo(dsherret): use the preloaded module from the graph if available? // todo(dsherret): use the preloaded module from the graph if available?
let media_type = MediaType::from_path(path); let media_type = MediaType::from_path(path);
let text = self.fs.read_text_file_lossy_sync(path, None)?; let text = self.sys.fs_read_to_string_lossy(path)?;
if media_type.is_emittable() { if media_type.is_emittable() {
let specifier = deno_path_util::url_from_file_path(path)?; let specifier = deno_path_util::url_from_file_path(path)?;
if self.in_npm_pkg_checker.in_npm_package(&specifier) { if self.in_npm_pkg_checker.in_npm_package(&specifier) {

View file

@ -8,7 +8,7 @@ use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_graph::ParsedSourceStore; use deno_graph::ParsedSourceStore;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_node::DenoFsNodeResolverEnv; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis; use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
use node_resolver::analyze::CjsAnalysisExports; use node_resolver::analyze::CjsAnalysisExports;
use node_resolver::analyze::CjsCodeAnalyzer; use node_resolver::analyze::CjsCodeAnalyzer;
@ -20,24 +20,15 @@ use crate::cache::CacheDBHash;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::sys::CliSys;
pub type CliNodeCodeTranslator = pub type CliNodeCodeTranslator = NodeCodeTranslator<
NodeCodeTranslator<CliCjsCodeAnalyzer, DenoFsNodeResolverEnv>; CliCjsCodeAnalyzer,
RealIsBuiltInNodeModuleChecker,
/// Resolves a specifier that is pointing into a node_modules folder. CliSys,
/// >;
/// Note: This should be called whenever getting the specifier from pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver<CliSys>;
/// a Module::External(module) reference because that module might pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver<CliSys>;
/// not be fully resolved at the time deno_graph is analyzing it
/// because the node_modules folder might not exist at that time.
pub fn resolve_specifier_into_node_modules(
specifier: &ModuleSpecifier,
fs: &dyn deno_fs::FileSystem,
) -> ModuleSpecifier {
node_resolver::resolve_specifier_into_node_modules(specifier, &|path| {
fs.realpath_sync(path).map_err(|err| err.into_io_error())
})
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CliCjsAnalysis { pub enum CliCjsAnalysis {

View file

@ -4,27 +4,25 @@ use std::borrow::Cow;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use crate::sys::CliSys;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmNpmResolver;
use deno_resolver::npm::ByonmNpmResolverCreateOptions; use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::CliNpmReqResolver; use deno_resolver::npm::CliNpmReqResolver;
use deno_runtime::deno_node::DenoFsNodeResolverEnv;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use deno_runtime::ops::process::NpmProcessStateProvider; use deno_runtime::ops::process::NpmProcessStateProvider;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use crate::args::NpmProcessState; use crate::args::NpmProcessState;
use crate::args::NpmProcessStateKind; use crate::args::NpmProcessStateKind;
use crate::resolver::CliDenoResolverFs;
use super::CliNpmResolver; use super::CliNpmResolver;
use super::InnerCliNpmResolverRef; use super::InnerCliNpmResolverRef;
pub type CliByonmNpmResolverCreateOptions = pub type CliByonmNpmResolverCreateOptions =
ByonmNpmResolverCreateOptions<CliDenoResolverFs, DenoFsNodeResolverEnv>; ByonmNpmResolverCreateOptions<CliSys>;
pub type CliByonmNpmResolver = pub type CliByonmNpmResolver = ByonmNpmResolver<CliSys>;
ByonmNpmResolver<CliDenoResolverFs, DenoFsNodeResolverEnv>;
// todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple. // todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple.
#[derive(Debug)] #[derive(Debug)]

View file

@ -5,6 +5,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::sys::CliSys;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_cache_dir::npm::NpmCacheDir; use deno_cache_dir::npm::NpmCacheDir;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
@ -20,9 +21,10 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage; use deno_npm::NpmResolutionPackage;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_npm_cache::NpmCacheSetting;
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
use deno_resolver::npm::CliNpmReqResolver; use deno_resolver::npm::CliNpmReqResolver;
use deno_runtime::colors; use deno_runtime::colors;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use deno_runtime::ops::process::NpmProcessStateProvider; use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
@ -40,7 +42,6 @@ use crate::args::NpmProcessState;
use crate::args::NpmProcessStateKind; use crate::args::NpmProcessStateKind;
use crate::args::PackageJsonDepValueParseWithLocationError; use crate::args::PackageJsonDepValueParseWithLocationError;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::sync::AtomicFlag; use crate::util::sync::AtomicFlag;
@ -49,7 +50,7 @@ use self::resolvers::create_npm_fs_resolver;
use self::resolvers::NpmPackageFsResolver; use self::resolvers::NpmPackageFsResolver;
use super::CliNpmCache; use super::CliNpmCache;
use super::CliNpmCacheEnv; use super::CliNpmCacheHttpClient;
use super::CliNpmRegistryInfoProvider; use super::CliNpmRegistryInfoProvider;
use super::CliNpmResolver; use super::CliNpmResolver;
use super::CliNpmTarballCache; use super::CliNpmTarballCache;
@ -67,10 +68,10 @@ pub enum CliNpmResolverManagedSnapshotOption {
pub struct CliManagedNpmResolverCreateOptions { pub struct CliManagedNpmResolverCreateOptions {
pub snapshot: CliNpmResolverManagedSnapshotOption, pub snapshot: CliNpmResolverManagedSnapshotOption,
pub maybe_lockfile: Option<Arc<CliLockfile>>, pub maybe_lockfile: Option<Arc<CliLockfile>>,
pub fs: Arc<dyn deno_runtime::deno_fs::FileSystem>,
pub http_client_provider: Arc<crate::http_util::HttpClientProvider>, pub http_client_provider: Arc<crate::http_util::HttpClientProvider>,
pub npm_cache_dir: Arc<NpmCacheDir>, pub npm_cache_dir: Arc<NpmCacheDir>,
pub cache_setting: crate::args::CacheSetting, pub sys: CliSys,
pub cache_setting: deno_cache_dir::file_fetcher::CacheSetting,
pub text_only_progress_bar: crate::util::progress_bar::ProgressBar, pub text_only_progress_bar: crate::util::progress_bar::ProgressBar,
pub maybe_node_modules_path: Option<PathBuf>, pub maybe_node_modules_path: Option<PathBuf>,
pub npm_system_info: NpmSystemInfo, pub npm_system_info: NpmSystemInfo,
@ -82,9 +83,12 @@ pub struct CliManagedNpmResolverCreateOptions {
pub async fn create_managed_npm_resolver_for_lsp( pub async fn create_managed_npm_resolver_for_lsp(
options: CliManagedNpmResolverCreateOptions, options: CliManagedNpmResolverCreateOptions,
) -> Arc<dyn CliNpmResolver> { ) -> Arc<dyn CliNpmResolver> {
let cache_env = create_cache_env(&options); let npm_cache = create_cache(&options);
let npm_cache = create_cache(cache_env.clone(), &options); let http_client = Arc::new(CliNpmCacheHttpClient::new(
let npm_api = create_api(npm_cache.clone(), cache_env.clone(), &options); options.http_client_provider.clone(),
options.text_only_progress_bar.clone(),
));
let npm_api = create_api(npm_cache.clone(), http_client.clone(), &options);
// spawn due to the lsp's `Send` requirement // spawn due to the lsp's `Send` requirement
deno_core::unsync::spawn(async move { deno_core::unsync::spawn(async move {
let snapshot = match resolve_snapshot(&npm_api, options.snapshot).await { let snapshot = match resolve_snapshot(&npm_api, options.snapshot).await {
@ -95,14 +99,14 @@ pub async fn create_managed_npm_resolver_for_lsp(
} }
}; };
create_inner( create_inner(
cache_env, http_client,
options.fs,
options.maybe_lockfile,
npm_api,
npm_cache, npm_cache,
options.npmrc,
options.npm_install_deps_provider, options.npm_install_deps_provider,
npm_api,
options.sys,
options.text_only_progress_bar, options.text_only_progress_bar,
options.maybe_lockfile,
options.npmrc,
options.maybe_node_modules_path, options.maybe_node_modules_path,
options.npm_system_info, options.npm_system_info,
snapshot, snapshot,
@ -116,19 +120,22 @@ pub async fn create_managed_npm_resolver_for_lsp(
pub async fn create_managed_npm_resolver( pub async fn create_managed_npm_resolver(
options: CliManagedNpmResolverCreateOptions, options: CliManagedNpmResolverCreateOptions,
) -> Result<Arc<dyn CliNpmResolver>, AnyError> { ) -> Result<Arc<dyn CliNpmResolver>, AnyError> {
let npm_cache_env = create_cache_env(&options); let npm_cache = create_cache(&options);
let npm_cache = create_cache(npm_cache_env.clone(), &options); let http_client = Arc::new(CliNpmCacheHttpClient::new(
let api = create_api(npm_cache.clone(), npm_cache_env.clone(), &options); options.http_client_provider.clone(),
options.text_only_progress_bar.clone(),
));
let api = create_api(npm_cache.clone(), http_client.clone(), &options);
let snapshot = resolve_snapshot(&api, options.snapshot).await?; let snapshot = resolve_snapshot(&api, options.snapshot).await?;
Ok(create_inner( Ok(create_inner(
npm_cache_env, http_client,
options.fs,
options.maybe_lockfile,
api,
npm_cache, npm_cache,
options.npmrc,
options.npm_install_deps_provider, options.npm_install_deps_provider,
api,
options.sys,
options.text_only_progress_bar, options.text_only_progress_bar,
options.maybe_lockfile,
options.npmrc,
options.maybe_node_modules_path, options.maybe_node_modules_path,
options.npm_system_info, options.npm_system_info,
snapshot, snapshot,
@ -138,14 +145,14 @@ pub async fn create_managed_npm_resolver(
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn create_inner( fn create_inner(
env: Arc<CliNpmCacheEnv>, http_client: Arc<CliNpmCacheHttpClient>,
fs: Arc<dyn deno_runtime::deno_fs::FileSystem>,
maybe_lockfile: Option<Arc<CliLockfile>>,
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
npm_cache: Arc<CliNpmCache>, npm_cache: Arc<CliNpmCache>,
npm_rc: Arc<ResolvedNpmRc>,
npm_install_deps_provider: Arc<NpmInstallDepsProvider>, npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
sys: CliSys,
text_only_progress_bar: crate::util::progress_bar::ProgressBar, text_only_progress_bar: crate::util::progress_bar::ProgressBar,
maybe_lockfile: Option<Arc<CliLockfile>>,
npm_rc: Arc<ResolvedNpmRc>,
node_modules_dir_path: Option<PathBuf>, node_modules_dir_path: Option<PathBuf>,
npm_system_info: NpmSystemInfo, npm_system_info: NpmSystemInfo,
snapshot: Option<ValidSerializedNpmResolutionSnapshot>, snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
@ -158,28 +165,29 @@ fn create_inner(
)); ));
let tarball_cache = Arc::new(CliNpmTarballCache::new( let tarball_cache = Arc::new(CliNpmTarballCache::new(
npm_cache.clone(), npm_cache.clone(),
env, http_client,
sys.clone(),
npm_rc.clone(), npm_rc.clone(),
)); ));
let fs_resolver = create_npm_fs_resolver( let fs_resolver = create_npm_fs_resolver(
fs.clone(),
npm_cache.clone(), npm_cache.clone(),
&npm_install_deps_provider, &npm_install_deps_provider,
&text_only_progress_bar, &text_only_progress_bar,
resolution.clone(), resolution.clone(),
sys.clone(),
tarball_cache.clone(), tarball_cache.clone(),
node_modules_dir_path, node_modules_dir_path,
npm_system_info.clone(), npm_system_info.clone(),
lifecycle_scripts.clone(), lifecycle_scripts.clone(),
); );
Arc::new(ManagedCliNpmResolver::new( Arc::new(ManagedCliNpmResolver::new(
fs,
fs_resolver, fs_resolver,
maybe_lockfile, maybe_lockfile,
registry_info_provider, registry_info_provider,
npm_cache, npm_cache,
npm_install_deps_provider, npm_install_deps_provider,
resolution, resolution,
sys,
tarball_cache, tarball_cache,
text_only_progress_bar, text_only_progress_bar,
npm_system_info, npm_system_info,
@ -187,36 +195,25 @@ fn create_inner(
)) ))
} }
fn create_cache_env(
options: &CliManagedNpmResolverCreateOptions,
) -> Arc<CliNpmCacheEnv> {
Arc::new(CliNpmCacheEnv::new(
options.fs.clone(),
options.http_client_provider.clone(),
options.text_only_progress_bar.clone(),
))
}
fn create_cache( fn create_cache(
env: Arc<CliNpmCacheEnv>,
options: &CliManagedNpmResolverCreateOptions, options: &CliManagedNpmResolverCreateOptions,
) -> Arc<CliNpmCache> { ) -> Arc<CliNpmCache> {
Arc::new(CliNpmCache::new( Arc::new(CliNpmCache::new(
options.npm_cache_dir.clone(), options.npm_cache_dir.clone(),
options.cache_setting.as_npm_cache_setting(), options.sys.clone(),
env, NpmCacheSetting::from_cache_setting(&options.cache_setting),
options.npmrc.clone(), options.npmrc.clone(),
)) ))
} }
fn create_api( fn create_api(
cache: Arc<CliNpmCache>, cache: Arc<CliNpmCache>,
env: Arc<CliNpmCacheEnv>, http_client: Arc<CliNpmCacheHttpClient>,
options: &CliManagedNpmResolverCreateOptions, options: &CliManagedNpmResolverCreateOptions,
) -> Arc<CliNpmRegistryInfoProvider> { ) -> Arc<CliNpmRegistryInfoProvider> {
Arc::new(CliNpmRegistryInfoProvider::new( Arc::new(CliNpmRegistryInfoProvider::new(
cache, cache,
env, http_client,
options.npmrc.clone(), options.npmrc.clone(),
)) ))
} }
@ -305,12 +302,12 @@ pub enum PackageCaching<'a> {
/// An npm resolver where the resolution is managed by Deno rather than /// An npm resolver where the resolution is managed by Deno rather than
/// the user bringing their own node_modules (BYONM) on the file system. /// the user bringing their own node_modules (BYONM) on the file system.
pub struct ManagedCliNpmResolver { pub struct ManagedCliNpmResolver {
fs: Arc<dyn FileSystem>,
fs_resolver: Arc<dyn NpmPackageFsResolver>, fs_resolver: Arc<dyn NpmPackageFsResolver>,
maybe_lockfile: Option<Arc<CliLockfile>>, maybe_lockfile: Option<Arc<CliLockfile>>,
registry_info_provider: Arc<CliNpmRegistryInfoProvider>, registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
npm_cache: Arc<CliNpmCache>, npm_cache: Arc<CliNpmCache>,
npm_install_deps_provider: Arc<NpmInstallDepsProvider>, npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
sys: CliSys,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
text_only_progress_bar: ProgressBar, text_only_progress_bar: ProgressBar,
@ -330,20 +327,19 @@ impl std::fmt::Debug for ManagedCliNpmResolver {
impl ManagedCliNpmResolver { impl ManagedCliNpmResolver {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
fs: Arc<dyn FileSystem>,
fs_resolver: Arc<dyn NpmPackageFsResolver>, fs_resolver: Arc<dyn NpmPackageFsResolver>,
maybe_lockfile: Option<Arc<CliLockfile>>, maybe_lockfile: Option<Arc<CliLockfile>>,
registry_info_provider: Arc<CliNpmRegistryInfoProvider>, registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
npm_cache: Arc<CliNpmCache>, npm_cache: Arc<CliNpmCache>,
npm_install_deps_provider: Arc<NpmInstallDepsProvider>, npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
sys: CliSys,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
text_only_progress_bar: ProgressBar, text_only_progress_bar: ProgressBar,
npm_system_info: NpmSystemInfo, npm_system_info: NpmSystemInfo,
lifecycle_scripts: LifecycleScriptsConfig, lifecycle_scripts: LifecycleScriptsConfig,
) -> Self { ) -> Self {
Self { Self {
fs,
fs_resolver, fs_resolver,
maybe_lockfile, maybe_lockfile,
registry_info_provider, registry_info_provider,
@ -351,6 +347,7 @@ impl ManagedCliNpmResolver {
npm_install_deps_provider, npm_install_deps_provider,
text_only_progress_bar, text_only_progress_bar,
resolution, resolution,
sys,
tarball_cache, tarball_cache,
npm_system_info, npm_system_info,
top_level_install_flag: Default::default(), top_level_install_flag: Default::default(),
@ -363,8 +360,7 @@ impl ManagedCliNpmResolver {
pkg_id: &NpmPackageId, pkg_id: &NpmPackageId,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, AnyError> {
let path = self.fs_resolver.package_folder(pkg_id)?; let path = self.fs_resolver.package_folder(pkg_id)?;
let path = let path = canonicalize_path_maybe_not_exists(&self.sys, &path)?;
canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref())?;
log::debug!( log::debug!(
"Resolved package folder of {} to {}", "Resolved package folder of {} to {}",
pkg_id.as_serialized(), pkg_id.as_serialized(),
@ -559,11 +555,11 @@ impl ManagedCliNpmResolver {
&self, &self,
) -> Result<(), Box<PackageJsonDepValueParseWithLocationError>> { ) -> Result<(), Box<PackageJsonDepValueParseWithLocationError>> {
for err in self.npm_install_deps_provider.pkg_json_dep_errors() { for err in self.npm_install_deps_provider.pkg_json_dep_errors() {
match &err.source { match err.source.as_kind() {
deno_package_json::PackageJsonDepValueParseError::VersionReq(_) => { deno_package_json::PackageJsonDepValueParseErrorKind::VersionReq(_) => {
return Err(Box::new(err.clone())); return Err(Box::new(err.clone()));
} }
deno_package_json::PackageJsonDepValueParseError::Unsupported { deno_package_json::PackageJsonDepValueParseErrorKind::Unsupported {
.. ..
} => { } => {
// only warn for this one // only warn for this one
@ -666,12 +662,13 @@ impl NpmPackageFolderResolver for ManagedCliNpmResolver {
.fs_resolver .fs_resolver
.resolve_package_folder_from_package(name, referrer)?; .resolve_package_folder_from_package(name, referrer)?;
let path = let path =
canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref()) canonicalize_path_maybe_not_exists(&self.sys, &path).map_err(|err| {
.map_err(|err| PackageFolderResolveIoError { PackageFolderResolveIoError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.clone(),
source: err, source: err,
})?; }
})?;
log::debug!("Resolved {} from {} to {}", name, referrer, path.display()); log::debug!("Resolved {} from {} to {}", name, referrer, path.display());
Ok(path) Ok(path)
} }
@ -727,13 +724,12 @@ impl CliNpmResolver for ManagedCliNpmResolver {
)); ));
Arc::new(ManagedCliNpmResolver::new( Arc::new(ManagedCliNpmResolver::new(
self.fs.clone(),
create_npm_fs_resolver( create_npm_fs_resolver(
self.fs.clone(),
self.npm_cache.clone(), self.npm_cache.clone(),
&self.npm_install_deps_provider, &self.npm_install_deps_provider,
&self.text_only_progress_bar, &self.text_only_progress_bar,
npm_resolution.clone(), npm_resolution.clone(),
self.sys.clone(),
self.tarball_cache.clone(), self.tarball_cache.clone(),
self.root_node_modules_path().map(ToOwned::to_owned), self.root_node_modules_path().map(ToOwned::to_owned),
self.npm_system_info.clone(), self.npm_system_info.clone(),
@ -744,6 +740,7 @@ impl CliNpmResolver for ManagedCliNpmResolver {
self.npm_cache.clone(), self.npm_cache.clone(),
self.npm_install_deps_provider.clone(), self.npm_install_deps_provider.clone(),
npm_resolution, npm_resolution,
self.sys.clone(),
self.tarball_cache.clone(), self.tarball_cache.clone(),
self.text_only_progress_bar.clone(), self.text_only_progress_bar.clone(),
self.npm_system_info.clone(), self.npm_system_info.clone(),

View file

@ -4,6 +4,7 @@ use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use capacity_builder::StringBuilder;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_lockfile::NpmPackageDependencyLockfileInfo; use deno_lockfile::NpmPackageDependencyLockfileInfo;
use deno_lockfile::NpmPackageLockfileInfo; use deno_lockfile::NpmPackageLockfileInfo;
@ -24,6 +25,7 @@ use deno_npm::NpmSystemInfo;
use deno_semver::jsr::JsrDepPackageReq; use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::SmallStackString;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use crate::args::CliLockfile; use crate::args::CliLockfile;
@ -336,7 +338,13 @@ fn populate_lockfile_from_snapshot(
let id = &snapshot.resolve_package_from_deno_module(nv).unwrap().id; let id = &snapshot.resolve_package_from_deno_module(nv).unwrap().id;
lockfile.insert_package_specifier( lockfile.insert_package_specifier(
JsrDepPackageReq::npm(package_req.clone()), JsrDepPackageReq::npm(package_req.clone()),
format!("{}{}", id.nv.version, id.peer_deps_serialized()), {
StringBuilder::<SmallStackString>::build(|builder| {
builder.append(&id.nv.version);
builder.append(&id.peer_dependencies);
})
.unwrap()
},
); );
} }
for package in snapshot.all_packages_for_every_system() { for package in snapshot.all_packages_for_every_system() {

View file

@ -11,7 +11,6 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use super::super::PackageCaching;
use async_trait::async_trait; use async_trait::async_trait;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
@ -21,11 +20,13 @@ use deno_core::futures::StreamExt;
use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage; use deno_npm::NpmResolutionPackage;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveError;
use sys_traits::FsCanonicalize;
use super::super::PackageCaching;
use crate::npm::CliNpmTarballCache; use crate::npm::CliNpmTarballCache;
use crate::sys::CliSys;
/// Part of the resolution that interacts with the file system. /// Part of the resolution that interacts with the file system.
#[async_trait(?Send)] #[async_trait(?Send)]
@ -73,15 +74,15 @@ pub trait NpmPackageFsResolver: Send + Sync {
#[derive(Debug)] #[derive(Debug)]
pub struct RegistryReadPermissionChecker { pub struct RegistryReadPermissionChecker {
fs: Arc<dyn FileSystem>, sys: CliSys,
cache: Mutex<HashMap<PathBuf, PathBuf>>, cache: Mutex<HashMap<PathBuf, PathBuf>>,
registry_path: PathBuf, registry_path: PathBuf,
} }
impl RegistryReadPermissionChecker { impl RegistryReadPermissionChecker {
pub fn new(fs: Arc<dyn FileSystem>, registry_path: PathBuf) -> Self { pub fn new(sys: CliSys, registry_path: PathBuf) -> Self {
Self { Self {
fs, sys,
registry_path, registry_path,
cache: Default::default(), cache: Default::default(),
} }
@ -108,7 +109,7 @@ impl RegistryReadPermissionChecker {
|path: &Path| -> Result<Option<PathBuf>, AnyError> { |path: &Path| -> Result<Option<PathBuf>, AnyError> {
match cache.get(path) { match cache.get(path) {
Some(canon) => Ok(Some(canon.clone())), Some(canon) => Ok(Some(canon.clone())),
None => match self.fs.realpath_sync(path) { None => match self.sys.fs_canonicalize(path) {
Ok(canon) => { Ok(canon) => {
cache.insert(path.to_path_buf(), canon.clone()); cache.insert(path.to_path_buf(), canon.clone());
Ok(Some(canon)) Ok(Some(canon))

View file

@ -28,8 +28,10 @@ fn default_bin_name(package: &NpmResolutionPackage) -> &str {
.id .id
.nv .nv
.name .name
.as_str()
.rsplit_once('/') .rsplit_once('/')
.map_or(package.id.nv.name.as_str(), |(_, name)| name) .map(|(_, name)| name)
.unwrap_or(package.id.nv.name.as_str())
} }
pub fn warn_missing_entrypoint( pub fn warn_missing_entrypoint(

View file

@ -11,6 +11,7 @@ use crate::colors;
use crate::npm::managed::PackageCaching; use crate::npm::managed::PackageCaching;
use crate::npm::CliNpmCache; use crate::npm::CliNpmCache;
use crate::npm::CliNpmTarballCache; use crate::npm::CliNpmTarballCache;
use crate::sys::CliSys;
use async_trait::async_trait; use async_trait::async_trait;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -18,7 +19,6 @@ use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage; use deno_npm::NpmResolutionPackage;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveError;
use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageNotFoundError;
@ -47,15 +47,15 @@ pub struct GlobalNpmPackageResolver {
impl GlobalNpmPackageResolver { impl GlobalNpmPackageResolver {
pub fn new( pub fn new(
cache: Arc<CliNpmCache>, cache: Arc<CliNpmCache>,
fs: Arc<dyn FileSystem>,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
sys: CliSys,
system_info: NpmSystemInfo, system_info: NpmSystemInfo,
lifecycle_scripts: LifecycleScriptsConfig, lifecycle_scripts: LifecycleScriptsConfig,
) -> Self { ) -> Self {
Self { Self {
registry_read_permission_checker: RegistryReadPermissionChecker::new( registry_read_permission_checker: RegistryReadPermissionChecker::new(
fs, sys,
cache.root_dir_path().to_path_buf(), cache.root_dir_path().to_path_buf(),
), ),
cache, cache,

View file

@ -15,11 +15,6 @@ use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use crate::args::LifecycleScriptsConfig;
use crate::colors;
use crate::npm::managed::PackageCaching;
use crate::npm::CliNpmCache;
use crate::npm::CliNpmTarballCache;
use async_trait::async_trait; use async_trait::async_trait;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_cache_dir::npm::mixed_case_package_name_decode; use deno_cache_dir::npm::mixed_case_package_name_decode;
@ -34,21 +29,28 @@ use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage; use deno_npm::NpmResolutionPackage;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_path_util::fs::atomic_write_file_with_retries;
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder; use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::StackString;
use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveError;
use node_resolver::errors::PackageFolderResolveIoError; use node_resolver::errors::PackageFolderResolveIoError;
use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageNotFoundError;
use node_resolver::errors::ReferrerNotFoundError; use node_resolver::errors::ReferrerNotFoundError;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use sys_traits::FsMetadata;
use crate::args::LifecycleScriptsConfig;
use crate::args::NpmInstallDepsProvider; use crate::args::NpmInstallDepsProvider;
use crate::cache::CACHE_PERM; use crate::cache::CACHE_PERM;
use crate::util::fs::atomic_write_file_with_retries; use crate::colors;
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs; use crate::npm::managed::PackageCaching;
use crate::npm::CliNpmCache;
use crate::npm::CliNpmTarballCache;
use crate::sys::CliSys;
use crate::util::fs::clone_dir_recursive; use crate::util::fs::clone_dir_recursive;
use crate::util::fs::symlink_dir; use crate::util::fs::symlink_dir;
use crate::util::fs::LaxSingleProcessFsFlag; use crate::util::fs::LaxSingleProcessFsFlag;
@ -65,10 +67,10 @@ use super::common::RegistryReadPermissionChecker;
#[derive(Debug)] #[derive(Debug)]
pub struct LocalNpmPackageResolver { pub struct LocalNpmPackageResolver {
cache: Arc<CliNpmCache>, cache: Arc<CliNpmCache>,
fs: Arc<dyn deno_fs::FileSystem>,
npm_install_deps_provider: Arc<NpmInstallDepsProvider>, npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
progress_bar: ProgressBar, progress_bar: ProgressBar,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
sys: CliSys,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
root_node_modules_path: PathBuf, root_node_modules_path: PathBuf,
root_node_modules_url: Url, root_node_modules_url: Url,
@ -81,10 +83,10 @@ impl LocalNpmPackageResolver {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
cache: Arc<CliNpmCache>, cache: Arc<CliNpmCache>,
fs: Arc<dyn deno_fs::FileSystem>,
npm_install_deps_provider: Arc<NpmInstallDepsProvider>, npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
progress_bar: ProgressBar, progress_bar: ProgressBar,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
sys: CliSys,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
node_modules_folder: PathBuf, node_modules_folder: PathBuf,
system_info: NpmSystemInfo, system_info: NpmSystemInfo,
@ -92,15 +94,15 @@ impl LocalNpmPackageResolver {
) -> Self { ) -> Self {
Self { Self {
cache, cache,
fs: fs.clone(),
npm_install_deps_provider, npm_install_deps_provider,
progress_bar, progress_bar,
resolution, resolution,
tarball_cache, tarball_cache,
registry_read_permission_checker: RegistryReadPermissionChecker::new( registry_read_permission_checker: RegistryReadPermissionChecker::new(
fs, sys.clone(),
node_modules_folder.clone(), node_modules_folder.clone(),
), ),
sys,
root_node_modules_url: Url::from_directory_path(&node_modules_folder) root_node_modules_url: Url::from_directory_path(&node_modules_folder)
.unwrap(), .unwrap(),
root_node_modules_path: node_modules_folder, root_node_modules_path: node_modules_folder,
@ -139,8 +141,7 @@ impl LocalNpmPackageResolver {
}; };
// Canonicalize the path so it's not pointing to the symlinked directory // Canonicalize the path so it's not pointing to the symlinked directory
// in `node_modules` directory of the referrer. // in `node_modules` directory of the referrer.
canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref()) canonicalize_path_maybe_not_exists(&self.sys, &path).map(Some)
.map(Some)
} }
fn resolve_package_folder_from_specifier( fn resolve_package_folder_from_specifier(
@ -209,7 +210,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
}; };
let sub_dir = join_package_name(&node_modules_folder, name); let sub_dir = join_package_name(&node_modules_folder, name);
if self.fs.is_dir_sync(&sub_dir) { if self.sys.fs_is_dir_no_err(&sub_dir) {
return Ok(sub_dir); return Ok(sub_dir);
} }
@ -355,8 +356,10 @@ async fn sync_resolution_with_fs(
let package_partitions = let package_partitions =
snapshot.all_system_packages_partitioned(system_info); snapshot.all_system_packages_partitioned(system_info);
let mut cache_futures = FuturesUnordered::new(); let mut cache_futures = FuturesUnordered::new();
let mut newest_packages_by_name: HashMap<&String, &NpmResolutionPackage> = let mut newest_packages_by_name: HashMap<
HashMap::with_capacity(package_partitions.packages.len()); &StackString,
&NpmResolutionPackage,
> = HashMap::with_capacity(package_partitions.packages.len());
let bin_entries = Rc::new(RefCell::new(bin_entries::BinEntries::new())); let bin_entries = Rc::new(RefCell::new(bin_entries::BinEntries::new()));
let mut lifecycle_scripts = let mut lifecycle_scripts =
super::common::lifecycle_scripts::LifecycleScripts::new( super::common::lifecycle_scripts::LifecycleScripts::new(
@ -536,7 +539,7 @@ async fn sync_resolution_with_fs(
} }
} }
let mut found_names: HashMap<&String, &PackageNv> = HashMap::new(); let mut found_names: HashMap<&StackString, &PackageNv> = HashMap::new();
// set of node_modules in workspace packages that we've already ensured exist // set of node_modules in workspace packages that we've already ensured exist
let mut existing_child_node_modules_dirs: HashSet<PathBuf> = HashSet::new(); let mut existing_child_node_modules_dirs: HashSet<PathBuf> = HashSet::new();
@ -922,7 +925,13 @@ impl SetupCache {
} }
bincode::serialize(&self.current).ok().and_then(|data| { bincode::serialize(&self.current).ok().and_then(|data| {
atomic_write_file_with_retries(&self.file_path, data, CACHE_PERM).ok() atomic_write_file_with_retries(
&CliSys::default(),
&self.file_path,
&data,
CACHE_PERM,
)
.ok()
}); });
true true
} }
@ -1012,10 +1021,10 @@ fn get_package_folder_id_from_folder_name(
) -> Option<NpmPackageCacheFolderId> { ) -> Option<NpmPackageCacheFolderId> {
let folder_name = folder_name.replace('+', "/"); let folder_name = folder_name.replace('+', "/");
let (name, ending) = folder_name.rsplit_once('@')?; let (name, ending) = folder_name.rsplit_once('@')?;
let name = if let Some(encoded_name) = name.strip_prefix('_') { let name: StackString = if let Some(encoded_name) = name.strip_prefix('_') {
mixed_case_package_name_decode(encoded_name)? StackString::from_string(mixed_case_package_name_decode(encoded_name)?)
} else { } else {
name.to_string() name.into()
}; };
let (raw_version, copy_index) = match ending.split_once('_') { let (raw_version, copy_index) = match ending.split_once('_') {
Some((raw_version, copy_index)) => { Some((raw_version, copy_index)) => {

View file

@ -7,8 +7,8 @@ mod local;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::sys::CliSys;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs::FileSystem;
use crate::args::LifecycleScriptsConfig; use crate::args::LifecycleScriptsConfig;
use crate::args::NpmInstallDepsProvider; use crate::args::NpmInstallDepsProvider;
@ -25,11 +25,11 @@ use super::resolution::NpmResolution;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn create_npm_fs_resolver( pub fn create_npm_fs_resolver(
fs: Arc<dyn FileSystem>,
npm_cache: Arc<CliNpmCache>, npm_cache: Arc<CliNpmCache>,
npm_install_deps_provider: &Arc<NpmInstallDepsProvider>, npm_install_deps_provider: &Arc<NpmInstallDepsProvider>,
progress_bar: &ProgressBar, progress_bar: &ProgressBar,
resolution: Arc<NpmResolution>, resolution: Arc<NpmResolution>,
sys: CliSys,
tarball_cache: Arc<CliNpmTarballCache>, tarball_cache: Arc<CliNpmTarballCache>,
maybe_node_modules_path: Option<PathBuf>, maybe_node_modules_path: Option<PathBuf>,
system_info: NpmSystemInfo, system_info: NpmSystemInfo,
@ -38,10 +38,10 @@ pub fn create_npm_fs_resolver(
match maybe_node_modules_path { match maybe_node_modules_path {
Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new( Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new(
npm_cache, npm_cache,
fs,
npm_install_deps_provider.clone(), npm_install_deps_provider.clone(),
progress_bar.clone(), progress_bar.clone(),
resolution, resolution,
sys,
tarball_cache, tarball_cache,
node_modules_folder, node_modules_folder,
system_info, system_info,
@ -49,9 +49,9 @@ pub fn create_npm_fs_resolver(
)), )),
None => Arc::new(GlobalNpmPackageResolver::new( None => Arc::new(GlobalNpmPackageResolver::new(
npm_cache, npm_cache,
fs,
tarball_cache, tarball_cache,
resolution, resolution,
sys,
system_info, system_info,
lifecycle_scripts, lifecycle_scripts,
)), )),

View file

@ -7,6 +7,7 @@ use std::borrow::Cow;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use crate::sys::CliSys;
use dashmap::DashMap; use dashmap::DashMap;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
@ -17,7 +18,6 @@ use deno_resolver::npm::ByonmInNpmPackageChecker;
use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmNpmResolver;
use deno_resolver::npm::CliNpmReqResolver; use deno_resolver::npm::CliNpmReqResolver;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use deno_runtime::ops::process::NpmProcessStateProvider; use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
@ -28,11 +28,8 @@ use managed::create_managed_in_npm_pkg_checker;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::util::fs::atomic_write_file_with_retries_and_fs;
use crate::util::fs::hard_link_dir_recursive;
use crate::util::fs::AtomicWriteFileFsAdapter;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
pub use self::byonm::CliByonmNpmResolver; pub use self::byonm::CliByonmNpmResolver;
@ -43,26 +40,24 @@ pub use self::managed::CliNpmResolverManagedSnapshotOption;
pub use self::managed::ManagedCliNpmResolver; pub use self::managed::ManagedCliNpmResolver;
pub use self::managed::PackageCaching; pub use self::managed::PackageCaching;
pub type CliNpmTarballCache = deno_npm_cache::TarballCache<CliNpmCacheEnv>; pub type CliNpmTarballCache =
pub type CliNpmCache = deno_npm_cache::NpmCache<CliNpmCacheEnv>; deno_npm_cache::TarballCache<CliNpmCacheHttpClient, CliSys>;
pub type CliNpmCache = deno_npm_cache::NpmCache<CliSys>;
pub type CliNpmRegistryInfoProvider = pub type CliNpmRegistryInfoProvider =
deno_npm_cache::RegistryInfoProvider<CliNpmCacheEnv>; deno_npm_cache::RegistryInfoProvider<CliNpmCacheHttpClient, CliSys>;
#[derive(Debug)] #[derive(Debug)]
pub struct CliNpmCacheEnv { pub struct CliNpmCacheHttpClient {
fs: Arc<dyn FileSystem>,
http_client_provider: Arc<HttpClientProvider>, http_client_provider: Arc<HttpClientProvider>,
progress_bar: ProgressBar, progress_bar: ProgressBar,
} }
impl CliNpmCacheEnv { impl CliNpmCacheHttpClient {
pub fn new( pub fn new(
fs: Arc<dyn FileSystem>,
http_client_provider: Arc<HttpClientProvider>, http_client_provider: Arc<HttpClientProvider>,
progress_bar: ProgressBar, progress_bar: ProgressBar,
) -> Self { ) -> Self {
Self { Self {
fs,
http_client_provider, http_client_provider,
progress_bar, progress_bar,
} }
@ -70,35 +65,7 @@ impl CliNpmCacheEnv {
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl deno_npm_cache::NpmCacheEnv for CliNpmCacheEnv { impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
fn exists(&self, path: &Path) -> bool {
self.fs.exists_sync(path)
}
fn hard_link_dir_recursive(
&self,
from: &Path,
to: &Path,
) -> Result<(), AnyError> {
// todo(dsherret): use self.fs here instead
hard_link_dir_recursive(from, to)
}
fn atomic_write_file_with_retries(
&self,
file_path: &Path,
data: &[u8],
) -> std::io::Result<()> {
atomic_write_file_with_retries_and_fs(
&AtomicWriteFileFsAdapter {
fs: self.fs.as_ref(),
write_mode: crate::cache::CACHE_PERM,
},
file_path,
data,
)
}
async fn download_with_retries_on_any_tokio_runtime( async fn download_with_retries_on_any_tokio_runtime(
&self, &self,
url: Url, url: Url,
@ -115,14 +82,14 @@ impl deno_npm_cache::NpmCacheEnv for CliNpmCacheEnv {
.download_with_progress_and_retries(url, maybe_auth_header, &guard) .download_with_progress_and_retries(url, maybe_auth_header, &guard)
.await .await
.map_err(|err| { .map_err(|err| {
use crate::http_util::DownloadError::*; use crate::http_util::DownloadErrorKind::*;
let status_code = match &err { let status_code = match err.as_kind() {
Fetch { .. } Fetch { .. }
| UrlParse { .. } | UrlParse { .. }
| HttpParse { .. } | HttpParse { .. }
| Json { .. } | Json { .. }
| ToStr { .. } | ToStr { .. }
| NoRedirectHeader { .. } | RedirectHeaderParse { .. }
| TooManyRedirects => None, | TooManyRedirects => None,
BadResponse(bad_response_error) => { BadResponse(bad_response_error) => {
Some(bad_response_error.status_code) Some(bad_response_error.status_code)
@ -232,13 +199,13 @@ pub trait CliNpmResolver: NpmPackageFolderResolver + CliNpmReqResolver {
pub struct NpmFetchResolver { pub struct NpmFetchResolver {
nv_by_req: DashMap<PackageReq, Option<PackageNv>>, nv_by_req: DashMap<PackageReq, Option<PackageNv>>,
info_by_name: DashMap<String, Option<Arc<NpmPackageInfo>>>, info_by_name: DashMap<String, Option<Arc<NpmPackageInfo>>>,
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
npmrc: Arc<ResolvedNpmRc>, npmrc: Arc<ResolvedNpmRc>,
} }
impl NpmFetchResolver { impl NpmFetchResolver {
pub fn new( pub fn new(
file_fetcher: Arc<FileFetcher>, file_fetcher: Arc<CliFileFetcher>,
npmrc: Arc<ResolvedNpmRc>, npmrc: Arc<ResolvedNpmRc>,
) -> Self { ) -> Self {
Self { Self {

34
cli/ops/lint.rs Normal file
View file

@ -0,0 +1,34 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op2;
use crate::tools::lint;
deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],);
#[op2]
#[buffer]
fn op_lint_create_serialized_ast(
#[string] file_name: &str,
#[string] source: String,
) -> Result<Vec<u8>, AnyError> {
let file_text = deno_ast::strip_bom(source);
let path = std::env::current_dir()?.join(file_name);
let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| {
generic_error(format!("Failed to parse path as URL: {}", path.display()))
})?;
let media_type = MediaType::from_specifier(&specifier);
let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
specifier,
text: file_text.into(),
media_type,
capture_tokens: false,
scope_analysis: false,
maybe_syntax: None,
})?;
Ok(lint::serialize_ast_to_buffer(&parsed_source))
}

View file

@ -2,4 +2,5 @@
pub mod bench; pub mod bench;
pub mod jupyter; pub mod jupyter;
pub mod lint;
pub mod testing; pub mod testing;

View file

@ -1,5 +1,11 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use crate::sys::CliSys;
use async_trait::async_trait; use async_trait::async_trait;
use dashmap::DashMap; use dashmap::DashMap;
use dashmap::DashSet; use dashmap::DashSet;
@ -20,16 +26,13 @@ use deno_npm::resolution::NpmResolutionError;
use deno_resolver::sloppy_imports::SloppyImportsResolver; use deno_resolver::sloppy_imports::SloppyImportsResolver;
use deno_runtime::colors; use deno_runtime::colors;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::is_builtin_node_module; use deno_runtime::deno_node::is_builtin_node_module;
use deno_runtime::deno_node::DenoFsNodeResolverEnv; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use std::borrow::Cow; use sys_traits::FsMetadata;
use std::path::Path; use sys_traits::FsMetadataValue;
use std::path::PathBuf;
use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
use crate::args::NpmCachingStrategy; use crate::args::NpmCachingStrategy;
@ -40,18 +43,17 @@ use crate::npm::InnerCliNpmResolverRef;
use crate::util::sync::AtomicFlag; use crate::util::sync::AtomicFlag;
use crate::util::text_encoding::from_utf8_lossy_cow; use crate::util::text_encoding::from_utf8_lossy_cow;
pub type CjsTracker = deno_resolver::cjs::CjsTracker<DenoFsNodeResolverEnv>; pub type CjsTracker = deno_resolver::cjs::CjsTracker<CliSys>;
pub type IsCjsResolver = pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver<CliSys>;
deno_resolver::cjs::IsCjsResolver<DenoFsNodeResolverEnv>;
pub type CliSloppyImportsResolver = pub type CliSloppyImportsResolver =
SloppyImportsResolver<SloppyImportsCachedFs>; SloppyImportsResolver<SloppyImportsCachedFs>;
pub type CliDenoResolver = deno_resolver::DenoResolver< pub type CliDenoResolver = deno_resolver::DenoResolver<
CliDenoResolverFs, RealIsBuiltInNodeModuleChecker,
DenoFsNodeResolverEnv,
SloppyImportsCachedFs, SloppyImportsCachedFs,
CliSys,
>; >;
pub type CliNpmReqResolver = pub type CliNpmReqResolver =
deno_resolver::npm::NpmReqResolver<CliDenoResolverFs, DenoFsNodeResolverEnv>; deno_resolver::npm::NpmReqResolver<RealIsBuiltInNodeModuleChecker, CliSys>;
pub struct ModuleCodeStringSource { pub struct ModuleCodeStringSource {
pub code: ModuleSourceCode, pub code: ModuleSourceCode,
@ -59,53 +61,6 @@ pub struct ModuleCodeStringSource {
pub media_type: MediaType, pub media_type: MediaType,
} }
#[derive(Debug, Clone)]
pub struct CliDenoResolverFs(pub Arc<dyn FileSystem>);
impl deno_resolver::fs::DenoResolverFs for CliDenoResolverFs {
fn read_to_string_lossy(
&self,
path: &Path,
) -> std::io::Result<Cow<'static, str>> {
self
.0
.read_text_file_lossy_sync(path, None)
.map_err(|e| e.into_io_error())
}
fn realpath_sync(&self, path: &Path) -> std::io::Result<PathBuf> {
self.0.realpath_sync(path).map_err(|e| e.into_io_error())
}
fn exists_sync(&self, path: &Path) -> bool {
self.0.exists_sync(path)
}
fn is_dir_sync(&self, path: &Path) -> bool {
self.0.is_dir_sync(path)
}
fn read_dir_sync(
&self,
dir_path: &Path,
) -> std::io::Result<Vec<deno_resolver::fs::DirEntry>> {
self
.0
.read_dir_sync(dir_path)
.map(|entries| {
entries
.into_iter()
.map(|e| deno_resolver::fs::DirEntry {
name: e.name,
is_file: e.is_file,
is_directory: e.is_directory,
})
.collect::<Vec<_>>()
})
.map_err(|err| err.into_io_error())
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error("{media_type} files are not supported in npm packages: {specifier}")] #[error("{media_type} files are not supported in npm packages: {specifier}")]
pub struct NotSupportedKindInNpmError { pub struct NotSupportedKindInNpmError {
@ -440,7 +395,7 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> {
#[derive(Debug)] #[derive(Debug)]
pub struct SloppyImportsCachedFs { pub struct SloppyImportsCachedFs {
fs: Arc<dyn deno_fs::FileSystem>, sys: CliSys,
cache: Option< cache: Option<
DashMap< DashMap<
PathBuf, PathBuf,
@ -450,15 +405,18 @@ pub struct SloppyImportsCachedFs {
} }
impl SloppyImportsCachedFs { impl SloppyImportsCachedFs {
pub fn new(fs: Arc<dyn FileSystem>) -> Self { pub fn new(sys: CliSys) -> Self {
Self { Self {
fs, sys,
cache: Some(Default::default()), cache: Some(Default::default()),
} }
} }
pub fn new_without_stat_cache(fs: Arc<dyn FileSystem>) -> Self { pub fn new_without_stat_cache(fs: CliSys) -> Self {
Self { fs, cache: None } Self {
sys: fs,
cache: None,
}
} }
} }
@ -475,10 +433,10 @@ impl deno_resolver::sloppy_imports::SloppyImportResolverFs
} }
} }
let entry = self.fs.stat_sync(path).ok().and_then(|stat| { let entry = self.sys.fs_metadata(path).ok().and_then(|stat| {
if stat.is_file { if stat.file_type().is_file() {
Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::File) Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::File)
} else if stat.is_directory { } else if stat.file_type().is_dir() {
Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::Dir) Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::Dir)
} else { } else {
None None

View file

@ -446,7 +446,6 @@
}, },
"command": { "command": {
"type": "string", "type": "string",
"required": true,
"description": "The task to execute" "description": "The task to execute"
}, },
"dependencies": { "dependencies": {

View file

@ -37,7 +37,6 @@ use deno_core::futures::AsyncReadExt;
use deno_core::futures::AsyncSeekExt; use deno_core::futures::AsyncSeekExt;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_graph::source::RealFileSystem;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_npm::resolution::SerializedNpmResolutionSnapshot; use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage; use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
@ -71,7 +70,7 @@ use crate::args::UnstableConfig;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::emit::Emitter; use crate::emit::Emitter;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::npm::InnerCliNpmResolverRef; use crate::npm::InnerCliNpmResolverRef;
@ -91,6 +90,7 @@ use super::serialization::DenoCompileModuleData;
use super::serialization::DeserializedDataSection; use super::serialization::DeserializedDataSection;
use super::serialization::RemoteModulesStore; use super::serialization::RemoteModulesStore;
use super::serialization::RemoteModulesStoreBuilder; use super::serialization::RemoteModulesStoreBuilder;
use super::serialization::SourceMapStore;
use super::virtual_fs::output_vfs; use super::virtual_fs::output_vfs;
use super::virtual_fs::BuiltVfs; use super::virtual_fs::BuiltVfs;
use super::virtual_fs::FileBackedVfs; use super::virtual_fs::FileBackedVfs;
@ -98,6 +98,7 @@ use super::virtual_fs::VfsBuilder;
use super::virtual_fs::VfsFileSubDataKind; use super::virtual_fs::VfsFileSubDataKind;
use super::virtual_fs::VfsRoot; use super::virtual_fs::VfsRoot;
use super::virtual_fs::VirtualDirectory; use super::virtual_fs::VirtualDirectory;
use super::virtual_fs::VirtualDirectoryEntries;
use super::virtual_fs::WindowsSystemRootablePath; use super::virtual_fs::WindowsSystemRootablePath;
pub static DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME: &str = pub static DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME: &str =
@ -203,18 +204,25 @@ pub struct Metadata {
pub otel_config: OtelConfig, pub otel_config: OtelConfig,
} }
#[allow(clippy::too_many_arguments)]
fn write_binary_bytes( fn write_binary_bytes(
mut file_writer: File, mut file_writer: File,
original_bin: Vec<u8>, original_bin: Vec<u8>,
metadata: &Metadata, metadata: &Metadata,
npm_snapshot: Option<SerializedNpmResolutionSnapshot>, npm_snapshot: Option<SerializedNpmResolutionSnapshot>,
remote_modules: &RemoteModulesStoreBuilder, remote_modules: &RemoteModulesStoreBuilder,
source_map_store: &SourceMapStore,
vfs: &BuiltVfs, vfs: &BuiltVfs,
compile_flags: &CompileFlags, compile_flags: &CompileFlags,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let data_section_bytes = let data_section_bytes = serialize_binary_data_section(
serialize_binary_data_section(metadata, npm_snapshot, remote_modules, vfs) metadata,
.context("Serializing binary data section.")?; npm_snapshot,
remote_modules,
source_map_store,
vfs,
)
.context("Serializing binary data section.")?;
let target = compile_flags.resolve_target(); let target = compile_flags.resolve_target();
if target.contains("linux") { if target.contains("linux") {
@ -251,11 +259,11 @@ pub fn is_standalone_binary(exe_path: &Path) -> bool {
} }
pub struct StandaloneData { pub struct StandaloneData {
pub fs: Arc<dyn deno_fs::FileSystem>,
pub metadata: Metadata, pub metadata: Metadata,
pub modules: StandaloneModules, pub modules: StandaloneModules,
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>, pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
pub root_path: PathBuf, pub root_path: PathBuf,
pub source_maps: SourceMapStore,
pub vfs: Arc<FileBackedVfs>, pub vfs: Arc<FileBackedVfs>,
} }
@ -283,13 +291,12 @@ impl StandaloneModules {
pub fn read<'a>( pub fn read<'a>(
&'a self, &'a self,
specifier: &'a ModuleSpecifier, specifier: &'a ModuleSpecifier,
kind: VfsFileSubDataKind,
) -> Result<Option<DenoCompileModuleData<'a>>, AnyError> { ) -> Result<Option<DenoCompileModuleData<'a>>, AnyError> {
if specifier.scheme() == "file" { if specifier.scheme() == "file" {
let path = deno_path_util::url_to_file_path(specifier)?; let path = deno_path_util::url_to_file_path(specifier)?;
let bytes = match self.vfs.file_entry(&path) { let bytes = match self.vfs.file_entry(&path) {
Ok(entry) => self Ok(entry) => self.vfs.read_file_all(entry, kind)?,
.vfs
.read_file_all(entry, VfsFileSubDataKind::ModuleGraph)?,
Err(err) if err.kind() == ErrorKind::NotFound => { Err(err) if err.kind() == ErrorKind::NotFound => {
match RealFs.read_file_sync(&path, None) { match RealFs.read_file_sync(&path, None) {
Ok(bytes) => bytes, Ok(bytes) => bytes,
@ -307,7 +314,18 @@ impl StandaloneModules {
data: bytes, data: bytes,
})) }))
} else { } else {
self.remote_modules.read(specifier) self.remote_modules.read(specifier).map(|maybe_entry| {
maybe_entry.map(|entry| DenoCompileModuleData {
media_type: entry.media_type,
specifier: entry.specifier,
data: match kind {
VfsFileSubDataKind::Raw => entry.data,
VfsFileSubDataKind::ModuleGraph => {
entry.transpiled_data.unwrap_or(entry.data)
}
},
})
})
} }
} }
} }
@ -328,7 +346,8 @@ pub fn extract_standalone(
mut metadata, mut metadata,
npm_snapshot, npm_snapshot,
remote_modules, remote_modules,
mut vfs_dir, source_maps,
vfs_root_entries,
vfs_files_data, vfs_files_data,
} = match deserialize_binary_data_section(data)? { } = match deserialize_binary_data_section(data)? {
Some(data_section) => data_section, Some(data_section) => data_section,
@ -351,20 +370,18 @@ pub fn extract_standalone(
metadata.argv.push(arg.into_string().unwrap()); metadata.argv.push(arg.into_string().unwrap());
} }
let vfs = { let vfs = {
// align the name of the directory with the root dir
vfs_dir.name = root_path.file_name().unwrap().to_string_lossy().to_string();
let fs_root = VfsRoot { let fs_root = VfsRoot {
dir: vfs_dir, dir: VirtualDirectory {
// align the name of the directory with the root dir
name: root_path.file_name().unwrap().to_string_lossy().to_string(),
entries: vfs_root_entries,
},
root_path: root_path.clone(), root_path: root_path.clone(),
start_file_offset: 0, start_file_offset: 0,
}; };
Arc::new(FileBackedVfs::new(Cow::Borrowed(vfs_files_data), fs_root)) Arc::new(FileBackedVfs::new(Cow::Borrowed(vfs_files_data), fs_root))
}; };
let fs: Arc<dyn deno_fs::FileSystem> =
Arc::new(DenoCompileFileSystem::new(vfs.clone()));
Ok(Some(StandaloneData { Ok(Some(StandaloneData {
fs,
metadata, metadata,
modules: StandaloneModules { modules: StandaloneModules {
remote_modules, remote_modules,
@ -372,6 +389,7 @@ pub fn extract_standalone(
}, },
npm_snapshot, npm_snapshot,
root_path, root_path,
source_maps,
vfs, vfs,
})) }))
} }
@ -390,7 +408,7 @@ pub struct DenoCompileBinaryWriter<'a> {
cli_options: &'a CliOptions, cli_options: &'a CliOptions,
deno_dir: &'a DenoDir, deno_dir: &'a DenoDir,
emitter: &'a Emitter, emitter: &'a Emitter,
file_fetcher: &'a FileFetcher, file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider, http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a dyn CliNpmResolver, npm_resolver: &'a dyn CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver, workspace_resolver: &'a WorkspaceResolver,
@ -404,7 +422,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
cli_options: &'a CliOptions, cli_options: &'a CliOptions,
deno_dir: &'a DenoDir, deno_dir: &'a DenoDir,
emitter: &'a Emitter, emitter: &'a Emitter,
file_fetcher: &'a FileFetcher, file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider, http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a dyn CliNpmResolver, npm_resolver: &'a dyn CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver, workspace_resolver: &'a WorkspaceResolver,
@ -451,7 +469,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
) )
} }
} }
self.write_standalone_binary(options, original_binary).await self.write_standalone_binary(options, original_binary)
} }
async fn get_base_binary( async fn get_base_binary(
@ -554,7 +572,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
/// This functions creates a standalone deno binary by appending a bundle /// This functions creates a standalone deno binary by appending a bundle
/// and magic trailer to the currently executing binary. /// and magic trailer to the currently executing binary.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
async fn write_standalone_binary( fn write_standalone_binary(
&self, &self,
options: WriteBinOptions<'_>, options: WriteBinOptions<'_>,
original_bin: Vec<u8>, original_bin: Vec<u8>,
@ -598,71 +616,81 @@ impl<'a> DenoCompileBinaryWriter<'a> {
.with_context(|| format!("Including {}", path.display()))?; .with_context(|| format!("Including {}", path.display()))?;
} }
let mut remote_modules_store = RemoteModulesStoreBuilder::default(); let mut remote_modules_store = RemoteModulesStoreBuilder::default();
let mut code_cache_key_hasher = if self.cli_options.code_cache_enabled() { let mut source_maps = Vec::with_capacity(graph.specifiers_count());
Some(FastInsecureHasher::new_deno_versioned()) // todo(dsherret): transpile in parallel
} else {
None
};
for module in graph.modules() { for module in graph.modules() {
if module.specifier().scheme() == "data" { if module.specifier().scheme() == "data" {
continue; // don't store data urls as an entry as they're in the code continue; // don't store data urls as an entry as they're in the code
} }
if let Some(hasher) = &mut code_cache_key_hasher { let (maybe_original_source, maybe_transpiled, media_type) = match module {
if let Some(source) = module.source() {
hasher.write(module.specifier().as_str().as_bytes());
hasher.write(source.as_bytes());
}
}
let (maybe_source, media_type) = match module {
deno_graph::Module::Js(m) => { deno_graph::Module::Js(m) => {
let source = if m.media_type.is_emittable() { let original_bytes = m.source.as_bytes().to_vec();
let maybe_transpiled = if m.media_type.is_emittable() {
let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script( let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script(
&m.specifier, &m.specifier,
m.media_type, m.media_type,
m.is_script, m.is_script,
)?; )?;
let module_kind = ModuleKind::from_is_cjs(is_cjs); let module_kind = ModuleKind::from_is_cjs(is_cjs);
let source = self let (source, source_map) =
.emitter self.emitter.emit_parsed_source_for_deno_compile(
.emit_parsed_source(
&m.specifier, &m.specifier,
m.media_type, m.media_type,
module_kind, module_kind,
&m.source, &m.source,
) )?;
.await?; if source != m.source.as_ref() {
source.into_bytes() source_maps.push((&m.specifier, source_map));
Some(source.into_bytes())
} else {
None
}
} else { } else {
m.source.as_bytes().to_vec() None
}; };
(Some(source), m.media_type) (Some(original_bytes), maybe_transpiled, m.media_type)
} }
deno_graph::Module::Json(m) => { deno_graph::Module::Json(m) => {
(Some(m.source.as_bytes().to_vec()), m.media_type) (Some(m.source.as_bytes().to_vec()), None, m.media_type)
} }
deno_graph::Module::Wasm(m) => { deno_graph::Module::Wasm(m) => {
(Some(m.source.to_vec()), MediaType::Wasm) (Some(m.source.to_vec()), None, MediaType::Wasm)
} }
deno_graph::Module::Npm(_) deno_graph::Module::Npm(_)
| deno_graph::Module::Node(_) | deno_graph::Module::Node(_)
| deno_graph::Module::External(_) => (None, MediaType::Unknown), | deno_graph::Module::External(_) => (None, None, MediaType::Unknown),
}; };
if module.specifier().scheme() == "file" { if let Some(original_source) = maybe_original_source {
let file_path = deno_path_util::url_to_file_path(module.specifier())?; if module.specifier().scheme() == "file" {
vfs let file_path = deno_path_util::url_to_file_path(module.specifier())?;
.add_file_with_data( vfs
&file_path, .add_file_with_data(
match maybe_source { &file_path,
Some(source) => source, original_source,
None => RealFs.read_file_sync(&file_path, None)?.into_owned(), VfsFileSubDataKind::Raw,
}, )
VfsFileSubDataKind::ModuleGraph, .with_context(|| {
) format!("Failed adding '{}'", file_path.display())
.with_context(|| { })?;
format!("Failed adding '{}'", file_path.display()) if let Some(transpiled_source) = maybe_transpiled {
})?; vfs
} else if let Some(source) = maybe_source { .add_file_with_data(
remote_modules_store.add(module.specifier(), media_type, source); &file_path,
transpiled_source,
VfsFileSubDataKind::ModuleGraph,
)
.with_context(|| {
format!("Failed adding '{}'", file_path.display())
})?;
}
} else {
remote_modules_store.add(
module.specifier(),
media_type,
original_source,
maybe_transpiled,
);
}
} }
} }
remote_modules_store.add_redirects(&graph.redirects); remote_modules_store.add_redirects(&graph.redirects);
@ -695,6 +723,28 @@ impl<'a> DenoCompileBinaryWriter<'a> {
None => StandaloneRelativeFileBaseUrl::WindowsSystemRoot, None => StandaloneRelativeFileBaseUrl::WindowsSystemRoot,
}; };
let code_cache_key = if self.cli_options.code_cache_enabled() {
let mut hasher = FastInsecureHasher::new_deno_versioned();
for module in graph.modules() {
if let Some(source) = module.source() {
hasher
.write(root_dir_url.specifier_key(module.specifier()).as_bytes());
hasher.write(source.as_bytes());
}
}
Some(hasher.finish())
} else {
None
};
let mut source_map_store = SourceMapStore::with_capacity(source_maps.len());
for (specifier, source_map) in source_maps {
source_map_store.add(
Cow::Owned(root_dir_url.specifier_key(specifier).into_owned()),
Cow::Owned(source_map.into_bytes()),
);
}
let node_modules = match self.npm_resolver.as_inner() { let node_modules = match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(_) => { InnerCliNpmResolverRef::Managed(_) => {
npm_snapshot.as_ref().map(|_| NodeModules::Managed { npm_snapshot.as_ref().map(|_| NodeModules::Managed {
@ -742,7 +792,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let metadata = Metadata { let metadata = Metadata {
argv: compile_flags.args.clone(), argv: compile_flags.args.clone(),
seed: self.cli_options.seed(), seed: self.cli_options.seed(),
code_cache_key: code_cache_key_hasher.map(|h| h.finish()), code_cache_key,
location: self.cli_options.location_flag().clone(), location: self.cli_options.location_flag().clone(),
permissions: self.cli_options.permission_flags().clone(), permissions: self.cli_options.permission_flags().clone(),
v8_flags: self.cli_options.v8_flags().clone(), v8_flags: self.cli_options.v8_flags().clone(),
@ -809,6 +859,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
&metadata, &metadata,
npm_snapshot.map(|s| s.into_serialized()), npm_snapshot.map(|s| s.into_serialized()),
&remote_modules_store, &remote_modules_store,
&source_map_store,
&vfs, &vfs,
compile_flags, compile_flags,
) )
@ -903,10 +954,10 @@ impl<'a> DenoCompileBinaryWriter<'a> {
root_dir.name = DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME.to_string(); root_dir.name = DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME.to_string();
let mut new_entries = Vec::with_capacity(root_dir.entries.len()); let mut new_entries = Vec::with_capacity(root_dir.entries.len());
let mut localhost_entries = IndexMap::new(); let mut localhost_entries = IndexMap::new();
for entry in std::mem::take(&mut root_dir.entries) { for entry in root_dir.entries.take_inner() {
match entry { match entry {
VfsEntry::Dir(dir) => { VfsEntry::Dir(mut dir) => {
for entry in dir.entries { for entry in dir.entries.take_inner() {
log::debug!("Flattening {} into node_modules", entry.name()); log::debug!("Flattening {} into node_modules", entry.name());
if let Some(existing) = if let Some(existing) =
localhost_entries.insert(entry.name().to_string(), entry) localhost_entries.insert(entry.name().to_string(), entry)
@ -925,11 +976,11 @@ impl<'a> DenoCompileBinaryWriter<'a> {
} }
new_entries.push(VfsEntry::Dir(VirtualDirectory { new_entries.push(VfsEntry::Dir(VirtualDirectory {
name: "localhost".to_string(), name: "localhost".to_string(),
entries: localhost_entries.into_iter().map(|(_, v)| v).collect(), entries: VirtualDirectoryEntries::new(
localhost_entries.into_iter().map(|(_, v)| v).collect(),
),
})); }));
// needs to be sorted by name root_dir.entries = VirtualDirectoryEntries::new(new_entries);
new_entries.sort_by(|a, b| a.name().cmp(b.name()));
root_dir.entries = new_entries;
// it's better to not expose the user's cache directory, so take it out // it's better to not expose the user's cache directory, so take it out
// of there // of there
@ -937,10 +988,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let parent_dir = vfs.get_dir_mut(parent).unwrap(); let parent_dir = vfs.get_dir_mut(parent).unwrap();
let index = parent_dir let index = parent_dir
.entries .entries
.iter() .binary_search(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME)
.position(|entry| {
entry.name() == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME
})
.unwrap(); .unwrap();
let npm_global_cache_dir_entry = parent_dir.entries.remove(index); let npm_global_cache_dir_entry = parent_dir.entries.remove(index);
@ -950,11 +998,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
Cow::Borrowed(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME); Cow::Borrowed(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME);
for ancestor in parent.ancestors() { for ancestor in parent.ancestors() {
let dir = vfs.get_dir_mut(ancestor).unwrap(); let dir = vfs.get_dir_mut(ancestor).unwrap();
if let Some(index) = dir if let Ok(index) = dir.entries.binary_search(&last_name) {
.entries
.iter()
.position(|entry| entry.name() == last_name)
{
dir.entries.remove(index); dir.entries.remove(index);
} }
last_name = Cow::Owned(dir.name.clone()); last_name = Cow::Owned(dir.name.clone());
@ -965,7 +1009,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
// now build the vfs and add the global cache dir entry there // now build the vfs and add the global cache dir entry there
let mut built_vfs = vfs.build(); let mut built_vfs = vfs.build();
built_vfs.root.insert_entry(npm_global_cache_dir_entry); built_vfs.entries.insert(npm_global_cache_dir_entry);
built_vfs built_vfs
} }
InnerCliNpmResolverRef::Byonm(_) => vfs.build(), InnerCliNpmResolverRef::Byonm(_) => vfs.build(),

View file

@ -15,11 +15,11 @@ use deno_core::anyhow::bail;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::unsync::sync::AtomicFlag; use deno_core::unsync::sync::AtomicFlag;
use deno_path_util::get_atomic_path;
use deno_runtime::code_cache::CodeCache; use deno_runtime::code_cache::CodeCache;
use deno_runtime::code_cache::CodeCacheType; use deno_runtime::code_cache::CodeCacheType;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::util::path::get_atomic_file_path;
use crate::worker::CliCodeCache; use crate::worker::CliCodeCache;
enum CodeCacheStrategy { enum CodeCacheStrategy {
@ -189,7 +189,8 @@ impl FirstRunCodeCacheStrategy {
cache_data: &HashMap<CodeCacheKey, DenoCompileCodeCacheEntry>, cache_data: &HashMap<CodeCacheKey, DenoCompileCodeCacheEntry>,
) { ) {
let count = cache_data.len(); let count = cache_data.len();
let temp_file = get_atomic_file_path(&self.file_path); let temp_file =
get_atomic_path(&sys_traits::impls::RealSys, &self.file_path);
match serialize(&temp_file, self.cache_key, cache_data) { match serialize(&temp_file, self.cache_key, cache_data) {
Ok(()) => { Ok(()) => {
if let Err(err) = std::fs::rename(&temp_file, &self.file_path) { if let Err(err) = std::fs::rename(&temp_file, &self.file_path) {

View file

@ -1,9 +1,13 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow;
use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use std::time::SystemTime;
use deno_runtime::deno_fs::AccessCheckCb; use deno_runtime::deno_fs::AccessCheckCb;
use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FileSystem;
@ -15,8 +19,16 @@ use deno_runtime::deno_io::fs::File;
use deno_runtime::deno_io::fs::FsError; use deno_runtime::deno_io::fs::FsError;
use deno_runtime::deno_io::fs::FsResult; use deno_runtime::deno_io::fs::FsResult;
use deno_runtime::deno_io::fs::FsStat; use deno_runtime::deno_io::fs::FsStat;
use sys_traits::boxed::BoxedFsDirEntry;
use sys_traits::boxed::BoxedFsMetadataValue;
use sys_traits::boxed::FsMetadataBoxed;
use sys_traits::boxed::FsReadDirBoxed;
use sys_traits::FsMetadata;
use super::virtual_fs::FileBackedVfs; use super::virtual_fs::FileBackedVfs;
use super::virtual_fs::FileBackedVfsDirEntry;
use super::virtual_fs::FileBackedVfsFile;
use super::virtual_fs::FileBackedVfsMetadata;
use super::virtual_fs::VfsFileSubDataKind; use super::virtual_fs::VfsFileSubDataKind;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -82,7 +94,7 @@ impl FileSystem for DenoCompileFileSystem {
access_check: Option<AccessCheckCb>, access_check: Option<AccessCheckCb>,
) -> FsResult<Rc<dyn File>> { ) -> FsResult<Rc<dyn File>> {
if self.0.is_path_within(path) { if self.0.is_path_within(path) {
Ok(self.0.open_file(path)?) Ok(Rc::new(self.0.open_file(path)?))
} else { } else {
RealFs.open_sync(path, options, access_check) RealFs.open_sync(path, options, access_check)
} }
@ -94,7 +106,7 @@ impl FileSystem for DenoCompileFileSystem {
access_check: Option<AccessCheckCb<'a>>, access_check: Option<AccessCheckCb<'a>>,
) -> FsResult<Rc<dyn File>> { ) -> FsResult<Rc<dyn File>> {
if self.0.is_path_within(&path) { if self.0.is_path_within(&path) {
Ok(self.0.open_file(&path)?) Ok(Rc::new(self.0.open_file(&path)?))
} else { } else {
RealFs.open_async(path, options, access_check).await RealFs.open_async(path, options, access_check).await
} }
@ -214,14 +226,14 @@ impl FileSystem for DenoCompileFileSystem {
fn stat_sync(&self, path: &Path) -> FsResult<FsStat> { fn stat_sync(&self, path: &Path) -> FsResult<FsStat> {
if self.0.is_path_within(path) { if self.0.is_path_within(path) {
Ok(self.0.stat(path)?) Ok(self.0.stat(path)?.as_fs_stat())
} else { } else {
RealFs.stat_sync(path) RealFs.stat_sync(path)
} }
} }
async fn stat_async(&self, path: PathBuf) -> FsResult<FsStat> { async fn stat_async(&self, path: PathBuf) -> FsResult<FsStat> {
if self.0.is_path_within(&path) { if self.0.is_path_within(&path) {
Ok(self.0.stat(&path)?) Ok(self.0.stat(&path)?.as_fs_stat())
} else { } else {
RealFs.stat_async(path).await RealFs.stat_async(path).await
} }
@ -229,14 +241,14 @@ impl FileSystem for DenoCompileFileSystem {
fn lstat_sync(&self, path: &Path) -> FsResult<FsStat> { fn lstat_sync(&self, path: &Path) -> FsResult<FsStat> {
if self.0.is_path_within(path) { if self.0.is_path_within(path) {
Ok(self.0.lstat(path)?) Ok(self.0.lstat(path)?.as_fs_stat())
} else { } else {
RealFs.lstat_sync(path) RealFs.lstat_sync(path)
} }
} }
async fn lstat_async(&self, path: PathBuf) -> FsResult<FsStat> { async fn lstat_async(&self, path: PathBuf) -> FsResult<FsStat> {
if self.0.is_path_within(&path) { if self.0.is_path_within(&path) {
Ok(self.0.lstat(&path)?) Ok(self.0.lstat(&path)?.as_fs_stat())
} else { } else {
RealFs.lstat_async(path).await RealFs.lstat_async(path).await
} }
@ -397,3 +409,428 @@ impl FileSystem for DenoCompileFileSystem {
.await .await
} }
} }
impl sys_traits::BaseFsHardLink for DenoCompileFileSystem {
#[inline]
fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
self.link_sync(src, dst).map_err(|err| err.into_io_error())
}
}
impl sys_traits::BaseFsRead for DenoCompileFileSystem {
#[inline]
fn base_fs_read(&self, path: &Path) -> std::io::Result<Cow<'static, [u8]>> {
self
.read_file_sync(path, None)
.map_err(|err| err.into_io_error())
}
}
impl sys_traits::FsMetadataValue for FileBackedVfsMetadata {
fn file_type(&self) -> sys_traits::FileType {
self.file_type
}
fn len(&self) -> u64 {
self.len
}
fn accessed(&self) -> std::io::Result<SystemTime> {
Err(not_supported("accessed time"))
}
fn created(&self) -> std::io::Result<SystemTime> {
Err(not_supported("created time"))
}
fn changed(&self) -> std::io::Result<SystemTime> {
Err(not_supported("changed time"))
}
fn modified(&self) -> std::io::Result<SystemTime> {
Err(not_supported("modified time"))
}
fn dev(&self) -> std::io::Result<u64> {
Ok(0)
}
fn ino(&self) -> std::io::Result<u64> {
Ok(0)
}
fn mode(&self) -> std::io::Result<u32> {
Ok(0)
}
fn nlink(&self) -> std::io::Result<u64> {
Ok(0)
}
fn uid(&self) -> std::io::Result<u32> {
Ok(0)
}
fn gid(&self) -> std::io::Result<u32> {
Ok(0)
}
fn rdev(&self) -> std::io::Result<u64> {
Ok(0)
}
fn blksize(&self) -> std::io::Result<u64> {
Ok(0)
}
fn blocks(&self) -> std::io::Result<u64> {
Ok(0)
}
fn is_block_device(&self) -> std::io::Result<bool> {
Ok(false)
}
fn is_char_device(&self) -> std::io::Result<bool> {
Ok(false)
}
fn is_fifo(&self) -> std::io::Result<bool> {
Ok(false)
}
fn is_socket(&self) -> std::io::Result<bool> {
Ok(false)
}
fn file_attributes(&self) -> std::io::Result<u32> {
Ok(0)
}
}
fn not_supported(name: &str) -> std::io::Error {
std::io::Error::new(
ErrorKind::Unsupported,
format!(
"{} is not supported for an embedded deno compile file",
name
),
)
}
impl sys_traits::FsDirEntry for FileBackedVfsDirEntry {
type Metadata = BoxedFsMetadataValue;
fn file_name(&self) -> Cow<std::ffi::OsStr> {
Cow::Borrowed(self.metadata.name.as_ref())
}
fn file_type(&self) -> std::io::Result<sys_traits::FileType> {
Ok(self.metadata.file_type)
}
fn metadata(&self) -> std::io::Result<Self::Metadata> {
Ok(BoxedFsMetadataValue(Box::new(self.metadata.clone())))
}
fn path(&self) -> Cow<Path> {
Cow::Owned(self.parent_path.join(&self.metadata.name))
}
}
impl sys_traits::BaseFsReadDir for DenoCompileFileSystem {
type ReadDirEntry = BoxedFsDirEntry;
fn base_fs_read_dir(
&self,
path: &Path,
) -> std::io::Result<
Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>> + '_>,
> {
if self.0.is_path_within(path) {
let entries = self.0.read_dir_with_metadata(path)?;
Ok(Box::new(
entries.map(|entry| Ok(BoxedFsDirEntry::new(entry))),
))
} else {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.fs_read_dir_boxed(path)
}
}
}
impl sys_traits::BaseFsCanonicalize for DenoCompileFileSystem {
#[inline]
fn base_fs_canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> {
self.realpath_sync(path).map_err(|err| err.into_io_error())
}
}
impl sys_traits::BaseFsMetadata for DenoCompileFileSystem {
type Metadata = BoxedFsMetadataValue;
#[inline]
fn base_fs_metadata(&self, path: &Path) -> std::io::Result<Self::Metadata> {
if self.0.is_path_within(path) {
Ok(BoxedFsMetadataValue::new(self.0.stat(path)?))
} else {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.fs_metadata_boxed(path)
}
}
#[inline]
fn base_fs_symlink_metadata(
&self,
path: &Path,
) -> std::io::Result<Self::Metadata> {
if self.0.is_path_within(path) {
Ok(BoxedFsMetadataValue::new(self.0.lstat(path)?))
} else {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.fs_symlink_metadata_boxed(path)
}
}
}
impl sys_traits::BaseFsCreateDir for DenoCompileFileSystem {
#[inline]
fn base_fs_create_dir(
&self,
path: &Path,
options: &sys_traits::CreateDirOptions,
) -> std::io::Result<()> {
self
.mkdir_sync(path, options.recursive, options.mode)
.map_err(|err| err.into_io_error())
}
}
impl sys_traits::BaseFsRemoveFile for DenoCompileFileSystem {
#[inline]
fn base_fs_remove_file(&self, path: &Path) -> std::io::Result<()> {
self
.remove_sync(path, false)
.map_err(|err| err.into_io_error())
}
}
impl sys_traits::BaseFsRename for DenoCompileFileSystem {
#[inline]
fn base_fs_rename(&self, from: &Path, to: &Path) -> std::io::Result<()> {
self
.rename_sync(from, to)
.map_err(|err| err.into_io_error())
}
}
pub enum FsFileAdapter {
Real(sys_traits::impls::RealFsFile),
Vfs(FileBackedVfsFile),
}
impl sys_traits::FsFile for FsFileAdapter {}
impl sys_traits::FsFileAsRaw for FsFileAdapter {
#[cfg(windows)]
fn fs_file_as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
match self {
Self::Real(file) => file.fs_file_as_raw_handle(),
Self::Vfs(_) => None,
}
}
#[cfg(unix)]
fn fs_file_as_raw_fd(&self) -> Option<std::os::fd::RawFd> {
match self {
Self::Real(file) => file.fs_file_as_raw_fd(),
Self::Vfs(_) => None,
}
}
}
impl sys_traits::FsFileSyncData for FsFileAdapter {
fn fs_file_sync_data(&mut self) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_sync_data(),
Self::Vfs(_) => Ok(()),
}
}
}
impl sys_traits::FsFileSyncAll for FsFileAdapter {
fn fs_file_sync_all(&mut self) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_sync_all(),
Self::Vfs(_) => Ok(()),
}
}
}
impl sys_traits::FsFileSetPermissions for FsFileAdapter {
#[inline]
fn fs_file_set_permissions(&mut self, mode: u32) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_set_permissions(mode),
Self::Vfs(_) => Ok(()),
}
}
}
impl std::io::Read for FsFileAdapter {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
Self::Real(file) => file.read(buf),
Self::Vfs(file) => file.read_to_buf(buf),
}
}
}
impl std::io::Seek for FsFileAdapter {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
match self {
Self::Real(file) => file.seek(pos),
Self::Vfs(file) => file.seek(pos),
}
}
}
impl std::io::Write for FsFileAdapter {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match self {
Self::Real(file) => file.write(buf),
Self::Vfs(_) => Err(not_supported("writing files")),
}
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
match self {
Self::Real(file) => file.flush(),
Self::Vfs(_) => Err(not_supported("writing files")),
}
}
}
impl sys_traits::FsFileSetLen for FsFileAdapter {
#[inline]
fn fs_file_set_len(&mut self, len: u64) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_set_len(len),
Self::Vfs(_) => Err(not_supported("setting file length")),
}
}
}
impl sys_traits::FsFileSetTimes for FsFileAdapter {
fn fs_file_set_times(
&mut self,
times: sys_traits::FsFileTimes,
) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_set_times(times),
Self::Vfs(_) => Err(not_supported("setting file times")),
}
}
}
impl sys_traits::FsFileLock for FsFileAdapter {
fn fs_file_lock(
&mut self,
mode: sys_traits::FsFileLockMode,
) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_lock(mode),
Self::Vfs(_) => Err(not_supported("locking files")),
}
}
fn fs_file_try_lock(
&mut self,
mode: sys_traits::FsFileLockMode,
) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_try_lock(mode),
Self::Vfs(_) => Err(not_supported("locking files")),
}
}
fn fs_file_unlock(&mut self) -> std::io::Result<()> {
match self {
Self::Real(file) => file.fs_file_unlock(),
Self::Vfs(_) => Err(not_supported("unlocking files")),
}
}
}
impl sys_traits::FsFileIsTerminal for FsFileAdapter {
#[inline]
fn fs_file_is_terminal(&self) -> bool {
match self {
Self::Real(file) => file.fs_file_is_terminal(),
Self::Vfs(_) => false,
}
}
}
impl sys_traits::BaseFsOpen for DenoCompileFileSystem {
type File = FsFileAdapter;
fn base_fs_open(
&self,
path: &Path,
options: &sys_traits::OpenOptions,
) -> std::io::Result<Self::File> {
if self.0.is_path_within(path) {
Ok(FsFileAdapter::Vfs(self.0.open_file(path)?))
} else {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
Ok(FsFileAdapter::Real(
sys_traits::impls::RealSys.base_fs_open(path, options)?,
))
}
}
}
impl sys_traits::SystemRandom for DenoCompileFileSystem {
#[inline]
fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.sys_random(buf)
}
}
impl sys_traits::SystemTimeNow for DenoCompileFileSystem {
#[inline]
fn sys_time_now(&self) -> SystemTime {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.sys_time_now()
}
}
impl sys_traits::ThreadSleep for DenoCompileFileSystem {
#[inline]
fn thread_sleep(&self, dur: Duration) {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.thread_sleep(dur)
}
}
impl sys_traits::EnvCurrentDir for DenoCompileFileSystem {
fn env_current_dir(&self) -> std::io::Result<PathBuf> {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.env_current_dir()
}
}
impl sys_traits::BaseEnvVar for DenoCompileFileSystem {
fn base_env_var_os(
&self,
key: &std::ffi::OsStr,
) -> Option<std::ffi::OsString> {
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
sys_traits::impls::RealSys.base_env_var_os(key)
}
}

View file

@ -9,6 +9,7 @@ use binary::StandaloneData;
use binary::StandaloneModules; use binary::StandaloneModules;
use code_cache::DenoCompileCodeCache; use code_cache::DenoCompileCodeCache;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::npm::NpmCacheDir; use deno_cache_dir::npm::NpmCacheDir;
use deno_config::workspace::MappedResolution; use deno_config::workspace::MappedResolution;
use deno_config::workspace::MappedResolutionError; use deno_config::workspace::MappedResolutionError;
@ -35,10 +36,11 @@ use deno_package_json::PackageJsonDepValue;
use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_node::PackageJsonResolver; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::rustls::RootCertStore;
@ -54,6 +56,7 @@ use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use serialization::DenoCompileModuleSource; use serialization::DenoCompileModuleSource;
use serialization::SourceMapStore;
use std::borrow::Cow; use std::borrow::Cow;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -64,18 +67,17 @@ use crate::args::create_default_npmrc;
use crate::args::get_root_cert_store; use crate::args::get_root_cert_store;
use crate::args::npm_pkg_req_ref_to_binary_command; use crate::args::npm_pkg_req_ref_to_binary_command;
use crate::args::CaData; use crate::args::CaData;
use crate::args::CacheSetting;
use crate::args::NpmInstallDepsProvider; use crate::args::NpmInstallDepsProvider;
use crate::args::StorageKeyResolver; use crate::args::StorageKeyResolver;
use crate::cache::Caches; use crate::cache::Caches;
use crate::cache::DenoCacheEnvFsAdapter;
use crate::cache::DenoDirProvider; use crate::cache::DenoDirProvider;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::RealDenoCacheEnv;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::node::CliCjsCodeAnalyzer; use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver; use crate::npm::create_cli_npm_resolver;
use crate::npm::create_in_npm_pkg_checker; use crate::npm::create_in_npm_pkg_checker;
use crate::npm::CliByonmNpmResolverCreateOptions; use crate::npm::CliByonmNpmResolverCreateOptions;
@ -86,9 +88,9 @@ use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption; use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions; use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::resolver::CliDenoResolverFs;
use crate::resolver::CliNpmReqResolver; use crate::resolver::CliNpmReqResolver;
use crate::resolver::NpmModuleLoader; use crate::resolver::NpmModuleLoader;
use crate::sys::CliSys;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
use crate::util::text_encoding::from_utf8_lossy_cow; use crate::util::text_encoding::from_utf8_lossy_cow;
@ -105,12 +107,12 @@ mod file_system;
mod serialization; mod serialization;
mod virtual_fs; mod virtual_fs;
pub use self::file_system::DenoCompileFileSystem;
pub use binary::extract_standalone; pub use binary::extract_standalone;
pub use binary::is_standalone_binary; pub use binary::is_standalone_binary;
pub use binary::DenoCompileBinaryWriter; pub use binary::DenoCompileBinaryWriter;
use self::binary::Metadata; use self::binary::Metadata;
use self::file_system::DenoCompileFileSystem;
struct SharedModuleLoaderState { struct SharedModuleLoaderState {
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
@ -118,10 +120,11 @@ struct SharedModuleLoaderState {
fs: Arc<dyn deno_fs::FileSystem>, fs: Arc<dyn deno_fs::FileSystem>,
modules: StandaloneModules, modules: StandaloneModules,
node_code_translator: Arc<CliNodeCodeTranslator>, node_code_translator: Arc<CliNodeCodeTranslator>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_module_loader: Arc<NpmModuleLoader>, npm_module_loader: Arc<NpmModuleLoader>,
npm_req_resolver: Arc<CliNpmReqResolver>, npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
source_maps: SourceMapStore,
vfs: Arc<FileBackedVfs>, vfs: Arc<FileBackedVfs>,
workspace_resolver: WorkspaceResolver, workspace_resolver: WorkspaceResolver,
} }
@ -396,7 +399,11 @@ impl ModuleLoader for EmbeddedModuleLoader {
); );
} }
match self.shared.modules.read(original_specifier) { match self
.shared
.modules
.read(original_specifier, VfsFileSubDataKind::ModuleGraph)
{
Ok(Some(module)) => { Ok(Some(module)) => {
let media_type = module.media_type; let media_type = module.media_type;
let (module_specifier, module_type, module_source) = let (module_specifier, module_type, module_source) =
@ -495,6 +502,45 @@ impl ModuleLoader for EmbeddedModuleLoader {
} }
std::future::ready(()).boxed_local() std::future::ready(()).boxed_local()
} }
fn get_source_map(&self, file_name: &str) -> Option<Cow<[u8]>> {
if file_name.starts_with("file:///") {
let url =
deno_path_util::url_from_directory_path(self.shared.vfs.root()).ok()?;
let file_url = ModuleSpecifier::parse(file_name).ok()?;
let relative_path = url.make_relative(&file_url)?;
self.shared.source_maps.get(&relative_path)
} else {
self.shared.source_maps.get(file_name)
}
.map(Cow::Borrowed)
}
fn get_source_mapped_source_line(
&self,
file_name: &str,
line_number: usize,
) -> Option<String> {
let specifier = ModuleSpecifier::parse(file_name).ok()?;
let data = self
.shared
.modules
.read(&specifier, VfsFileSubDataKind::Raw)
.ok()??;
let source = String::from_utf8_lossy(&data.data);
// Do NOT use .lines(): it skips the terminating empty line.
// (due to internally using_terminator() instead of .split())
let lines: Vec<&str> = source.split('\n').collect();
if line_number >= lines.len() {
Some(format!(
"{} Couldn't format source line: Line {} is out of bounds (source may have changed at runtime)",
crate::colors::yellow("Warning"), line_number + 1,
))
} else {
Some(lines[line_number].to_string())
}
}
} }
impl NodeRequireLoader for EmbeddedModuleLoader { impl NodeRequireLoader for EmbeddedModuleLoader {
@ -583,16 +629,20 @@ impl RootCertStoreProvider for StandaloneRootCertStoreProvider {
} }
} }
pub async fn run(data: StandaloneData) -> Result<i32, AnyError> { pub async fn run(
fs: Arc<dyn FileSystem>,
sys: CliSys,
data: StandaloneData,
) -> Result<i32, AnyError> {
let StandaloneData { let StandaloneData {
fs,
metadata, metadata,
modules, modules,
npm_snapshot, npm_snapshot,
root_path, root_path,
source_maps,
vfs, vfs,
} = data; } = data;
let deno_dir_provider = Arc::new(DenoDirProvider::new(None)); let deno_dir_provider = Arc::new(DenoDirProvider::new(sys.clone(), None));
let root_cert_store_provider = Arc::new(StandaloneRootCertStoreProvider { let root_cert_store_provider = Arc::new(StandaloneRootCertStoreProvider {
ca_stores: metadata.ca_stores, ca_stores: metadata.ca_stores,
ca_data: metadata.ca_data.map(CaData::Bytes), ca_data: metadata.ca_data.map(CaData::Bytes),
@ -610,9 +660,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap(); let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap();
let npm_global_cache_dir = root_path.join(".deno_compile_node_modules"); let npm_global_cache_dir = root_path.join(".deno_compile_node_modules");
let cache_setting = CacheSetting::Only; let cache_setting = CacheSetting::Only;
let pkg_json_resolver = Arc::new(PackageJsonResolver::new( let pkg_json_resolver = Arc::new(CliPackageJsonResolver::new(sys.clone()));
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
));
let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules { let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules {
Some(binary::NodeModules::Managed { node_modules_dir }) => { Some(binary::NodeModules::Managed { node_modules_dir }) => {
// create an npmrc that uses the fake npm_registry_url to resolve packages // create an npmrc that uses the fake npm_registry_url to resolve packages
@ -625,7 +673,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
registry_configs: Default::default(), registry_configs: Default::default(),
}); });
let npm_cache_dir = Arc::new(NpmCacheDir::new( let npm_cache_dir = Arc::new(NpmCacheDir::new(
&DenoCacheEnvFsAdapter(fs.as_ref()), &sys,
npm_global_cache_dir, npm_global_cache_dir,
npmrc.get_all_known_registries_urls(), npmrc.get_all_known_registries_urls(),
)); ));
@ -646,17 +694,17 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
snapshot, snapshot,
)), )),
maybe_lockfile: None, maybe_lockfile: None,
fs: fs.clone(),
http_client_provider: http_client_provider.clone(), http_client_provider: http_client_provider.clone(),
npm_cache_dir, npm_cache_dir,
cache_setting,
text_only_progress_bar: progress_bar,
maybe_node_modules_path,
npm_system_info: Default::default(),
npm_install_deps_provider: Arc::new( npm_install_deps_provider: Arc::new(
// this is only used for installing packages, which isn't necessary with deno compile // this is only used for installing packages, which isn't necessary with deno compile
NpmInstallDepsProvider::empty(), NpmInstallDepsProvider::empty(),
), ),
sys: sys.clone(),
text_only_progress_bar: progress_bar,
cache_setting,
maybe_node_modules_path,
npm_system_info: Default::default(),
npmrc, npmrc,
lifecycle_scripts: Default::default(), lifecycle_scripts: Default::default(),
}, },
@ -673,7 +721,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Byonm); create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Byonm);
let npm_resolver = create_cli_npm_resolver( let npm_resolver = create_cli_npm_resolver(
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
fs: CliDenoResolverFs(fs.clone()), sys: sys.clone(),
pkg_json_resolver: pkg_json_resolver.clone(), pkg_json_resolver: pkg_json_resolver.clone(),
root_node_modules_dir, root_node_modules_dir,
}), }),
@ -686,7 +734,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
// so no need to create actual `.npmrc` configuration. // so no need to create actual `.npmrc` configuration.
let npmrc = create_default_npmrc(); let npmrc = create_default_npmrc();
let npm_cache_dir = Arc::new(NpmCacheDir::new( let npm_cache_dir = Arc::new(NpmCacheDir::new(
&DenoCacheEnvFsAdapter(fs.as_ref()), &sys,
npm_global_cache_dir, npm_global_cache_dir,
npmrc.get_all_known_registries_urls(), npmrc.get_all_known_registries_urls(),
)); ));
@ -701,18 +749,18 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed( create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed(
CliManagedNpmResolverCreateOptions { CliManagedNpmResolverCreateOptions {
snapshot: CliNpmResolverManagedSnapshotOption::Specified(None), snapshot: CliNpmResolverManagedSnapshotOption::Specified(None),
maybe_lockfile: None,
fs: fs.clone(),
http_client_provider: http_client_provider.clone(), http_client_provider: http_client_provider.clone(),
npm_cache_dir,
cache_setting,
text_only_progress_bar: progress_bar,
maybe_node_modules_path: None,
npm_system_info: Default::default(),
npm_install_deps_provider: Arc::new( npm_install_deps_provider: Arc::new(
// this is only used for installing packages, which isn't necessary with deno compile // this is only used for installing packages, which isn't necessary with deno compile
NpmInstallDepsProvider::empty(), NpmInstallDepsProvider::empty(),
), ),
sys: sys.clone(),
cache_setting,
text_only_progress_bar: progress_bar,
npm_cache_dir,
maybe_lockfile: None,
maybe_node_modules_path: None,
npm_system_info: Default::default(),
npmrc: create_default_npmrc(), npmrc: create_default_npmrc(),
lifecycle_scripts: Default::default(), lifecycle_scripts: Default::default(),
}, },
@ -724,10 +772,11 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
let has_node_modules_dir = npm_resolver.root_node_modules_path().is_some(); let has_node_modules_dir = npm_resolver.root_node_modules_path().is_some();
let node_resolver = Arc::new(NodeResolver::new( let node_resolver = Arc::new(NodeResolver::new(
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
in_npm_pkg_checker.clone(), in_npm_pkg_checker.clone(),
RealIsBuiltInNodeModuleChecker,
npm_resolver.clone().into_npm_pkg_folder_resolver(), npm_resolver.clone().into_npm_pkg_folder_resolver(),
pkg_json_resolver.clone(), pkg_json_resolver.clone(),
sys.clone(),
)); ));
let cjs_tracker = Arc::new(CjsTracker::new( let cjs_tracker = Arc::new(CjsTracker::new(
in_npm_pkg_checker.clone(), in_npm_pkg_checker.clone(),
@ -745,7 +794,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
let npm_req_resolver = let npm_req_resolver =
Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions {
byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(),
fs: CliDenoResolverFs(fs.clone()), sys: sys.clone(),
in_npm_pkg_checker: in_npm_pkg_checker.clone(), in_npm_pkg_checker: in_npm_pkg_checker.clone(),
node_resolver: node_resolver.clone(), node_resolver: node_resolver.clone(),
npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(),
@ -758,11 +807,11 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
); );
let node_code_translator = Arc::new(NodeCodeTranslator::new( let node_code_translator = Arc::new(NodeCodeTranslator::new(
cjs_esm_code_analyzer, cjs_esm_code_analyzer,
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
in_npm_pkg_checker, in_npm_pkg_checker,
node_resolver.clone(), node_resolver.clone(),
npm_resolver.clone().into_npm_pkg_folder_resolver(), npm_resolver.clone().into_npm_pkg_folder_resolver(),
pkg_json_resolver.clone(), pkg_json_resolver.clone(),
sys.clone(),
)); ));
let workspace_resolver = { let workspace_resolver = {
let import_map = match metadata.workspace_resolver.import_map { let import_map = match metadata.workspace_resolver.import_map {
@ -841,6 +890,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
)), )),
npm_resolver: npm_resolver.clone(), npm_resolver: npm_resolver.clone(),
npm_req_resolver, npm_req_resolver,
source_maps,
vfs, vfs,
workspace_resolver, workspace_resolver,
}), }),
@ -864,7 +914,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
} }
let desc_parser = let desc_parser =
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone())); Arc::new(RuntimePermissionDescriptorParser::new(sys.clone()));
let permissions = let permissions =
Permissions::from_options(desc_parser.as_ref(), &permissions)?; Permissions::from_options(desc_parser.as_ref(), &permissions)?;
PermissionsContainer::new(desc_parser, permissions) PermissionsContainer::new(desc_parser, permissions)
@ -894,6 +944,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
root_cert_store_provider, root_cert_store_provider,
permissions, permissions,
StorageKeyResolver::empty(), StorageKeyResolver::empty(),
sys,
crate::args::DenoSubcommand::Run(Default::default()), crate::args::DenoSubcommand::Run(Default::default()),
CliMainWorkerOptions { CliMainWorkerOptions {
argv: metadata.argv, argv: metadata.argv,

View file

@ -1,10 +1,13 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write; use std::io::Write;
use capacity_builder::BytesAppendable;
use deno_ast::swc::common::source_map;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
@ -19,12 +22,15 @@ use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use indexmap::IndexMap;
use crate::standalone::virtual_fs::VirtualDirectory; use crate::standalone::virtual_fs::VirtualDirectory;
use super::binary::Metadata; use super::binary::Metadata;
use super::virtual_fs::BuiltVfs; use super::virtual_fs::BuiltVfs;
use super::virtual_fs::VfsBuilder; use super::virtual_fs::VfsBuilder;
use super::virtual_fs::VirtualDirectoryEntries;
const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd"; const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd";
@ -32,60 +38,64 @@ const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd";
/// * d3n0l4nd /// * d3n0l4nd
/// * <metadata_len><metadata> /// * <metadata_len><metadata>
/// * <npm_snapshot_len><npm_snapshot> /// * <npm_snapshot_len><npm_snapshot>
/// * <remote_modules_len><remote_modules> /// * <remote_modules>
/// * <vfs_headers_len><vfs_headers> /// * <vfs_headers_len><vfs_headers>
/// * <vfs_file_data_len><vfs_file_data> /// * <vfs_file_data_len><vfs_file_data>
/// * <source_map_data>
/// * d3n0l4nd /// * d3n0l4nd
pub fn serialize_binary_data_section( pub fn serialize_binary_data_section(
metadata: &Metadata, metadata: &Metadata,
npm_snapshot: Option<SerializedNpmResolutionSnapshot>, npm_snapshot: Option<SerializedNpmResolutionSnapshot>,
remote_modules: &RemoteModulesStoreBuilder, remote_modules: &RemoteModulesStoreBuilder,
source_map_store: &SourceMapStore,
vfs: &BuiltVfs, vfs: &BuiltVfs,
) -> Result<Vec<u8>, AnyError> { ) -> Result<Vec<u8>, AnyError> {
fn write_bytes_with_len(bytes: &mut Vec<u8>, data: &[u8]) { let metadata = serde_json::to_string(metadata)?;
bytes.extend_from_slice(&(data.len() as u64).to_le_bytes()); let npm_snapshot =
bytes.extend_from_slice(data); npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default();
} let serialized_vfs = serde_json::to_string(&vfs.entries)?;
let mut bytes = Vec::new(); let bytes = capacity_builder::BytesBuilder::build(|builder| {
bytes.extend_from_slice(MAGIC_BYTES); builder.append(MAGIC_BYTES);
// 1. Metadata
// 1. Metadata {
{ builder.append_le(metadata.len() as u64);
let metadata = serde_json::to_string(metadata)?; builder.append(&metadata);
write_bytes_with_len(&mut bytes, metadata.as_bytes()); }
} // 2. Npm snapshot
// 2. Npm snapshot {
{ builder.append_le(npm_snapshot.len() as u64);
let npm_snapshot = builder.append(&npm_snapshot);
npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default(); }
write_bytes_with_len(&mut bytes, &npm_snapshot); // 3. Remote modules
} {
// 3. Remote modules remote_modules.write(builder);
{ }
let update_index = bytes.len(); // 4. VFS
bytes.extend_from_slice(&(0_u64).to_le_bytes()); {
let start_index = bytes.len(); builder.append_le(serialized_vfs.len() as u64);
remote_modules.write(&mut bytes)?; builder.append(&serialized_vfs);
let length = bytes.len() - start_index; let vfs_bytes_len = vfs.files.iter().map(|f| f.len() as u64).sum::<u64>();
let length_bytes = (length as u64).to_le_bytes(); builder.append_le(vfs_bytes_len);
bytes[update_index..update_index + length_bytes.len()] for file in &vfs.files {
.copy_from_slice(&length_bytes); builder.append(file);
} }
// 4. VFS }
{ // 5. Source maps
let serialized_vfs = serde_json::to_string(&vfs.root)?; {
write_bytes_with_len(&mut bytes, serialized_vfs.as_bytes()); builder.append_le(source_map_store.data.len() as u32);
let vfs_bytes_len = vfs.files.iter().map(|f| f.len() as u64).sum::<u64>(); for (specifier, source_map) in &source_map_store.data {
bytes.extend_from_slice(&vfs_bytes_len.to_le_bytes()); builder.append_le(specifier.len() as u32);
for file in &vfs.files { builder.append(specifier);
bytes.extend_from_slice(file); builder.append_le(source_map.len() as u32);
builder.append(source_map.as_ref());
}
} }
}
// write the magic bytes at the end so we can use it // write the magic bytes at the end so we can use it
// to make sure we've deserialized correctly // to make sure we've deserialized correctly
bytes.extend_from_slice(MAGIC_BYTES); builder.append(MAGIC_BYTES);
})?;
Ok(bytes) Ok(bytes)
} }
@ -94,19 +104,14 @@ pub struct DeserializedDataSection {
pub metadata: Metadata, pub metadata: Metadata,
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>, pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
pub remote_modules: RemoteModulesStore, pub remote_modules: RemoteModulesStore,
pub vfs_dir: VirtualDirectory, pub source_maps: SourceMapStore,
pub vfs_root_entries: VirtualDirectoryEntries,
pub vfs_files_data: &'static [u8], pub vfs_files_data: &'static [u8],
} }
pub fn deserialize_binary_data_section( pub fn deserialize_binary_data_section(
data: &'static [u8], data: &'static [u8],
) -> Result<Option<DeserializedDataSection>, AnyError> { ) -> Result<Option<DeserializedDataSection>, AnyError> {
fn read_bytes_with_len(input: &[u8]) -> Result<(&[u8], &[u8]), AnyError> {
let (input, len) = read_u64(input)?;
let (input, data) = read_bytes(input, len as usize)?;
Ok((input, data))
}
fn read_magic_bytes(input: &[u8]) -> Result<(&[u8], bool), AnyError> { fn read_magic_bytes(input: &[u8]) -> Result<(&[u8], bool), AnyError> {
if input.len() < MAGIC_BYTES.len() { if input.len() < MAGIC_BYTES.len() {
bail!("Unexpected end of data. Could not find magic bytes."); bail!("Unexpected end of data. Could not find magic bytes.");
@ -118,34 +123,51 @@ pub fn deserialize_binary_data_section(
Ok((input, true)) Ok((input, true))
} }
#[allow(clippy::type_complexity)]
fn read_source_map_entry(
input: &[u8],
) -> Result<(&[u8], (Cow<str>, &[u8])), AnyError> {
let (input, specifier) = read_string_lossy(input)?;
let (input, source_map) = read_bytes_with_u32_len(input)?;
Ok((input, (specifier, source_map)))
}
let (input, found) = read_magic_bytes(data)?; let (input, found) = read_magic_bytes(data)?;
if !found { if !found {
return Ok(None); return Ok(None);
} }
// 1. Metadata // 1. Metadata
let (input, data) = read_bytes_with_len(input).context("reading metadata")?; let (input, data) =
read_bytes_with_u64_len(input).context("reading metadata")?;
let metadata: Metadata = let metadata: Metadata =
serde_json::from_slice(data).context("deserializing metadata")?; serde_json::from_slice(data).context("deserializing metadata")?;
// 2. Npm snapshot // 2. Npm snapshot
let (input, data) = let (input, data) =
read_bytes_with_len(input).context("reading npm snapshot")?; read_bytes_with_u64_len(input).context("reading npm snapshot")?;
let npm_snapshot = if data.is_empty() { let npm_snapshot = if data.is_empty() {
None None
} else { } else {
Some(deserialize_npm_snapshot(data).context("deserializing npm snapshot")?) Some(deserialize_npm_snapshot(data).context("deserializing npm snapshot")?)
}; };
// 3. Remote modules // 3. Remote modules
let (input, data) = let (input, remote_modules) =
read_bytes_with_len(input).context("reading remote modules data")?; RemoteModulesStore::build(input).context("deserializing remote modules")?;
let remote_modules =
RemoteModulesStore::build(data).context("deserializing remote modules")?;
// 4. VFS // 4. VFS
let (input, data) = read_bytes_with_len(input).context("vfs")?; let (input, data) = read_bytes_with_u64_len(input).context("vfs")?;
let vfs_dir: VirtualDirectory = let vfs_root_entries: VirtualDirectoryEntries =
serde_json::from_slice(data).context("deserializing vfs data")?; serde_json::from_slice(data).context("deserializing vfs data")?;
let (input, vfs_files_data) = let (input, vfs_files_data) =
read_bytes_with_len(input).context("reading vfs files data")?; read_bytes_with_u64_len(input).context("reading vfs files data")?;
// 5. Source maps
let (mut input, source_map_data_len) = read_u32_as_usize(input)?;
let mut source_maps = SourceMapStore::with_capacity(source_map_data_len);
for _ in 0..source_map_data_len {
let (current_input, (specifier, source_map)) =
read_source_map_entry(input)?;
input = current_input;
source_maps.add(specifier, Cow::Borrowed(source_map));
}
// finally ensure we read the magic bytes at the end // finally ensure we read the magic bytes at the end
let (_input, found) = read_magic_bytes(input)?; let (_input, found) = read_magic_bytes(input)?;
@ -157,7 +179,8 @@ pub fn deserialize_binary_data_section(
metadata, metadata,
npm_snapshot, npm_snapshot,
remote_modules, remote_modules,
vfs_dir, source_maps,
vfs_root_entries,
vfs_files_data, vfs_files_data,
})) }))
} }
@ -165,19 +188,31 @@ pub fn deserialize_binary_data_section(
#[derive(Default)] #[derive(Default)]
pub struct RemoteModulesStoreBuilder { pub struct RemoteModulesStoreBuilder {
specifiers: Vec<(String, u64)>, specifiers: Vec<(String, u64)>,
data: Vec<(MediaType, Vec<u8>)>, data: Vec<(MediaType, Vec<u8>, Option<Vec<u8>>)>,
data_byte_len: u64, data_byte_len: u64,
redirects: Vec<(String, String)>, redirects: Vec<(String, String)>,
redirects_len: u64, redirects_len: u64,
} }
impl RemoteModulesStoreBuilder { impl RemoteModulesStoreBuilder {
pub fn add(&mut self, specifier: &Url, media_type: MediaType, data: Vec<u8>) { pub fn add(
&mut self,
specifier: &Url,
media_type: MediaType,
data: Vec<u8>,
maybe_transpiled: Option<Vec<u8>>,
) {
log::debug!("Adding '{}' ({})", specifier, media_type); log::debug!("Adding '{}' ({})", specifier, media_type);
let specifier = specifier.to_string(); let specifier = specifier.to_string();
self.specifiers.push((specifier, self.data_byte_len)); self.specifiers.push((specifier, self.data_byte_len));
self.data_byte_len += 1 + 8 + data.len() as u64; // media type (1 byte), data length (8 bytes), data let maybe_transpiled_len = match &maybe_transpiled {
self.data.push((media_type, data)); // data length (4 bytes), data
Some(data) => 4 + data.len() as u64,
None => 0,
};
// media type (1 byte), data length (4 bytes), data, has transpiled (1 byte), transpiled length
self.data_byte_len += 1 + 4 + data.len() as u64 + 1 + maybe_transpiled_len;
self.data.push((media_type, data, maybe_transpiled));
} }
pub fn add_redirects(&mut self, redirects: &BTreeMap<Url, Url>) { pub fn add_redirects(&mut self, redirects: &BTreeMap<Url, Url>) {
@ -191,26 +226,50 @@ impl RemoteModulesStoreBuilder {
} }
} }
fn write(&self, writer: &mut dyn Write) -> Result<(), AnyError> { fn write<'a, TBytes: capacity_builder::BytesType>(
writer.write_all(&(self.specifiers.len() as u32).to_le_bytes())?; &'a self,
writer.write_all(&(self.redirects.len() as u32).to_le_bytes())?; builder: &mut capacity_builder::BytesBuilder<'a, TBytes>,
) {
builder.append_le(self.specifiers.len() as u32);
builder.append_le(self.redirects.len() as u32);
for (specifier, offset) in &self.specifiers { for (specifier, offset) in &self.specifiers {
writer.write_all(&(specifier.len() as u32).to_le_bytes())?; builder.append_le(specifier.len() as u32);
writer.write_all(specifier.as_bytes())?; builder.append(specifier);
writer.write_all(&offset.to_le_bytes())?; builder.append_le(*offset);
} }
for (from, to) in &self.redirects { for (from, to) in &self.redirects {
writer.write_all(&(from.len() as u32).to_le_bytes())?; builder.append_le(from.len() as u32);
writer.write_all(from.as_bytes())?; builder.append(from);
writer.write_all(&(to.len() as u32).to_le_bytes())?; builder.append_le(to.len() as u32);
writer.write_all(to.as_bytes())?; builder.append(to);
} }
for (media_type, data) in &self.data { builder.append_le(
writer.write_all(&[serialize_media_type(*media_type)])?; self
writer.write_all(&(data.len() as u64).to_le_bytes())?; .data
writer.write_all(data)?; .iter()
.map(|(_, data, maybe_transpiled)| {
1 + 4
+ (data.len() as u64)
+ 1
+ match maybe_transpiled {
Some(transpiled) => 4 + (transpiled.len() as u64),
None => 0,
}
})
.sum::<u64>(),
);
for (media_type, data, maybe_transpiled) in &self.data {
builder.append(serialize_media_type(*media_type));
builder.append_le(data.len() as u32);
builder.append(data);
if let Some(transpiled) = maybe_transpiled {
builder.append(1);
builder.append_le(transpiled.len() as u32);
builder.append(transpiled);
} else {
builder.append(0);
}
} }
Ok(())
} }
} }
@ -238,6 +297,30 @@ impl DenoCompileModuleSource {
} }
} }
pub struct SourceMapStore {
data: IndexMap<Cow<'static, str>, Cow<'static, [u8]>>,
}
impl SourceMapStore {
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: IndexMap::with_capacity(capacity),
}
}
pub fn add(
&mut self,
specifier: Cow<'static, str>,
source_map: Cow<'static, [u8]>,
) {
self.data.insert(specifier, source_map);
}
pub fn get(&self, specifier: &str) -> Option<&[u8]> {
self.data.get(specifier).map(|v| v.as_ref())
}
}
pub struct DenoCompileModuleData<'a> { pub struct DenoCompileModuleData<'a> {
pub specifier: &'a Url, pub specifier: &'a Url,
pub media_type: MediaType, pub media_type: MediaType,
@ -284,6 +367,13 @@ impl<'a> DenoCompileModuleData<'a> {
} }
} }
pub struct RemoteModuleEntry<'a> {
pub specifier: &'a Url,
pub media_type: MediaType,
pub data: Cow<'static, [u8]>,
pub transpiled_data: Option<Cow<'static, [u8]>>,
}
enum RemoteModulesStoreSpecifierValue { enum RemoteModulesStoreSpecifierValue {
Data(usize), Data(usize),
Redirect(Url), Redirect(Url),
@ -295,7 +385,7 @@ pub struct RemoteModulesStore {
} }
impl RemoteModulesStore { impl RemoteModulesStore {
fn build(data: &'static [u8]) -> Result<Self, AnyError> { fn build(input: &'static [u8]) -> Result<(&'static [u8], Self), AnyError> {
fn read_specifier(input: &[u8]) -> Result<(&[u8], (Url, u64)), AnyError> { fn read_specifier(input: &[u8]) -> Result<(&[u8], (Url, u64)), AnyError> {
let (input, specifier) = read_string_lossy(input)?; let (input, specifier) = read_string_lossy(input)?;
let specifier = Url::parse(&specifier)?; let specifier = Url::parse(&specifier)?;
@ -338,12 +428,16 @@ impl RemoteModulesStore {
Ok((input, specifiers)) Ok((input, specifiers))
} }
let (files_data, specifiers) = read_headers(data)?; let (input, specifiers) = read_headers(input)?;
let (input, files_data) = read_bytes_with_u64_len(input)?;
Ok(Self { Ok((
specifiers, input,
files_data, Self {
}) specifiers,
files_data,
},
))
} }
pub fn resolve_specifier<'a>( pub fn resolve_specifier<'a>(
@ -374,7 +468,7 @@ impl RemoteModulesStore {
pub fn read<'a>( pub fn read<'a>(
&'a self, &'a self,
original_specifier: &'a Url, original_specifier: &'a Url,
) -> Result<Option<DenoCompileModuleData<'a>>, AnyError> { ) -> Result<Option<RemoteModuleEntry<'a>>, AnyError> {
let mut count = 0; let mut count = 0;
let mut specifier = original_specifier; let mut specifier = original_specifier;
loop { loop {
@ -390,12 +484,25 @@ impl RemoteModulesStore {
let input = &self.files_data[*offset..]; let input = &self.files_data[*offset..];
let (input, media_type_byte) = read_bytes(input, 1)?; let (input, media_type_byte) = read_bytes(input, 1)?;
let media_type = deserialize_media_type(media_type_byte[0])?; let media_type = deserialize_media_type(media_type_byte[0])?;
let (input, len) = read_u64(input)?; let (input, data) = read_bytes_with_u32_len(input)?;
let (_input, data) = read_bytes(input, len as usize)?; check_has_len(input, 1)?;
return Ok(Some(DenoCompileModuleData { let (input, has_transpiled) = (&input[1..], input[0]);
let (_, transpiled_data) = match has_transpiled {
0 => (input, None),
1 => {
let (input, data) = read_bytes_with_u32_len(input)?;
(input, Some(data))
}
value => bail!(
"Invalid transpiled data flag: {}. Compiled data is corrupt.",
value
),
};
return Ok(Some(RemoteModuleEntry {
specifier, specifier,
media_type, media_type,
data: Cow::Borrowed(data), data: Cow::Borrowed(data),
transpiled_data: transpiled_data.map(Cow::Borrowed),
})); }));
} }
None => { None => {
@ -479,12 +586,13 @@ fn deserialize_npm_snapshot(
#[allow(clippy::needless_lifetimes)] // clippy bug #[allow(clippy::needless_lifetimes)] // clippy bug
fn parse_package_dep<'a>( fn parse_package_dep<'a>(
id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>, id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>,
) -> impl Fn(&[u8]) -> Result<(&[u8], (String, NpmPackageId)), AnyError> + 'a ) -> impl Fn(&[u8]) -> Result<(&[u8], (StackString, NpmPackageId)), AnyError> + 'a
{ {
|input| { |input| {
let (input, req) = read_string_lossy(input)?; let (input, req) = read_string_lossy(input)?;
let (input, id) = read_u32_as_usize(input)?; let (input, id) = read_u32_as_usize(input)?;
Ok((input, (req.into_owned(), id_to_npm_id(id)?))) let req = StackString::from_cow(req);
Ok((input, (req, id_to_npm_id(id)?)))
} }
} }
@ -634,17 +742,34 @@ fn parse_vec_n_times_with_index<TResult>(
Ok((input, results)) Ok((input, results))
} }
fn read_bytes_with_u64_len(input: &[u8]) -> Result<(&[u8], &[u8]), AnyError> {
let (input, len) = read_u64(input)?;
let (input, data) = read_bytes(input, len as usize)?;
Ok((input, data))
}
fn read_bytes_with_u32_len(input: &[u8]) -> Result<(&[u8], &[u8]), AnyError> {
let (input, len) = read_u32_as_usize(input)?;
let (input, data) = read_bytes(input, len)?;
Ok((input, data))
}
fn read_bytes(input: &[u8], len: usize) -> Result<(&[u8], &[u8]), AnyError> { fn read_bytes(input: &[u8], len: usize) -> Result<(&[u8], &[u8]), AnyError> {
if input.len() < len { check_has_len(input, len)?;
bail!("Unexpected end of data.",);
}
let (len_bytes, input) = input.split_at(len); let (len_bytes, input) = input.split_at(len);
Ok((input, len_bytes)) Ok((input, len_bytes))
} }
#[inline(always)]
fn check_has_len(input: &[u8], len: usize) -> Result<(), AnyError> {
if input.len() < len {
bail!("Unexpected end of data.");
}
Ok(())
}
fn read_string_lossy(input: &[u8]) -> Result<(&[u8], Cow<str>), AnyError> { fn read_string_lossy(input: &[u8]) -> Result<(&[u8], Cow<str>), AnyError> {
let (input, str_len) = read_u32_as_usize(input)?; let (input, data_bytes) = read_bytes_with_u32_len(input)?;
let (input, data_bytes) = read_bytes(input, str_len)?;
Ok((input, String::from_utf8_lossy(data_bytes))) Ok((input, String::from_utf8_lossy(data_bytes)))
} }

View file

@ -51,8 +51,16 @@ pub enum WindowsSystemRootablePath {
impl WindowsSystemRootablePath { impl WindowsSystemRootablePath {
pub fn join(&self, name_component: &str) -> PathBuf { pub fn join(&self, name_component: &str) -> PathBuf {
// this method doesn't handle multiple components // this method doesn't handle multiple components
debug_assert!(!name_component.contains('\\')); debug_assert!(
debug_assert!(!name_component.contains('/')); !name_component.contains('\\'),
"Invalid component: {}",
name_component
);
debug_assert!(
!name_component.contains('/'),
"Invalid component: {}",
name_component
);
match self { match self {
WindowsSystemRootablePath::WindowSystemRoot => { WindowsSystemRootablePath::WindowSystemRoot => {
@ -67,7 +75,7 @@ impl WindowsSystemRootablePath {
#[derive(Debug)] #[derive(Debug)]
pub struct BuiltVfs { pub struct BuiltVfs {
pub root_path: WindowsSystemRootablePath, pub root_path: WindowsSystemRootablePath,
pub root: VirtualDirectory, pub entries: VirtualDirectoryEntries,
pub files: Vec<Vec<u8>>, pub files: Vec<Vec<u8>>,
} }
@ -95,7 +103,7 @@ impl VfsBuilder {
Self { Self {
executable_root: VirtualDirectory { executable_root: VirtualDirectory {
name: "/".to_string(), name: "/".to_string(),
entries: Vec::new(), entries: Default::default(),
}, },
files: Vec::new(), files: Vec::new(),
current_offset: 0, current_offset: 0,
@ -208,23 +216,20 @@ impl VfsBuilder {
continue; continue;
} }
let name = component.as_os_str().to_string_lossy(); let name = component.as_os_str().to_string_lossy();
let index = match current_dir let index = match current_dir.entries.binary_search(&name) {
.entries
.binary_search_by(|e| e.name().cmp(&name))
{
Ok(index) => index, Ok(index) => index,
Err(insert_index) => { Err(insert_index) => {
current_dir.entries.insert( current_dir.entries.0.insert(
insert_index, insert_index,
VfsEntry::Dir(VirtualDirectory { VfsEntry::Dir(VirtualDirectory {
name: name.to_string(), name: name.to_string(),
entries: Vec::new(), entries: Default::default(),
}), }),
); );
insert_index insert_index
} }
}; };
match &mut current_dir.entries[index] { match &mut current_dir.entries.0[index] {
VfsEntry::Dir(dir) => { VfsEntry::Dir(dir) => {
current_dir = dir; current_dir = dir;
} }
@ -248,14 +253,8 @@ impl VfsBuilder {
continue; continue;
} }
let name = component.as_os_str().to_string_lossy(); let name = component.as_os_str().to_string_lossy();
let index = match current_dir let entry = current_dir.entries.get_mut_by_name(&name)?;
.entries match entry {
.binary_search_by(|e| e.name().cmp(&name))
{
Ok(index) => index,
Err(_) => return None,
};
match &mut current_dir.entries[index] {
VfsEntry::Dir(dir) => { VfsEntry::Dir(dir) => {
current_dir = dir; current_dir = dir;
} }
@ -320,9 +319,9 @@ impl VfsBuilder {
offset, offset,
len: data.len() as u64, len: data.len() as u64,
}; };
match dir.entries.binary_search_by(|e| e.name().cmp(&name)) { match dir.entries.binary_search(&name) {
Ok(index) => { Ok(index) => {
let entry = &mut dir.entries[index]; let entry = &mut dir.entries.0[index];
match entry { match entry {
VfsEntry::File(virtual_file) => match sub_data_kind { VfsEntry::File(virtual_file) => match sub_data_kind {
VfsFileSubDataKind::Raw => { VfsFileSubDataKind::Raw => {
@ -336,7 +335,7 @@ impl VfsBuilder {
} }
} }
Err(insert_index) => { Err(insert_index) => {
dir.entries.insert( dir.entries.0.insert(
insert_index, insert_index,
VfsEntry::File(VirtualFile { VfsEntry::File(VirtualFile {
name: name.to_string(), name: name.to_string(),
@ -384,10 +383,10 @@ impl VfsBuilder {
let target = normalize_path(path.parent().unwrap().join(&target)); let target = normalize_path(path.parent().unwrap().join(&target));
let dir = self.add_dir_raw(path.parent().unwrap()); let dir = self.add_dir_raw(path.parent().unwrap());
let name = path.file_name().unwrap().to_string_lossy(); let name = path.file_name().unwrap().to_string_lossy();
match dir.entries.binary_search_by(|e| e.name().cmp(&name)) { match dir.entries.binary_search(&name) {
Ok(_) => {} // previously inserted Ok(_) => {} // previously inserted
Err(insert_index) => { Err(insert_index) => {
dir.entries.insert( dir.entries.0.insert(
insert_index, insert_index,
VfsEntry::Symlink(VirtualSymlink { VfsEntry::Symlink(VirtualSymlink {
name: name.to_string(), name: name.to_string(),
@ -426,7 +425,7 @@ impl VfsBuilder {
dir: &mut VirtualDirectory, dir: &mut VirtualDirectory,
parts: &[String], parts: &[String],
) { ) {
for entry in &mut dir.entries { for entry in &mut dir.entries.0 {
match entry { match entry {
VfsEntry::Dir(dir) => { VfsEntry::Dir(dir) => {
strip_prefix_from_symlinks(dir, parts); strip_prefix_from_symlinks(dir, parts);
@ -454,13 +453,13 @@ impl VfsBuilder {
if self.min_root_dir.as_ref() == Some(&current_path) { if self.min_root_dir.as_ref() == Some(&current_path) {
break; break;
} }
match &current_dir.entries[0] { match &current_dir.entries.0[0] {
VfsEntry::Dir(dir) => { VfsEntry::Dir(dir) => {
if dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME { if dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME {
// special directory we want to maintain // special directory we want to maintain
break; break;
} }
match current_dir.entries.remove(0) { match current_dir.entries.0.remove(0) {
VfsEntry::Dir(dir) => { VfsEntry::Dir(dir) => {
current_path = current_path =
WindowsSystemRootablePath::Path(current_path.join(&dir.name)); WindowsSystemRootablePath::Path(current_path.join(&dir.name));
@ -480,7 +479,7 @@ impl VfsBuilder {
} }
BuiltVfs { BuiltVfs {
root_path: current_path, root_path: current_path,
root: current_dir, entries: current_dir.entries,
files: self.files, files: self.files,
} }
} }
@ -506,7 +505,7 @@ pub fn output_vfs(vfs: &BuiltVfs, executable_name: &str) {
return; // no need to compute if won't output return; // no need to compute if won't output
} }
if vfs.root.entries.is_empty() { if vfs.entries.is_empty() {
return; // nothing to output return; // nothing to output
} }
@ -696,7 +695,7 @@ fn vfs_as_display_tree(
fn dir_size(dir: &VirtualDirectory, seen_offsets: &mut HashSet<u64>) -> Size { fn dir_size(dir: &VirtualDirectory, seen_offsets: &mut HashSet<u64>) -> Size {
let mut size = Size::default(); let mut size = Size::default();
for entry in &dir.entries { for entry in dir.entries.iter() {
match entry { match entry {
VfsEntry::Dir(virtual_directory) => { VfsEntry::Dir(virtual_directory) => {
size = size + dir_size(virtual_directory, seen_offsets); size = size + dir_size(virtual_directory, seen_offsets);
@ -760,15 +759,10 @@ fn vfs_as_display_tree(
fn include_all_entries<'a>( fn include_all_entries<'a>(
dir_path: &WindowsSystemRootablePath, dir_path: &WindowsSystemRootablePath,
vfs_dir: &'a VirtualDirectory, entries: &'a VirtualDirectoryEntries,
seen_offsets: &mut HashSet<u64>, seen_offsets: &mut HashSet<u64>,
) -> Vec<DirEntryOutput<'a>> { ) -> Vec<DirEntryOutput<'a>> {
if vfs_dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME { entries
return show_global_node_modules_dir(vfs_dir, seen_offsets);
}
vfs_dir
.entries
.iter() .iter()
.map(|entry| DirEntryOutput { .map(|entry| DirEntryOutput {
name: Cow::Borrowed(entry.name()), name: Cow::Borrowed(entry.name()),
@ -826,10 +820,12 @@ fn vfs_as_display_tree(
} else { } else {
EntryOutput::Subset(children) EntryOutput::Subset(children)
} }
} else if vfs_dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME {
EntryOutput::Subset(show_global_node_modules_dir(vfs_dir, seen_offsets))
} else { } else {
EntryOutput::Subset(include_all_entries( EntryOutput::Subset(include_all_entries(
&WindowsSystemRootablePath::Path(dir), &WindowsSystemRootablePath::Path(dir),
vfs_dir, &vfs_dir.entries,
seen_offsets, seen_offsets,
)) ))
} }
@ -839,7 +835,7 @@ fn vfs_as_display_tree(
// user might not have context about what's being shown // user might not have context about what's being shown
let mut seen_offsets = HashSet::with_capacity(vfs.files.len()); let mut seen_offsets = HashSet::with_capacity(vfs.files.len());
let mut child_entries = let mut child_entries =
include_all_entries(&vfs.root_path, &vfs.root, &mut seen_offsets); include_all_entries(&vfs.root_path, &vfs.entries, &mut seen_offsets);
for child_entry in &mut child_entries { for child_entry in &mut child_entries {
child_entry.collapse_leaf_nodes(); child_entry.collapse_leaf_nodes();
} }
@ -859,78 +855,28 @@ enum VfsEntryRef<'a> {
Symlink(&'a VirtualSymlink), Symlink(&'a VirtualSymlink),
} }
impl<'a> VfsEntryRef<'a> { impl VfsEntryRef<'_> {
pub fn as_fs_stat(&self) -> FsStat { pub fn as_metadata(&self) -> FileBackedVfsMetadata {
FileBackedVfsMetadata {
file_type: match self {
Self::Dir(_) => sys_traits::FileType::Dir,
Self::File(_) => sys_traits::FileType::File,
Self::Symlink(_) => sys_traits::FileType::Symlink,
},
name: self.name().to_string(),
len: match self {
Self::Dir(_) => 0,
Self::File(file) => file.offset.len,
Self::Symlink(_) => 0,
},
}
}
pub fn name(&self) -> &str {
match self { match self {
VfsEntryRef::Dir(_) => FsStat { Self::Dir(dir) => &dir.name,
is_directory: true, Self::File(file) => &file.name,
is_file: false, Self::Symlink(symlink) => &symlink.name,
is_symlink: false,
atime: None,
birthtime: None,
mtime: None,
ctime: None,
blksize: 0,
size: 0,
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blocks: 0,
is_block_device: false,
is_char_device: false,
is_fifo: false,
is_socket: false,
},
VfsEntryRef::File(file) => FsStat {
is_directory: false,
is_file: true,
is_symlink: false,
atime: None,
birthtime: None,
mtime: None,
ctime: None,
blksize: 0,
size: file.offset.len,
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blocks: 0,
is_block_device: false,
is_char_device: false,
is_fifo: false,
is_socket: false,
},
VfsEntryRef::Symlink(_) => FsStat {
is_directory: false,
is_file: false,
is_symlink: true,
atime: None,
birthtime: None,
mtime: None,
ctime: None,
blksize: 0,
size: 0,
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blocks: 0,
is_block_device: false,
is_char_device: false,
is_fifo: false,
is_socket: false,
},
} }
} }
} }
@ -946,9 +892,9 @@ pub enum VfsEntry {
impl VfsEntry { impl VfsEntry {
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
match self { match self {
VfsEntry::Dir(dir) => &dir.name, Self::Dir(dir) => &dir.name,
VfsEntry::File(file) => &file.name, Self::File(file) => &file.name,
VfsEntry::Symlink(symlink) => &symlink.name, Self::Symlink(symlink) => &symlink.name,
} }
} }
@ -961,27 +907,70 @@ impl VfsEntry {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct VirtualDirectoryEntries(Vec<VfsEntry>);
impl VirtualDirectoryEntries {
pub fn new(mut entries: Vec<VfsEntry>) -> Self {
// needs to be sorted by name
entries.sort_by(|a, b| a.name().cmp(b.name()));
Self(entries)
}
pub fn take_inner(&mut self) -> Vec<VfsEntry> {
std::mem::take(&mut self.0)
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get_by_name(&self, name: &str) -> Option<&VfsEntry> {
self.binary_search(name).ok().map(|index| &self.0[index])
}
pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut VfsEntry> {
self
.binary_search(name)
.ok()
.map(|index| &mut self.0[index])
}
pub fn binary_search(&self, name: &str) -> Result<usize, usize> {
self.0.binary_search_by(|e| e.name().cmp(name))
}
pub fn insert(&mut self, entry: VfsEntry) {
match self.binary_search(entry.name()) {
Ok(index) => {
self.0[index] = entry;
}
Err(insert_index) => {
self.0.insert(insert_index, entry);
}
}
}
pub fn remove(&mut self, index: usize) -> VfsEntry {
self.0.remove(index)
}
pub fn iter(&self) -> std::slice::Iter<'_, VfsEntry> {
self.0.iter()
}
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct VirtualDirectory { pub struct VirtualDirectory {
#[serde(rename = "n")] #[serde(rename = "n")]
pub name: String, pub name: String,
// should be sorted by name // should be sorted by name
#[serde(rename = "e")] #[serde(rename = "e")]
pub entries: Vec<VfsEntry>, pub entries: VirtualDirectoryEntries,
}
impl VirtualDirectory {
pub fn insert_entry(&mut self, entry: VfsEntry) {
let name = entry.name();
match self.entries.binary_search_by(|e| e.name().cmp(name)) {
Ok(index) => {
self.entries[index] = entry;
}
Err(insert_index) => {
self.entries.insert(insert_index, entry);
}
}
}
} }
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -1136,34 +1125,27 @@ impl VfsRoot {
} }
}; };
let component = component.to_string_lossy(); let component = component.to_string_lossy();
match current_dir current_entry = current_dir
.entries .entries
.binary_search_by(|e| e.name().cmp(&component)) .get_by_name(&component)
{ .ok_or_else(|| {
Ok(index) => { std::io::Error::new(std::io::ErrorKind::NotFound, "path not found")
current_entry = current_dir.entries[index].as_ref(); })?
} .as_ref();
Err(_) => {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"path not found",
));
}
}
} }
Ok((final_path, current_entry)) Ok((final_path, current_entry))
} }
} }
struct FileBackedVfsFile { pub struct FileBackedVfsFile {
file: VirtualFile, file: VirtualFile,
pos: RefCell<u64>, pos: RefCell<u64>,
vfs: Arc<FileBackedVfs>, vfs: Arc<FileBackedVfs>,
} }
impl FileBackedVfsFile { impl FileBackedVfsFile {
fn seek(&self, pos: SeekFrom) -> FsResult<u64> { pub fn seek(&self, pos: SeekFrom) -> std::io::Result<u64> {
match pos { match pos {
SeekFrom::Start(pos) => { SeekFrom::Start(pos) => {
*self.pos.borrow_mut() = pos; *self.pos.borrow_mut() = pos;
@ -1172,10 +1154,10 @@ impl FileBackedVfsFile {
SeekFrom::End(offset) => { SeekFrom::End(offset) => {
if offset < 0 && -offset as u64 > self.file.offset.len { if offset < 0 && -offset as u64 > self.file.offset.len {
let msg = "An attempt was made to move the file pointer before the beginning of the file."; let msg = "An attempt was made to move the file pointer before the beginning of the file.";
Err( Err(std::io::Error::new(
std::io::Error::new(std::io::ErrorKind::PermissionDenied, msg) std::io::ErrorKind::PermissionDenied,
.into(), msg,
) ))
} else { } else {
let mut current_pos = self.pos.borrow_mut(); let mut current_pos = self.pos.borrow_mut();
*current_pos = if offset >= 0 { *current_pos = if offset >= 0 {
@ -1191,7 +1173,7 @@ impl FileBackedVfsFile {
if offset >= 0 { if offset >= 0 {
*current_pos += offset as u64; *current_pos += offset as u64;
} else if -offset as u64 > *current_pos { } else if -offset as u64 > *current_pos {
return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file.").into()); return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file."));
} else { } else {
*current_pos -= -offset as u64; *current_pos -= -offset as u64;
} }
@ -1200,7 +1182,7 @@ impl FileBackedVfsFile {
} }
} }
fn read_to_buf(&self, buf: &mut [u8]) -> FsResult<usize> { pub fn read_to_buf(&self, buf: &mut [u8]) -> std::io::Result<usize> {
let read_pos = { let read_pos = {
let mut pos = self.pos.borrow_mut(); let mut pos = self.pos.borrow_mut();
let read_pos = *pos; let read_pos = *pos;
@ -1208,10 +1190,7 @@ impl FileBackedVfsFile {
*pos = std::cmp::min(self.file.offset.len, *pos + buf.len() as u64); *pos = std::cmp::min(self.file.offset.len, *pos + buf.len() as u64);
read_pos read_pos
}; };
self self.vfs.read_file(&self.file, read_pos, buf)
.vfs
.read_file(&self.file, read_pos, buf)
.map_err(|err| err.into())
} }
fn read_to_end(&self) -> FsResult<Cow<'static, [u8]>> { fn read_to_end(&self) -> FsResult<Cow<'static, [u8]>> {
@ -1246,7 +1225,7 @@ impl FileBackedVfsFile {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl deno_io::fs::File for FileBackedVfsFile { impl deno_io::fs::File for FileBackedVfsFile {
fn read_sync(self: Rc<Self>, buf: &mut [u8]) -> FsResult<usize> { fn read_sync(self: Rc<Self>, buf: &mut [u8]) -> FsResult<usize> {
self.read_to_buf(buf) self.read_to_buf(buf).map_err(Into::into)
} }
async fn read_byob( async fn read_byob(
self: Rc<Self>, self: Rc<Self>,
@ -1290,10 +1269,10 @@ impl deno_io::fs::File for FileBackedVfsFile {
} }
fn seek_sync(self: Rc<Self>, pos: SeekFrom) -> FsResult<u64> { fn seek_sync(self: Rc<Self>, pos: SeekFrom) -> FsResult<u64> {
self.seek(pos) self.seek(pos).map_err(|err| err.into())
} }
async fn seek_async(self: Rc<Self>, pos: SeekFrom) -> FsResult<u64> { async fn seek_async(self: Rc<Self>, pos: SeekFrom) -> FsResult<u64> {
self.seek(pos) self.seek(pos).map_err(|err| err.into())
} }
fn datasync_sync(self: Rc<Self>) -> FsResult<()> { fn datasync_sync(self: Rc<Self>) -> FsResult<()> {
@ -1369,6 +1348,47 @@ impl deno_io::fs::File for FileBackedVfsFile {
} }
} }
#[derive(Debug, Clone)]
pub struct FileBackedVfsDirEntry {
pub parent_path: PathBuf,
pub metadata: FileBackedVfsMetadata,
}
#[derive(Debug, Clone)]
pub struct FileBackedVfsMetadata {
pub name: String,
pub file_type: sys_traits::FileType,
pub len: u64,
}
impl FileBackedVfsMetadata {
pub fn as_fs_stat(&self) -> FsStat {
FsStat {
is_directory: self.file_type == sys_traits::FileType::Dir,
is_file: self.file_type == sys_traits::FileType::File,
is_symlink: self.file_type == sys_traits::FileType::Symlink,
atime: None,
birthtime: None,
mtime: None,
ctime: None,
blksize: 0,
size: self.len,
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blocks: 0,
is_block_device: false,
is_char_device: false,
is_fifo: false,
is_socket: false,
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct FileBackedVfs { pub struct FileBackedVfs {
vfs_data: Cow<'static, [u8]>, vfs_data: Cow<'static, [u8]>,
@ -1394,13 +1414,13 @@ impl FileBackedVfs {
pub fn open_file( pub fn open_file(
self: &Arc<Self>, self: &Arc<Self>,
path: &Path, path: &Path,
) -> std::io::Result<Rc<dyn deno_io::fs::File>> { ) -> std::io::Result<FileBackedVfsFile> {
let file = self.file_entry(path)?; let file = self.file_entry(path)?;
Ok(Rc::new(FileBackedVfsFile { Ok(FileBackedVfsFile {
file: file.clone(), file: file.clone(),
vfs: self.clone(), vfs: self.clone(),
pos: Default::default(), pos: Default::default(),
})) })
} }
pub fn read_dir(&self, path: &Path) -> std::io::Result<Vec<FsDirEntry>> { pub fn read_dir(&self, path: &Path) -> std::io::Result<Vec<FsDirEntry>> {
@ -1419,6 +1439,18 @@ impl FileBackedVfs {
) )
} }
pub fn read_dir_with_metadata<'a>(
&'a self,
path: &Path,
) -> std::io::Result<impl Iterator<Item = FileBackedVfsDirEntry> + 'a> {
let dir = self.dir_entry(path)?;
let path = path.to_path_buf();
Ok(dir.entries.iter().map(move |entry| FileBackedVfsDirEntry {
parent_path: path.to_path_buf(),
metadata: entry.as_ref().as_metadata(),
}))
}
pub fn read_link(&self, path: &Path) -> std::io::Result<PathBuf> { pub fn read_link(&self, path: &Path) -> std::io::Result<PathBuf> {
let (_, entry) = self.fs_root.find_entry_no_follow(path)?; let (_, entry) = self.fs_root.find_entry_no_follow(path)?;
match entry { match entry {
@ -1432,14 +1464,14 @@ impl FileBackedVfs {
} }
} }
pub fn lstat(&self, path: &Path) -> std::io::Result<FsStat> { pub fn lstat(&self, path: &Path) -> std::io::Result<FileBackedVfsMetadata> {
let (_, entry) = self.fs_root.find_entry_no_follow(path)?; let (_, entry) = self.fs_root.find_entry_no_follow(path)?;
Ok(entry.as_fs_stat()) Ok(entry.as_metadata())
} }
pub fn stat(&self, path: &Path) -> std::io::Result<FsStat> { pub fn stat(&self, path: &Path) -> std::io::Result<FileBackedVfsMetadata> {
let (_, entry) = self.fs_root.find_entry(path)?; let (_, entry) = self.fs_root.find_entry(path)?;
Ok(entry.as_fs_stat()) Ok(entry.as_metadata())
} }
pub fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> { pub fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> {
@ -1532,6 +1564,7 @@ impl FileBackedVfs {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use console_static_text::ansi::strip_ansi_codes; use console_static_text::ansi::strip_ansi_codes;
use deno_io::fs::File;
use std::io::Write; use std::io::Write;
use test_util::assert_contains; use test_util::assert_contains;
use test_util::TempDir; use test_util::TempDir;
@ -1617,25 +1650,31 @@ mod test {
); );
// metadata // metadata
assert!( assert_eq!(
virtual_fs virtual_fs
.lstat(&dest_path.join("sub_dir").join("e.txt")) .lstat(&dest_path.join("sub_dir").join("e.txt"))
.unwrap() .unwrap()
.is_symlink .file_type,
sys_traits::FileType::Symlink,
); );
assert!( assert_eq!(
virtual_fs virtual_fs
.stat(&dest_path.join("sub_dir").join("e.txt")) .stat(&dest_path.join("sub_dir").join("e.txt"))
.unwrap() .unwrap()
.is_file .file_type,
sys_traits::FileType::File,
); );
assert!( assert_eq!(
virtual_fs virtual_fs
.stat(&dest_path.join("sub_dir")) .stat(&dest_path.join("sub_dir"))
.unwrap() .unwrap()
.is_directory, .file_type,
sys_traits::FileType::Dir,
);
assert_eq!(
virtual_fs.stat(&dest_path.join("e.txt")).unwrap().file_type,
sys_traits::FileType::File
); );
assert!(virtual_fs.stat(&dest_path.join("e.txt")).unwrap().is_file,);
} }
#[test] #[test]
@ -1672,11 +1711,12 @@ mod test {
read_file(&virtual_fs, &dest_path.join("sub_dir_link").join("c.txt")), read_file(&virtual_fs, &dest_path.join("sub_dir_link").join("c.txt")),
"c", "c",
); );
assert!( assert_eq!(
virtual_fs virtual_fs
.lstat(&dest_path.join("sub_dir_link")) .lstat(&dest_path.join("sub_dir_link"))
.unwrap() .unwrap()
.is_symlink .file_type,
sys_traits::FileType::Symlink,
); );
assert_eq!( assert_eq!(
@ -1706,7 +1746,10 @@ mod test {
FileBackedVfs::new( FileBackedVfs::new(
Cow::Owned(data), Cow::Owned(data),
VfsRoot { VfsRoot {
dir: vfs.root, dir: VirtualDirectory {
name: "".to_string(),
entries: vfs.entries,
},
root_path: dest_path.to_path_buf(), root_path: dest_path.to_path_buf(),
start_file_offset: 0, start_file_offset: 0,
}, },
@ -1745,37 +1788,35 @@ mod test {
let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir); let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir);
let virtual_fs = Arc::new(virtual_fs); let virtual_fs = Arc::new(virtual_fs);
let file = virtual_fs.open_file(&dest_path.join("a.txt")).unwrap(); let file = virtual_fs.open_file(&dest_path.join("a.txt")).unwrap();
file.clone().seek_sync(SeekFrom::Current(2)).unwrap(); file.seek(SeekFrom::Current(2)).unwrap();
let mut buf = vec![0; 2]; let mut buf = vec![0; 2];
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"23"); assert_eq!(buf, b"23");
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"45"); assert_eq!(buf, b"45");
file.clone().seek_sync(SeekFrom::Current(-4)).unwrap(); file.seek(SeekFrom::Current(-4)).unwrap();
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"23"); assert_eq!(buf, b"23");
file.clone().seek_sync(SeekFrom::Start(2)).unwrap(); file.seek(SeekFrom::Start(2)).unwrap();
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"23"); assert_eq!(buf, b"23");
file.clone().seek_sync(SeekFrom::End(2)).unwrap(); file.seek(SeekFrom::End(2)).unwrap();
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"89"); assert_eq!(buf, b"89");
file.clone().seek_sync(SeekFrom::Current(-8)).unwrap(); file.seek(SeekFrom::Current(-8)).unwrap();
file.clone().read_sync(&mut buf).unwrap(); file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"23"); assert_eq!(buf, b"23");
assert_eq!( assert_eq!(
file file
.clone() .seek(SeekFrom::Current(-5))
.seek_sync(SeekFrom::Current(-5)) .unwrap_err()
.err()
.unwrap()
.into_io_error()
.to_string(), .to_string(),
"An attempt was made to move the file pointer before the beginning of the file." "An attempt was made to move the file pointer before the beginning of the file."
); );
// go beyond the file length, then back // go beyond the file length, then back
file.clone().seek_sync(SeekFrom::Current(40)).unwrap(); file.seek(SeekFrom::Current(40)).unwrap();
file.clone().seek_sync(SeekFrom::Current(-38)).unwrap(); file.seek(SeekFrom::Current(-38)).unwrap();
let file = Rc::new(file);
let read_buf = file.clone().read(2).await.unwrap(); let read_buf = file.clone().read(2).await.unwrap();
assert_eq!(read_buf.to_vec(), b"67"); assert_eq!(read_buf.to_vec(), b"67");
file.clone().seek_sync(SeekFrom::Current(-2)).unwrap(); file.clone().seek_sync(SeekFrom::Current(-2)).unwrap();

218
cli/sys.rs Normal file
View file

@ -0,0 +1,218 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// todo(dsherret): this should instead use conditional compilation and directly
// surface the underlying implementation.
//
// The problem atm is that there's no way to have conditional compilation for
// denort or the deno binary. We should extract out denort to a separate binary.
use std::borrow::Cow;
use sys_traits::boxed::BoxedFsDirEntry;
use sys_traits::boxed::BoxedFsFile;
use sys_traits::boxed::BoxedFsMetadataValue;
use sys_traits::boxed::FsMetadataBoxed;
use sys_traits::boxed::FsOpenBoxed;
use sys_traits::boxed::FsReadDirBoxed;
use sys_traits::CreateDirOptions;
use crate::standalone::DenoCompileFileSystem;
#[derive(Debug, Clone)]
pub enum CliSys {
#[allow(dead_code)] // will be dead code for denort
#[allow(clippy::disallowed_types)] // ok because sys impl
Real(sys_traits::impls::RealSys),
#[allow(dead_code)] // will be dead code for deno
DenoCompile(DenoCompileFileSystem),
}
impl Default for CliSys {
fn default() -> Self {
Self::Real(sys_traits::impls::RealSys)
}
}
impl deno_runtime::deno_node::ExtNodeSys for CliSys {}
impl sys_traits::BaseFsHardLink for CliSys {
fn base_fs_hard_link(
&self,
src: &std::path::Path,
dst: &std::path::Path,
) -> std::io::Result<()> {
match self {
Self::Real(sys) => sys.base_fs_hard_link(src, dst),
Self::DenoCompile(sys) => sys.base_fs_hard_link(src, dst),
}
}
}
impl sys_traits::BaseFsRead for CliSys {
fn base_fs_read(
&self,
p: &std::path::Path,
) -> std::io::Result<Cow<'static, [u8]>> {
match self {
Self::Real(sys) => sys.base_fs_read(p),
Self::DenoCompile(sys) => sys.base_fs_read(p),
}
}
}
impl sys_traits::BaseFsReadDir for CliSys {
type ReadDirEntry = BoxedFsDirEntry;
fn base_fs_read_dir(
&self,
p: &std::path::Path,
) -> std::io::Result<
Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>> + '_>,
> {
match self {
Self::Real(sys) => sys.fs_read_dir_boxed(p),
Self::DenoCompile(sys) => sys.fs_read_dir_boxed(p),
}
}
}
impl sys_traits::BaseFsCanonicalize for CliSys {
fn base_fs_canonicalize(
&self,
p: &std::path::Path,
) -> std::io::Result<std::path::PathBuf> {
match self {
Self::Real(sys) => sys.base_fs_canonicalize(p),
Self::DenoCompile(sys) => sys.base_fs_canonicalize(p),
}
}
}
impl sys_traits::BaseFsMetadata for CliSys {
type Metadata = BoxedFsMetadataValue;
fn base_fs_metadata(
&self,
path: &std::path::Path,
) -> std::io::Result<Self::Metadata> {
match self {
Self::Real(sys) => sys.fs_metadata_boxed(path),
Self::DenoCompile(sys) => sys.fs_metadata_boxed(path),
}
}
fn base_fs_symlink_metadata(
&self,
path: &std::path::Path,
) -> std::io::Result<Self::Metadata> {
match self {
Self::Real(sys) => sys.fs_symlink_metadata_boxed(path),
Self::DenoCompile(sys) => sys.fs_symlink_metadata_boxed(path),
}
}
}
impl sys_traits::BaseFsCreateDir for CliSys {
fn base_fs_create_dir(
&self,
p: &std::path::Path,
options: &CreateDirOptions,
) -> std::io::Result<()> {
match self {
Self::Real(sys) => sys.base_fs_create_dir(p, options),
Self::DenoCompile(sys) => sys.base_fs_create_dir(p, options),
}
}
}
impl sys_traits::BaseFsOpen for CliSys {
type File = BoxedFsFile;
fn base_fs_open(
&self,
path: &std::path::Path,
options: &sys_traits::OpenOptions,
) -> std::io::Result<Self::File> {
match self {
Self::Real(sys) => sys.fs_open_boxed(path, options),
Self::DenoCompile(sys) => sys.fs_open_boxed(path, options),
}
}
}
impl sys_traits::BaseFsRemoveFile for CliSys {
fn base_fs_remove_file(&self, p: &std::path::Path) -> std::io::Result<()> {
match self {
Self::Real(sys) => sys.base_fs_remove_file(p),
Self::DenoCompile(sys) => sys.base_fs_remove_file(p),
}
}
}
impl sys_traits::BaseFsRename for CliSys {
fn base_fs_rename(
&self,
old: &std::path::Path,
new: &std::path::Path,
) -> std::io::Result<()> {
match self {
Self::Real(sys) => sys.base_fs_rename(old, new),
Self::DenoCompile(sys) => sys.base_fs_rename(old, new),
}
}
}
impl sys_traits::SystemRandom for CliSys {
fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> {
match self {
Self::Real(sys) => sys.sys_random(buf),
Self::DenoCompile(sys) => sys.sys_random(buf),
}
}
}
impl sys_traits::SystemTimeNow for CliSys {
fn sys_time_now(&self) -> std::time::SystemTime {
match self {
Self::Real(sys) => sys.sys_time_now(),
Self::DenoCompile(sys) => sys.sys_time_now(),
}
}
}
impl sys_traits::ThreadSleep for CliSys {
fn thread_sleep(&self, dur: std::time::Duration) {
match self {
Self::Real(sys) => sys.thread_sleep(dur),
Self::DenoCompile(sys) => sys.thread_sleep(dur),
}
}
}
impl sys_traits::EnvCurrentDir for CliSys {
fn env_current_dir(&self) -> std::io::Result<std::path::PathBuf> {
match self {
Self::Real(sys) => sys.env_current_dir(),
Self::DenoCompile(sys) => sys.env_current_dir(),
}
}
}
impl sys_traits::BaseEnvVar for CliSys {
fn base_env_var_os(
&self,
key: &std::ffi::OsStr,
) -> Option<std::ffi::OsString> {
match self {
Self::Real(sys) => sys.base_env_var_os(key),
Self::DenoCompile(sys) => sys.base_env_var_os(key),
}
}
}
impl sys_traits::EnvHomeDir for CliSys {
fn env_home_dir(&self) -> Option<std::path::PathBuf> {
#[allow(clippy::disallowed_types)] // ok because sys impl
sys_traits::impls::RealSys.env_home_dir()
}
}

View file

@ -10,7 +10,6 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures; use deno_core::futures;
use deno_core::futures::future::LocalBoxFuture; use deno_core::futures::future::LocalBoxFuture;
use deno_runtime::deno_node::NodeResolver;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_task_shell::ExecutableCommand; use deno_task_shell::ExecutableCommand;
use deno_task_shell::ExecuteResult; use deno_task_shell::ExecuteResult;
@ -25,6 +24,7 @@ use tokio::task::JoinHandle;
use tokio::task::LocalSet; use tokio::task::LocalSet;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::npm::InnerCliNpmResolverRef; use crate::npm::InnerCliNpmResolverRef;
use crate::npm::ManagedCliNpmResolver; use crate::npm::ManagedCliNpmResolver;
@ -415,7 +415,7 @@ impl ShellCommand for NodeModulesFileRunCommand {
pub fn resolve_custom_commands( pub fn resolve_custom_commands(
npm_resolver: &dyn CliNpmResolver, npm_resolver: &dyn CliNpmResolver,
node_resolver: &NodeResolver, node_resolver: &CliNodeResolver,
) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> { ) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> {
let mut commands = match npm_resolver.as_inner() { let mut commands = match npm_resolver.as_inner() {
InnerCliNpmResolverRef::Byonm(npm_resolver) => { InnerCliNpmResolverRef::Byonm(npm_resolver) => {
@ -522,7 +522,7 @@ fn resolve_execution_path_from_npx_shim(
fn resolve_managed_npm_commands( fn resolve_managed_npm_commands(
npm_resolver: &ManagedCliNpmResolver, npm_resolver: &ManagedCliNpmResolver,
node_resolver: &NodeResolver, node_resolver: &CliNodeResolver,
) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> { ) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> {
let mut result = HashMap::new(); let mut result = HashMap::new();
let snapshot = npm_resolver.snapshot(); let snapshot = npm_resolver.snapshot();

View file

@ -7,6 +7,7 @@ use crate::display::write_json_to_stdout;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::graph_util::has_graph_root_local_dependent_changed; use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::ops; use crate::ops;
use crate::sys::CliSys;
use crate::tools::test::format_test_error; use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter; use crate::tools::test::TestFilter;
use crate::util::file_watcher; use crate::util::file_watcher;
@ -265,7 +266,7 @@ async fn bench_specifier_inner(
async fn bench_specifiers( async fn bench_specifiers(
worker_factory: Arc<CliMainWorkerFactory>, worker_factory: Arc<CliMainWorkerFactory>,
permissions: &Permissions, permissions: &Permissions,
permissions_desc_parser: &Arc<RuntimePermissionDescriptorParser>, permissions_desc_parser: &Arc<RuntimePermissionDescriptorParser<CliSys>>,
specifiers: Vec<ModuleSpecifier>, specifiers: Vec<ModuleSpecifier>,
options: BenchSpecifierOptions, options: BenchSpecifierOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {

View file

@ -9,7 +9,6 @@ use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_runtime::deno_node::NodeResolver;
use deno_terminal::colors; use deno_terminal::colors;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
@ -29,6 +28,7 @@ use crate::cache::TypeCheckCache;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::graph_util::BuildFastCheckGraphOptions; use crate::graph_util::BuildFastCheckGraphOptions;
use crate::graph_util::ModuleGraphBuilder; use crate::graph_util::ModuleGraphBuilder;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::tsc; use crate::tsc;
use crate::tsc::Diagnostics; use crate::tsc::Diagnostics;
@ -64,7 +64,7 @@ pub async fn check(
let file = file_fetcher.fetch(&s, root_permissions).await?; let file = file_fetcher.fetch(&s, root_permissions).await?;
let snippet_files = extract::extract_snippet_files(file)?; let snippet_files = extract::extract_snippet_files(file)?;
for snippet_file in snippet_files { for snippet_file in snippet_files {
specifiers_for_typecheck.push(snippet_file.specifier.clone()); specifiers_for_typecheck.push(snippet_file.url.clone());
file_fetcher.insert_memory_files(snippet_file); file_fetcher.insert_memory_files(snippet_file);
} }
} }
@ -103,7 +103,7 @@ pub struct TypeChecker {
cjs_tracker: Arc<TypeCheckingCjsTracker>, cjs_tracker: Arc<TypeCheckingCjsTracker>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
module_graph_builder: Arc<ModuleGraphBuilder>, module_graph_builder: Arc<ModuleGraphBuilder>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
} }
@ -113,7 +113,7 @@ impl TypeChecker {
cjs_tracker: Arc<TypeCheckingCjsTracker>, cjs_tracker: Arc<TypeCheckingCjsTracker>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
module_graph_builder: Arc<ModuleGraphBuilder>, module_graph_builder: Arc<ModuleGraphBuilder>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
) -> Self { ) -> Self {
Self { Self {

View file

@ -7,6 +7,7 @@ use std::path::Path;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::colors; use crate::colors;
use crate::display; use crate::display;
use crate::sys::CliSys;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
use crate::util::progress_bar::ProgressMessagePrompt; use crate::util::progress_bar::ProgressMessagePrompt;
@ -28,7 +29,7 @@ impl CleanState {
} }
pub fn clean() -> Result<(), AnyError> { pub fn clean() -> Result<(), AnyError> {
let deno_dir = DenoDir::new(None)?; let deno_dir = DenoDir::new(CliSys::default(), None)?;
if deno_dir.root.exists() { if deno_dir.root.exists() {
let no_of_files = walkdir::WalkDir::new(&deno_dir.root).into_iter().count(); let no_of_files = walkdir::WalkDir::new(&deno_dir.root).into_iter().count();
let progress_bar = ProgressBar::new(ProgressBarStyle::ProgressBars); let progress_bar = ProgressBar::new(ProgressBarStyle::ProgressBars);

View file

@ -5,8 +5,8 @@ use crate::args::CompileFlags;
use crate::args::Flags; use crate::args::Flags;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::standalone::binary::is_standalone_binary;
use crate::standalone::binary::WriteBinOptions; use crate::standalone::binary::WriteBinOptions;
use crate::standalone::is_standalone_binary;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;

View file

@ -6,6 +6,8 @@ use crate::args::FileFlags;
use crate::args::Flags; use crate::args::Flags;
use crate::cdp; use crate::cdp;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::TextDecodedFile;
use crate::sys::CliSys;
use crate::tools::fmt::format_json; use crate::tools::fmt::format_json;
use crate::tools::test::is_supported_test_path; use crate::tools::test::is_supported_test_path;
use crate::util::text_encoding::source_map_from_code; use crate::util::text_encoding::source_map_from_code;
@ -197,7 +199,7 @@ pub struct CoverageReport {
fn generate_coverage_report( fn generate_coverage_report(
script_coverage: &cdp::ScriptCoverage, script_coverage: &cdp::ScriptCoverage,
script_source: String, script_source: String,
maybe_source_map: &Option<Vec<u8>>, maybe_source_map: Option<&[u8]>,
output: &Option<PathBuf>, output: &Option<PathBuf>,
) -> CoverageReport { ) -> CoverageReport {
let maybe_source_map = maybe_source_map let maybe_source_map = maybe_source_map
@ -427,7 +429,7 @@ fn collect_coverages(
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned))
.collect_file_patterns(&deno_config::fs::RealDenoConfigFs, file_patterns)?; .collect_file_patterns(&CliSys::default(), file_patterns)?;
let coverage_patterns = FilePatterns { let coverage_patterns = FilePatterns {
base: initial_cwd.to_path_buf(), base: initial_cwd.to_path_buf(),
@ -559,6 +561,12 @@ pub fn cover_files(
}, },
None => None, None => None,
}; };
let get_message = |specifier: &ModuleSpecifier| -> String {
format!(
"Failed to fetch \"{}\" from cache. Before generating coverage report, run `deno test --coverage` to ensure consistent state.",
specifier,
)
};
for script_coverage in script_coverages { for script_coverage in script_coverages {
let module_specifier = deno_core::resolve_url_or_path( let module_specifier = deno_core::resolve_url_or_path(
@ -566,21 +574,14 @@ pub fn cover_files(
cli_options.initial_cwd(), cli_options.initial_cwd(),
)?; )?;
let maybe_file = if module_specifier.scheme() == "file" { let maybe_file_result = file_fetcher
file_fetcher.get_source(&module_specifier) .get_cached_source_or_local(&module_specifier)
} else { .map_err(AnyError::from);
file_fetcher let file = match maybe_file_result {
.fetch_cached(&module_specifier, 10) Ok(Some(file)) => TextDecodedFile::decode(file)?,
.with_context(|| { Ok(None) => return Err(anyhow!("{}", get_message(&module_specifier))),
format!("Failed to fetch \"{module_specifier}\" from cache.") Err(err) => return Err(err).context(get_message(&module_specifier)),
})?
}; };
let file = maybe_file.ok_or_else(|| {
anyhow!("Failed to fetch \"{}\" from cache.
Before generating coverage report, run `deno test --coverage` to ensure consistent state.",
module_specifier
)
})?.into_text_decoded()?;
let original_source = file.source.clone(); let original_source = file.source.clone();
// Check if file was transpiled // Check if file was transpiled
@ -625,7 +626,7 @@ pub fn cover_files(
let coverage_report = generate_coverage_report( let coverage_report = generate_coverage_report(
&script_coverage, &script_coverage,
runtime_code.as_str().to_owned(), runtime_code.as_str().to_owned(),
&source_map, source_map.as_deref(),
&out_mode, &out_mode,
); );

View file

@ -10,6 +10,7 @@ use crate::factory::CliFactory;
use crate::graph_util::graph_exit_integrity_errors; use crate::graph_util::graph_exit_integrity_errors;
use crate::graph_util::graph_walk_errors; use crate::graph_util::graph_walk_errors;
use crate::graph_util::GraphWalkErrorsOptions; use crate::graph_util::GraphWalkErrorsOptions;
use crate::sys::CliSys;
use crate::tsc::get_types_declaration_file_text; use crate::tsc::get_types_declaration_file_text;
use crate::util::fs::collect_specifiers; use crate::util::fs::collect_specifiers;
use deno_ast::diagnostics::Diagnostic; use deno_ast::diagnostics::Diagnostic;
@ -114,7 +115,7 @@ pub async fn doc(
} }
DocSourceFileFlag::Paths(ref source_files) => { DocSourceFileFlag::Paths(ref source_files) => {
let module_graph_creator = factory.module_graph_creator().await?; let module_graph_creator = factory.module_graph_creator().await?;
let fs = factory.fs(); let sys = CliSys::default();
let module_specifiers = collect_specifiers( let module_specifiers = collect_specifiers(
FilePatterns { FilePatterns {
@ -141,7 +142,7 @@ pub async fn doc(
graph_exit_integrity_errors(&graph); graph_exit_integrity_errors(&graph);
let errors = graph_walk_errors( let errors = graph_walk_errors(
&graph, &graph,
fs, &sys,
&module_specifiers, &module_specifiers,
GraphWalkErrorsOptions { GraphWalkErrorsOptions {
check_js: false, check_js: false,
@ -343,14 +344,14 @@ impl deno_doc::html::HrefResolver for DocResolver {
let name = &res.req().name; let name = &res.req().name;
Some(( Some((
format!("https://www.npmjs.com/package/{name}"), format!("https://www.npmjs.com/package/{name}"),
name.to_owned(), name.to_string(),
)) ))
} }
"jsr" => { "jsr" => {
let res = let res =
deno_semver::jsr::JsrPackageReqReference::from_str(module).ok()?; deno_semver::jsr::JsrPackageReqReference::from_str(module).ok()?;
let name = &res.req().name; let name = &res.req().name;
Some((format!("https://jsr.io/{name}"), name.to_owned())) Some((format!("https://jsr.io/{name}"), name.to_string()))
} }
_ => None, _ => None,
} }

View file

@ -17,6 +17,7 @@ use crate::args::UnstableFmtOptions;
use crate::cache::Caches; use crate::cache::Caches;
use crate::colors; use crate::colors;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::sys::CliSys;
use crate::util::diff::diff; use crate::util::diff::diff;
use crate::util::file_watcher; use crate::util::file_watcher;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
@ -57,7 +58,7 @@ pub async fn format(
fmt_flags: FmtFlags, fmt_flags: FmtFlags,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
if fmt_flags.is_stdin() { if fmt_flags.is_stdin() {
let cli_options = CliOptions::from_flags(flags)?; let cli_options = CliOptions::from_flags(&CliSys::default(), flags)?;
let start_dir = &cli_options.start_dir; let start_dir = &cli_options.start_dir;
let fmt_config = start_dir let fmt_config = start_dir
.to_fmt_config(FilePatterns::new_with_base(start_dir.dir_path()))?; .to_fmt_config(FilePatterns::new_with_base(start_dir.dir_path()))?;
@ -230,7 +231,7 @@ fn collect_fmt_files(
.ignore_node_modules() .ignore_node_modules()
.use_gitignore() .use_gitignore()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned))
.collect_file_patterns(&deno_config::fs::RealDenoConfigFs, files) .collect_file_patterns(&CliSys::default(), files)
} }
/// Formats markdown (using <https://github.com/dprint/dprint-plugin-markdown>) and its code blocks /// Formats markdown (using <https://github.com/dprint/dprint-plugin-markdown>) and its code blocks

View file

@ -278,8 +278,10 @@ fn add_npm_packages_to_json(
}); });
if let Some(pkg) = maybe_package { if let Some(pkg) = maybe_package {
if let Some(module) = module.as_object_mut() { if let Some(module) = module.as_object_mut() {
module module.insert(
.insert("npmPackage".to_string(), pkg.id.as_serialized().into()); "npmPackage".to_string(),
pkg.id.as_serialized().into_string().into(),
);
} }
} }
} }
@ -296,7 +298,7 @@ fn add_npm_packages_to_json(
{ {
dep.insert( dep.insert(
"npmPackage".to_string(), "npmPackage".to_string(),
pkg.id.as_serialized().into(), pkg.id.as_serialized().into_string().into(),
); );
} }
} }
@ -324,19 +326,19 @@ fn add_npm_packages_to_json(
let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len()); let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len());
for pkg in sorted_packages { for pkg in sorted_packages {
let mut kv = serde_json::Map::new(); let mut kv = serde_json::Map::new();
kv.insert("name".to_string(), pkg.id.nv.name.clone().into()); kv.insert("name".to_string(), pkg.id.nv.name.to_string().into());
kv.insert("version".to_string(), pkg.id.nv.version.to_string().into()); kv.insert("version".to_string(), pkg.id.nv.version.to_string().into());
let mut deps = pkg.dependencies.values().collect::<Vec<_>>(); let mut deps = pkg.dependencies.values().collect::<Vec<_>>();
deps.sort(); deps.sort();
let deps = deps let deps = deps
.into_iter() .into_iter()
.map(|id| serde_json::Value::String(id.as_serialized())) .map(|id| serde_json::Value::String(id.as_serialized().into_string()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
kv.insert("dependencies".to_string(), deps.into()); kv.insert("dependencies".to_string(), deps.into());
let registry_url = npmrc.get_registry_url(&pkg.id.nv.name); let registry_url = npmrc.get_registry_url(&pkg.id.nv.name);
kv.insert("registryUrl".to_string(), registry_url.to_string().into()); kv.insert("registryUrl".to_string(), registry_url.to_string().into());
json_packages.insert(pkg.id.as_serialized(), kv.into()); json_packages.insert(pkg.id.as_serialized().into_string(), kv.into());
} }
json.insert("npmPackages".to_string(), json_packages.into()); json.insert("npmPackages".to_string(), json_packages.into());
@ -549,7 +551,7 @@ impl<'a> GraphDisplayContext<'a> {
None => Specifier(module.specifier().clone()), None => Specifier(module.specifier().clone()),
}; };
let was_seen = !self.seen.insert(match &package_or_specifier { let was_seen = !self.seen.insert(match &package_or_specifier {
Package(package) => package.id.as_serialized(), Package(package) => package.id.as_serialized().into_string(),
Specifier(specifier) => specifier.to_string(), Specifier(specifier) => specifier.to_string(),
}); });
let header_text = if was_seen { let header_text = if was_seen {
@ -631,7 +633,8 @@ impl<'a> GraphDisplayContext<'a> {
)); ));
if let Some(package) = self.npm_info.packages.get(dep_id) { if let Some(package) = self.npm_info.packages.get(dep_id) {
if !package.dependencies.is_empty() { if !package.dependencies.is_empty() {
let was_seen = !self.seen.insert(package.id.as_serialized()); let was_seen =
!self.seen.insert(package.id.as_serialized().into_string());
if was_seen { if was_seen {
child.text = format!("{} {}", child.text, colors::gray("*")); child.text = format!("{} {}", child.text, colors::gray("*"));
} else { } else {

View file

@ -3,7 +3,6 @@
use crate::args::resolve_no_prompt; use crate::args::resolve_no_prompt;
use crate::args::AddFlags; use crate::args::AddFlags;
use crate::args::CaData; use crate::args::CaData;
use crate::args::CacheSetting;
use crate::args::ConfigFlag; use crate::args::ConfigFlag;
use crate::args::Flags; use crate::args::Flags;
use crate::args::InstallFlags; use crate::args::InstallFlags;
@ -13,13 +12,14 @@ use crate::args::TypeCheckMode;
use crate::args::UninstallFlags; use crate::args::UninstallFlags;
use crate::args::UninstallKind; use crate::args::UninstallKind;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::graph_container::ModuleGraphContainer; use crate::graph_container::ModuleGraphContainer;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::jsr::JsrFetchResolver; use crate::jsr::JsrFetchResolver;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::util::fs::canonicalize_path_maybe_not_exists;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error; use deno_core::error::generic_error;
@ -161,11 +161,11 @@ pub async fn infer_name_from_url(
let npm_ref = npm_ref.into_inner(); let npm_ref = npm_ref.into_inner();
if let Some(sub_path) = npm_ref.sub_path { if let Some(sub_path) = npm_ref.sub_path {
if !sub_path.contains('/') { if !sub_path.contains('/') {
return Some(sub_path); return Some(sub_path.to_string());
} }
} }
if !npm_ref.req.name.contains('/') { if !npm_ref.req.name.contains('/') {
return Some(npm_ref.req.name); return Some(npm_ref.req.name.into_string());
} }
return None; return None;
} }
@ -361,18 +361,19 @@ async fn install_global(
let cli_options = factory.cli_options()?; let cli_options = factory.cli_options()?;
let http_client = factory.http_client_provider(); let http_client = factory.http_client_provider();
let deps_http_cache = factory.global_http_cache()?; let deps_http_cache = factory.global_http_cache()?;
let mut deps_file_fetcher = FileFetcher::new( let deps_file_fetcher = CliFileFetcher::new(
deps_http_cache.clone(), deps_http_cache.clone(),
CacheSetting::ReloadAll,
true,
http_client.clone(), http_client.clone(),
factory.sys(),
Default::default(), Default::default(),
None, None,
true,
CacheSetting::ReloadAll,
log::Level::Trace,
); );
let npmrc = factory.cli_options().unwrap().npmrc(); let npmrc = factory.cli_options().unwrap().npmrc();
deps_file_fetcher.set_download_log_level(log::Level::Trace);
let deps_file_fetcher = Arc::new(deps_file_fetcher); let deps_file_fetcher = Arc::new(deps_file_fetcher);
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone())); let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
let npm_resolver = Arc::new(NpmFetchResolver::new( let npm_resolver = Arc::new(NpmFetchResolver::new(

View file

@ -0,0 +1,536 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::fmt::Display;
use deno_ast::swc::common::Span;
use deno_ast::swc::common::DUMMY_SP;
use indexmap::IndexMap;
/// Each property has this flag to mark what kind of value it holds-
/// Plain objects and arrays are not supported yet, but could be easily
/// added if needed.
#[derive(Debug, PartialEq)]
pub enum PropFlags {
Ref,
RefArr,
String,
Bool,
Null,
Undefined,
}
impl From<PropFlags> for u8 {
fn from(m: PropFlags) -> u8 {
m as u8
}
}
impl TryFrom<u8> for PropFlags {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(PropFlags::Ref),
1 => Ok(PropFlags::RefArr),
2 => Ok(PropFlags::String),
3 => Ok(PropFlags::Bool),
4 => Ok(PropFlags::Null),
5 => Ok(PropFlags::Undefined),
_ => Err("Unknown Prop flag"),
}
}
}
const MASK_U32_1: u32 = 0b11111111_00000000_00000000_00000000;
const MASK_U32_2: u32 = 0b00000000_11111111_00000000_00000000;
const MASK_U32_3: u32 = 0b00000000_00000000_11111111_00000000;
const MASK_U32_4: u32 = 0b00000000_00000000_00000000_11111111;
// TODO: There is probably a native Rust function to do this.
pub fn append_u32(result: &mut Vec<u8>, value: u32) {
let v1: u8 = ((value & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((value & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((value & MASK_U32_3) >> 8) as u8;
let v4: u8 = (value & MASK_U32_4) as u8;
result.push(v1);
result.push(v2);
result.push(v3);
result.push(v4);
}
pub fn append_usize(result: &mut Vec<u8>, value: usize) {
let raw = u32::try_from(value).unwrap();
append_u32(result, raw);
}
pub fn write_usize(result: &mut [u8], value: usize, idx: usize) {
let raw = u32::try_from(value).unwrap();
let v1: u8 = ((raw & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((raw & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((raw & MASK_U32_3) >> 8) as u8;
let v4: u8 = (raw & MASK_U32_4) as u8;
result[idx] = v1;
result[idx + 1] = v2;
result[idx + 2] = v3;
result[idx + 3] = v4;
}
#[derive(Debug)]
pub struct StringTable {
id: usize,
table: IndexMap<String, usize>,
}
impl StringTable {
pub fn new() -> Self {
Self {
id: 0,
table: IndexMap::new(),
}
}
pub fn insert(&mut self, s: &str) -> usize {
if let Some(id) = self.table.get(s) {
return *id;
}
let id = self.id;
self.id += 1;
self.table.insert(s.to_string(), id);
id
}
pub fn serialize(&mut self) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
append_u32(&mut result, self.table.len() as u32);
// Assume that it's sorted by id
for (s, _id) in &self.table {
let bytes = s.as_bytes();
append_u32(&mut result, bytes.len() as u32);
result.append(&mut bytes.to_vec());
}
result
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NodeRef(pub usize);
/// Represents an offset to a node whose schema hasn't been committed yet
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PendingNodeRef(pub NodeRef);
#[derive(Debug)]
pub struct BoolPos(pub usize);
#[derive(Debug)]
pub struct FieldPos(pub usize);
#[derive(Debug)]
pub struct FieldArrPos(pub usize);
#[derive(Debug)]
pub struct StrPos(pub usize);
#[derive(Debug)]
pub struct UndefPos(pub usize);
#[derive(Debug)]
pub struct NullPos(pub usize);
#[derive(Debug)]
pub enum NodePos {
Bool(BoolPos),
#[allow(dead_code)]
Field(FieldPos),
#[allow(dead_code)]
FieldArr(FieldArrPos),
Str(StrPos),
Undef(UndefPos),
#[allow(dead_code)]
Null(NullPos),
}
pub trait AstBufSerializer<K, P>
where
K: Into<u8> + Display,
P: Into<u8> + Display,
{
fn header(&mut self, kind: K, parent: NodeRef, span: &Span)
-> PendingNodeRef;
fn ref_field(&mut self, prop: P) -> FieldPos;
fn ref_vec_field(&mut self, prop: P, len: usize) -> FieldArrPos;
fn str_field(&mut self, prop: P) -> StrPos;
fn bool_field(&mut self, prop: P) -> BoolPos;
fn undefined_field(&mut self, prop: P) -> UndefPos;
#[allow(dead_code)]
fn null_field(&mut self, prop: P) -> NullPos;
fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef;
fn write_ref(&mut self, pos: FieldPos, value: NodeRef);
fn write_maybe_ref(&mut self, pos: FieldPos, value: Option<NodeRef>);
fn write_refs(&mut self, pos: FieldArrPos, value: Vec<NodeRef>);
fn write_str(&mut self, pos: StrPos, value: &str);
fn write_bool(&mut self, pos: BoolPos, value: bool);
fn serialize(&mut self) -> Vec<u8>;
}
#[derive(Debug)]
pub struct SerializeCtx {
buf: Vec<u8>,
start_buf: NodeRef,
str_table: StringTable,
kind_map: Vec<usize>,
prop_map: Vec<usize>,
field_count: u8,
}
/// This is the internal context used to allocate and fill the buffer. The point
/// is to be able to write absolute offsets directly in place.
///
/// The typical workflow is to reserve all necessary space for the currrent
/// node with placeholders for the offsets of the child nodes. Once child
/// nodes have been traversed, we know their offsets and can replace the
/// placeholder values with the actual ones.
impl SerializeCtx {
pub fn new(kind_len: u8, prop_len: u8) -> Self {
let kind_size = kind_len as usize;
let prop_size = prop_len as usize;
let mut ctx = Self {
start_buf: NodeRef(0),
buf: vec![],
str_table: StringTable::new(),
kind_map: vec![0; kind_size],
prop_map: vec![0; prop_size],
field_count: 0,
};
let empty_str = ctx.str_table.insert("");
// Placeholder node is always 0
ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0);
ctx.kind_map[0] = empty_str;
ctx.start_buf = NodeRef(ctx.buf.len());
// Insert default props that are always present
let type_str = ctx.str_table.insert("type");
let parent_str = ctx.str_table.insert("parent");
let range_str = ctx.str_table.insert("range");
let length_str = ctx.str_table.insert("length");
// These values are expected to be in this order on the JS side
ctx.prop_map[0] = empty_str;
ctx.prop_map[1] = type_str;
ctx.prop_map[2] = parent_str;
ctx.prop_map[3] = range_str;
ctx.prop_map[4] = length_str;
ctx
}
/// Allocate a node's header
fn field_header<P>(&mut self, prop: P, prop_flags: PropFlags) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field_count += 1;
let offset = self.buf.len();
let n: u8 = prop.clone().into();
self.buf.push(n);
if let Some(v) = self.prop_map.get::<usize>(n.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{prop}"));
self.prop_map[n as usize] = id;
}
}
let flags: u8 = prop_flags.into();
self.buf.push(flags);
offset
}
/// Allocate a property pointing to another node.
fn field<P>(&mut self, prop: P, prop_flags: PropFlags) -> usize
where
P: Into<u8> + Display + Clone,
{
let offset = self.field_header(prop, prop_flags);
append_usize(&mut self.buf, 0);
offset
}
fn append_node(
&mut self,
kind: u8,
parent: NodeRef,
span: &Span,
prop_count: usize,
) -> PendingNodeRef {
let offset = self.buf.len();
// Node type fits in a u8
self.buf.push(kind);
// Offset to the parent node. Will be 0 if none exists
append_usize(&mut self.buf, parent.0);
// Span, the start and end location of this node
append_u32(&mut self.buf, span.lo.0);
append_u32(&mut self.buf, span.hi.0);
// No node has more than <10 properties
debug_assert!(prop_count < 10);
self.buf.push(prop_count as u8);
PendingNodeRef(NodeRef(offset))
}
pub fn commit_schema(&mut self, node_ref: PendingNodeRef) -> NodeRef {
let mut offset = node_ref.0 .0;
// type + parentId + span lo + span hi
offset += 1 + 4 + 4 + 4;
self.buf[offset] = self.field_count;
self.field_count = 0;
node_ref.0
}
/// Allocate the node header. It's always the same for every node.
/// <type u8>
/// <parent offset u32>
/// <span lo u32>
/// <span high u32>
/// <property count u8> (There is no node with more than 10 properties)
pub fn header<N>(
&mut self,
kind: N,
parent: NodeRef,
span: &Span,
) -> PendingNodeRef
where
N: Into<u8> + Display + Clone,
{
let n: u8 = kind.clone().into();
if let Some(v) = self.kind_map.get::<usize>(n.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{kind}"));
self.kind_map[n as usize] = id;
}
}
// Prop count will be filled with the actual value when the
// schema is committed.
self.append_node(n, parent, span, 0)
}
/// Allocate a reference property that will hold the offset of
/// another node.
pub fn ref_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::Ref)
}
/// Allocate a property that is a vec of node offsets pointing to other
/// nodes.
pub fn ref_vec_field<P>(&mut self, prop: P, len: usize) -> usize
where
P: Into<u8> + Display + Clone,
{
let offset = self.field(prop, PropFlags::RefArr);
for _ in 0..len {
append_u32(&mut self.buf, 0);
}
offset
}
// Allocate a property representing a string. Strings are deduplicated
// in the message and the property will only contain the string id.
pub fn str_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::String)
}
/// Allocate a bool field
pub fn bool_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
let offset = self.field_header(prop, PropFlags::Bool);
self.buf.push(0);
offset
}
/// Allocate an undefined field
pub fn undefined_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Undefined)
}
/// Allocate an undefined field
#[allow(dead_code)]
pub fn null_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Null)
}
/// Replace the placeholder of a reference field with the actual offset
/// to the node we want to point to.
pub fn write_ref(&mut self, field_offset: usize, value: NodeRef) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
write_usize(&mut self.buf, value.0, field_offset + 2);
}
/// Helper for writing optional node offsets
pub fn write_maybe_ref(
&mut self,
field_offset: usize,
value: Option<NodeRef>,
) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
let ref_value = if let Some(v) = value { v } else { NodeRef(0) };
write_usize(&mut self.buf, ref_value.0, field_offset + 2);
}
/// Write a vec of node offsets into the property. The necessary space
/// has been reserved earlier.
pub fn write_refs(&mut self, field_offset: usize, value: Vec<NodeRef>) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::RefArr {
panic!("Trying to write a ref into a non-ref array field")
}
}
let mut offset = field_offset + 2;
write_usize(&mut self.buf, value.len(), offset);
offset += 4;
for item in value {
write_usize(&mut self.buf, item.0, offset);
offset += 4;
}
}
/// Store the string in our string table and save the id of the string
/// in the current field.
pub fn write_str(&mut self, field_offset: usize, value: &str) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::String {
panic!("Trying to write a ref into a non-string field")
}
}
let id = self.str_table.insert(value);
write_usize(&mut self.buf, id, field_offset + 2);
}
/// Write a bool to a field.
pub fn write_bool(&mut self, field_offset: usize, value: bool) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Bool {
panic!("Trying to write a ref into a non-bool field")
}
}
self.buf[field_offset + 2] = if value { 1 } else { 0 };
}
/// Serialize all information we have into a buffer that can be sent to JS.
/// It has the following structure:
///
/// <...ast>
/// <string table>
/// <node kind map> <- node kind id maps to string id
/// <node prop map> <- node property id maps to string id
/// <offset kind map>
/// <offset prop map>
/// <offset str table>
pub fn serialize(&mut self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![];
// The buffer starts with the serialized AST first, because that
// contains absolute offsets. By butting this at the start of the
// message we don't have to waste time updating any offsets.
buf.append(&mut self.buf);
// Next follows the string table. We'll keep track of the offset
// in the message of where the string table begins
let offset_str_table = buf.len();
// Serialize string table
buf.append(&mut self.str_table.serialize());
// Next, serialize the mappings of kind -> string of encountered
// nodes in the AST. We use this additional lookup table to compress
// the message so that we can save space by using a u8 . All nodes of
// JS, TS and JSX together are <200
let offset_kind_map = buf.len();
// Write the total number of entries in the kind -> str mapping table
// TODO: make this a u8
append_usize(&mut buf, self.kind_map.len());
for v in &self.kind_map {
append_usize(&mut buf, *v);
}
// Store offset to prop -> string map. It's the same as with node kind
// as the total number of properties is <120 which allows us to store it
// as u8.
let offset_prop_map = buf.len();
// Write the total number of entries in the kind -> str mapping table
append_usize(&mut buf, self.prop_map.len());
for v in &self.prop_map {
append_usize(&mut buf, *v);
}
// Putting offsets of relevant parts of the buffer at the end. This
// allows us to hop to the relevant part by merely looking at the last
// for values in the message. Each value represents an offset into the
// buffer.
append_usize(&mut buf, offset_kind_map);
append_usize(&mut buf, offset_prop_map);
append_usize(&mut buf, offset_str_table);
append_usize(&mut buf, self.start_buf.0);
buf
}
}

View file

@ -0,0 +1,13 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_ast::ParsedSource;
use swc::serialize_swc_to_buffer;
mod buffer;
mod swc;
mod ts_estree;
pub fn serialize_ast_to_buffer(parsed_source: &ParsedSource) -> Vec<u8> {
// TODO: We could support multiple languages here
serialize_swc_to_buffer(parsed_source)
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,520 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use deno_ast::swc::common::Span;
use super::buffer::AstBufSerializer;
use super::buffer::BoolPos;
use super::buffer::FieldArrPos;
use super::buffer::FieldPos;
use super::buffer::NodeRef;
use super::buffer::NullPos;
use super::buffer::PendingNodeRef;
use super::buffer::SerializeCtx;
use super::buffer::StrPos;
use super::buffer::UndefPos;
#[derive(Debug, Clone, PartialEq)]
pub enum AstNode {
// First node must always be the empty/invalid node
Invalid,
// Typically the
Program,
// Module declarations
ExportAllDeclaration,
ExportDefaultDeclaration,
ExportNamedDeclaration,
ImportDeclaration,
TsExportAssignment,
TsImportEquals,
TsNamespaceExport,
// Decls
ClassDeclaration,
FunctionDeclaration,
TSEnumDeclaration,
TSInterface,
TsModule,
TsTypeAlias,
Using,
VariableDeclaration,
// Statements
BlockStatement,
BreakStatement,
ContinueStatement,
DebuggerStatement,
DoWhileStatement,
EmptyStatement,
ExpressionStatement,
ForInStatement,
ForOfStatement,
ForStatement,
IfStatement,
LabeledStatement,
ReturnStatement,
SwitchCase,
SwitchStatement,
ThrowStatement,
TryStatement,
WhileStatement,
WithStatement,
// Expressions
ArrayExpression,
ArrowFunctionExpression,
AssignmentExpression,
AwaitExpression,
BinaryExpression,
CallExpression,
ChainExpression,
ClassExpression,
ConditionalExpression,
FunctionExpression,
Identifier,
ImportExpression,
LogicalExpression,
MemberExpression,
MetaProp,
NewExpression,
ObjectExpression,
PrivateIdentifier,
SequenceExpression,
Super,
TaggedTemplateExpression,
TemplateLiteral,
ThisExpression,
TSAsExpression,
TsConstAssertion,
TsInstantiation,
TSNonNullExpression,
TSSatisfiesExpression,
TSTypeAssertion,
UnaryExpression,
UpdateExpression,
YieldExpression,
// TODO: TSEsTree uses a single literal node
// Literals
StringLiteral,
Bool,
Null,
NumericLiteral,
BigIntLiteral,
RegExpLiteral,
EmptyExpr,
SpreadElement,
Property,
VariableDeclarator,
CatchClause,
RestElement,
ExportSpecifier,
TemplateElement,
MethodDefinition,
ClassBody,
// Patterns
ArrayPattern,
AssignmentPattern,
ObjectPattern,
// JSX
JSXAttribute,
JSXClosingElement,
JSXClosingFragment,
JSXElement,
JSXEmptyExpression,
JSXExpressionContainer,
JSXFragment,
JSXIdentifier,
JSXMemberExpression,
JSXNamespacedName,
JSXOpeningElement,
JSXOpeningFragment,
JSXSpreadAttribute,
JSXSpreadChild,
JSXText,
TSTypeAnnotation,
TSTypeParameterDeclaration,
TSTypeParameter,
TSTypeParameterInstantiation,
TSEnumMember,
TSInterfaceBody,
TSInterfaceHeritage,
TSTypeReference,
TSThisType,
TSLiteralType,
TSInferType,
TSConditionalType,
TSUnionType,
TSIntersectionType,
TSMappedType,
TSTypeQuery,
TSTupleType,
TSNamedTupleMember,
TSFunctionType,
TsCallSignatureDeclaration,
TSPropertySignature,
TSMethodSignature,
TSIndexSignature,
TSIndexedAccessType,
TSTypeOperator,
TSTypePredicate,
TSImportType,
TSRestType,
TSArrayType,
TSClassImplements,
TSAnyKeyword,
TSBigIntKeyword,
TSBooleanKeyword,
TSIntrinsicKeyword,
TSNeverKeyword,
TSNullKeyword,
TSNumberKeyword,
TSObjectKeyword,
TSStringKeyword,
TSSymbolKeyword,
TSUndefinedKeyword,
TSUnknownKeyword,
TSVoidKeyword,
TSEnumBody, // Last value is used for max value
}
impl Display for AstNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
impl From<AstNode> for u8 {
fn from(m: AstNode) -> u8 {
m as u8
}
}
#[derive(Debug, Clone)]
pub enum AstProp {
// Base, these must be in sync with JS in the same order.
Invalid,
Type,
Parent,
Range,
Length, // Not used in AST, but can be used in attr selectors
// Starting from here the order doesn't matter.
// Following are all possible AST node properties.
Abstract,
Accessibility,
Alternate,
Argument,
Arguments,
Asserts,
Async,
Attributes,
Await,
Block,
Body,
Callee,
Cases,
Children,
CheckType,
ClosingElement,
ClosingFragment,
Computed,
Consequent,
Const,
Constraint,
Cooked,
Declaration,
Declarations,
Declare,
Default,
Definite,
Delegate,
Discriminant,
Elements,
ElementType,
ElementTypes,
ExprName,
Expression,
Expressions,
Exported,
Extends,
ExtendsType,
FalseType,
Finalizer,
Flags,
Generator,
Handler,
Id,
In,
IndexType,
Init,
Initializer,
Implements,
Key,
Kind,
Label,
Left,
Literal,
Local,
Members,
Meta,
Method,
Name,
Namespace,
NameType,
Object,
ObjectType,
OpeningElement,
OpeningFragment,
Operator,
Optional,
Out,
Param,
ParameterName,
Params,
Pattern,
Prefix,
Properties,
Property,
Qualifier,
Quasi,
Quasis,
Raw,
Readonly,
ReturnType,
Right,
SelfClosing,
Shorthand,
Source,
SourceType,
Specifiers,
Static,
SuperClass,
SuperTypeArguments,
Tag,
Tail,
Test,
TrueType,
TypeAnnotation,
TypeArguments,
TypeName,
TypeParameter,
TypeParameters,
Types,
Update,
Value, // Last value is used for max value
}
// TODO: Feels like there should be an easier way to iterater over an
// enum in Rust and lowercase the first letter.
impl Display for AstProp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
AstProp::Invalid => "__invalid__", // unused
AstProp::Parent => "parent",
AstProp::Range => "range",
AstProp::Type => "type",
AstProp::Length => "length",
AstProp::Abstract => "abstract",
AstProp::Accessibility => "accessibility",
AstProp::Alternate => "alternate",
AstProp::Argument => "argument",
AstProp::Arguments => "arguments",
AstProp::Asserts => "asserts",
AstProp::Async => "async",
AstProp::Attributes => "attributes",
AstProp::Await => "await",
AstProp::Block => "block",
AstProp::Body => "body",
AstProp::Callee => "callee",
AstProp::Cases => "cases",
AstProp::Children => "children",
AstProp::CheckType => "checkType",
AstProp::ClosingElement => "closingElement",
AstProp::ClosingFragment => "closingFragment",
AstProp::Computed => "computed",
AstProp::Consequent => "consequent",
AstProp::Const => "const",
AstProp::Constraint => "constraint",
AstProp::Cooked => "cooked",
AstProp::Declaration => "declaration",
AstProp::Declarations => "declarations",
AstProp::Declare => "declare",
AstProp::Default => "default",
AstProp::Definite => "definite",
AstProp::Delegate => "delegate",
AstProp::Discriminant => "discriminant",
AstProp::Elements => "elements",
AstProp::ElementType => "elementType",
AstProp::ElementTypes => "elementTypes",
AstProp::ExprName => "exprName",
AstProp::Expression => "expression",
AstProp::Expressions => "expressions",
AstProp::Exported => "exported",
AstProp::Extends => "extends",
AstProp::ExtendsType => "extendsType",
AstProp::FalseType => "falseType",
AstProp::Finalizer => "finalizer",
AstProp::Flags => "flags",
AstProp::Generator => "generator",
AstProp::Handler => "handler",
AstProp::Id => "id",
AstProp::In => "in",
AstProp::IndexType => "indexType",
AstProp::Init => "init",
AstProp::Initializer => "initializer",
AstProp::Implements => "implements",
AstProp::Key => "key",
AstProp::Kind => "kind",
AstProp::Label => "label",
AstProp::Left => "left",
AstProp::Literal => "literal",
AstProp::Local => "local",
AstProp::Members => "members",
AstProp::Meta => "meta",
AstProp::Method => "method",
AstProp::Name => "name",
AstProp::Namespace => "namespace",
AstProp::NameType => "nameType",
AstProp::Object => "object",
AstProp::ObjectType => "objectType",
AstProp::OpeningElement => "openingElement",
AstProp::OpeningFragment => "openingFragment",
AstProp::Operator => "operator",
AstProp::Optional => "optional",
AstProp::Out => "out",
AstProp::Param => "param",
AstProp::ParameterName => "parameterName",
AstProp::Params => "params",
AstProp::Pattern => "pattern",
AstProp::Prefix => "prefix",
AstProp::Properties => "properties",
AstProp::Property => "property",
AstProp::Qualifier => "qualifier",
AstProp::Quasi => "quasi",
AstProp::Quasis => "quasis",
AstProp::Raw => "raw",
AstProp::Readonly => "readonly",
AstProp::ReturnType => "returnType",
AstProp::Right => "right",
AstProp::SelfClosing => "selfClosing",
AstProp::Shorthand => "shorthand",
AstProp::Source => "source",
AstProp::SourceType => "sourceType",
AstProp::Specifiers => "specifiers",
AstProp::Static => "static",
AstProp::SuperClass => "superClass",
AstProp::SuperTypeArguments => "superTypeArguments",
AstProp::Tag => "tag",
AstProp::Tail => "tail",
AstProp::Test => "test",
AstProp::TrueType => "trueType",
AstProp::TypeAnnotation => "typeAnnotation",
AstProp::TypeArguments => "typeArguments",
AstProp::TypeName => "typeName",
AstProp::TypeParameter => "typeParameter",
AstProp::TypeParameters => "typeParameters",
AstProp::Types => "types",
AstProp::Update => "update",
AstProp::Value => "value",
};
write!(f, "{}", s)
}
}
impl From<AstProp> for u8 {
fn from(m: AstProp) -> u8 {
m as u8
}
}
pub struct TsEsTreeBuilder {
ctx: SerializeCtx,
}
// TODO: Add a builder API to make it easier to convert from different source
// ast formats.
impl TsEsTreeBuilder {
pub fn new() -> Self {
// Max values
// TODO: Maybe there is a rust macro to grab the last enum value?
let kind_max_count: u8 = u8::from(AstNode::TSEnumBody) + 1;
let prop_max_count: u8 = u8::from(AstProp::Value) + 1;
Self {
ctx: SerializeCtx::new(kind_max_count, prop_max_count),
}
}
}
impl AstBufSerializer<AstNode, AstProp> for TsEsTreeBuilder {
fn header(
&mut self,
kind: AstNode,
parent: NodeRef,
span: &Span,
) -> PendingNodeRef {
self.ctx.header(kind, parent, span)
}
fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef {
self.ctx.commit_schema(offset)
}
fn ref_field(&mut self, prop: AstProp) -> FieldPos {
FieldPos(self.ctx.ref_field(prop))
}
fn ref_vec_field(&mut self, prop: AstProp, len: usize) -> FieldArrPos {
FieldArrPos(self.ctx.ref_vec_field(prop, len))
}
fn str_field(&mut self, prop: AstProp) -> StrPos {
StrPos(self.ctx.str_field(prop))
}
fn bool_field(&mut self, prop: AstProp) -> BoolPos {
BoolPos(self.ctx.bool_field(prop))
}
fn undefined_field(&mut self, prop: AstProp) -> UndefPos {
UndefPos(self.ctx.undefined_field(prop))
}
fn null_field(&mut self, prop: AstProp) -> NullPos {
NullPos(self.ctx.null_field(prop))
}
fn write_ref(&mut self, pos: FieldPos, value: NodeRef) {
self.ctx.write_ref(pos.0, value);
}
fn write_maybe_ref(&mut self, pos: FieldPos, value: Option<NodeRef>) {
self.ctx.write_maybe_ref(pos.0, value);
}
fn write_refs(&mut self, pos: FieldArrPos, value: Vec<NodeRef>) {
self.ctx.write_refs(pos.0, value);
}
fn write_str(&mut self, pos: StrPos, value: &str) {
self.ctx.write_str(pos.0, value);
}
fn write_bool(&mut self, pos: BoolPos, value: bool) {
self.ctx.write_bool(pos.0, value);
}
fn serialize(&mut self) -> Vec<u8> {
self.ctx.serialize()
}
}

View file

@ -15,8 +15,9 @@ use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_lint::linter::LintFileOptions; use deno_lint::linter::LintFileOptions;
use deno_lint::linter::Linter as DenoLintLinter; use deno_lint::linter::Linter as DenoLintLinter;
use deno_lint::linter::LinterOptions; use deno_lint::linter::LinterOptions;
use deno_path_util::fs::atomic_write_file_with_retries;
use crate::util::fs::atomic_write_file_with_retries; use crate::sys::CliSys;
use crate::util::fs::specifier_from_file_path; use crate::util::fs::specifier_from_file_path;
use super::rules::FileOrPackageLintRule; use super::rules::FileOrPackageLintRule;
@ -176,8 +177,9 @@ impl CliLinter {
if fix_iterations > 0 { if fix_iterations > 0 {
// everything looks good and the file still parses, so write it out // everything looks good and the file still parses, so write it out
atomic_write_file_with_retries( atomic_write_file_with_retries(
&CliSys::default(),
file_path, file_path,
source.text().as_ref(), source.text().as_bytes(),
crate::cache::CACHE_PERM, crate::cache::CACHE_PERM,
) )
.context("Failed writing fix to file.")?; .context("Failed writing fix to file.")?;

View file

@ -20,7 +20,7 @@ use deno_core::unsync::future::LocalFutureExt;
use deno_core::unsync::future::SharedLocal; use deno_core::unsync::future::SharedLocal;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_lint::diagnostic::LintDiagnostic; use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::linter::LintConfig; use deno_lint::linter::LintConfig as DenoLintConfig;
use log::debug; use log::debug;
use reporters::create_reporter; use reporters::create_reporter;
use reporters::LintReporter; use reporters::LintReporter;
@ -29,7 +29,6 @@ use std::collections::HashSet;
use std::fs; use std::fs;
use std::io::stdin; use std::io::stdin;
use std::io::Read; use std::io::Read;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -44,17 +43,22 @@ use crate::cache::IncrementalCache;
use crate::colors; use crate::colors;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::graph_util::ModuleGraphCreator; use crate::graph_util::ModuleGraphCreator;
use crate::sys::CliSys;
use crate::tools::fmt::run_parallelized; use crate::tools::fmt::run_parallelized;
use crate::util::display; use crate::util::display;
use crate::util::file_watcher; use crate::util::file_watcher;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
use crate::util::path::is_script_ext; use crate::util::path::is_script_ext;
use crate::util::sync::AtomicFlag; use crate::util::sync::AtomicFlag;
mod ast_buffer;
mod linter; mod linter;
mod reporters; mod reporters;
mod rules; mod rules;
// TODO(bartlomieju): remove once we wire plugins through the CLI linter
pub use ast_buffer::serialize_ast_to_buffer;
pub use linter::CliLinter; pub use linter::CliLinter;
pub use linter::CliLinterOptions; pub use linter::CliLinterOptions;
pub use rules::collect_no_slow_type_diagnostics; pub use rules::collect_no_slow_type_diagnostics;
@ -69,136 +73,139 @@ pub async fn lint(
flags: Arc<Flags>, flags: Arc<Flags>,
lint_flags: LintFlags, lint_flags: LintFlags,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
if let Some(watch_flags) = &lint_flags.watch { if lint_flags.watch.is_some() {
if lint_flags.is_stdin() { if lint_flags.is_stdin() {
return Err(generic_error( return Err(generic_error(
"Lint watch on standard input is not supported.", "Lint watch on standard input is not supported.",
)); ));
} }
file_watcher::watch_func(
flags,
file_watcher::PrintConfig::new("Lint", !watch_flags.no_clear_screen),
move |flags, watcher_communicator, changed_paths| {
let lint_flags = lint_flags.clone();
watcher_communicator.show_path_changed(changed_paths.clone());
Ok(async move {
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
let lint_config = cli_options.resolve_deno_lint_config()?;
let mut paths_with_options_batches =
resolve_paths_with_options_batches(cli_options, &lint_flags)?;
for paths_with_options in &mut paths_with_options_batches {
_ = watcher_communicator
.watch_paths(paths_with_options.paths.clone());
let files = std::mem::take(&mut paths_with_options.paths); return lint_with_watch(flags, lint_flags).await;
paths_with_options.paths = if let Some(paths) = &changed_paths { }
// lint all files on any changed (https://github.com/denoland/deno/issues/12446)
files
.iter()
.any(|path| {
canonicalize_path(path)
.map(|p| paths.contains(&p))
.unwrap_or(false)
})
.then_some(files)
.unwrap_or_else(|| [].to_vec())
} else {
files
};
}
let mut linter = WorkspaceLinter::new( let factory = CliFactory::from_flags(flags);
factory.caches()?.clone(), let cli_options = factory.cli_options()?;
factory.lint_rule_provider().await?, let lint_rule_provider = factory.lint_rule_provider().await?;
factory.module_graph_creator().await?.clone(), let is_stdin = lint_flags.is_stdin();
cli_options.start_dir.clone(), let deno_lint_config = cli_options.resolve_deno_lint_config()?;
&cli_options.resolve_workspace_lint_options(&lint_flags)?, let workspace_lint_options =
); cli_options.resolve_workspace_lint_options(&lint_flags)?;
for paths_with_options in paths_with_options_batches { let success = if is_stdin {
linter lint_stdin(
.lint_files( cli_options,
cli_options, lint_rule_provider,
paths_with_options.options, workspace_lint_options,
lint_config.clone(), lint_flags,
paths_with_options.dir, deno_lint_config,
paths_with_options.paths, )?
)
.await?;
}
linter.finish();
Ok(())
})
},
)
.await?;
} else { } else {
let factory = CliFactory::from_flags(flags); let mut linter = WorkspaceLinter::new(
let cli_options = factory.cli_options()?; factory.caches()?.clone(),
let is_stdin = lint_flags.is_stdin(); lint_rule_provider,
let deno_lint_config = cli_options.resolve_deno_lint_config()?; factory.module_graph_creator().await?.clone(),
let workspace_lint_options = cli_options.start_dir.clone(),
cli_options.resolve_workspace_lint_options(&lint_flags)?; &workspace_lint_options,
let success = if is_stdin { );
let start_dir = &cli_options.start_dir; let paths_with_options_batches =
let reporter_lock = Arc::new(Mutex::new(create_reporter( resolve_paths_with_options_batches(cli_options, &lint_flags)?;
workspace_lint_options.reporter_kind, for paths_with_options in paths_with_options_batches {
))); linter
let lint_config = start_dir .lint_files(
.to_lint_config(FilePatterns::new_with_base(start_dir.dir_path()))?; cli_options,
let lint_options = LintOptions::resolve(lint_config, &lint_flags); paths_with_options.options,
let lint_rules = factory deno_lint_config.clone(),
.lint_rule_provider() paths_with_options.dir,
.await? paths_with_options.paths,
.resolve_lint_rules_err_empty( )
lint_options.rules, .await?;
start_dir.maybe_deno_json().map(|c| c.as_ref()),
)?;
let mut file_path = cli_options.initial_cwd().join(STDIN_FILE_NAME);
if let Some(ext) = cli_options.ext_flag() {
file_path.set_extension(ext);
}
let r = lint_stdin(&file_path, lint_rules, deno_lint_config);
let success = handle_lint_result(
&file_path.to_string_lossy(),
r,
reporter_lock.clone(),
);
reporter_lock.lock().close(1);
success
} else {
let mut linter = WorkspaceLinter::new(
factory.caches()?.clone(),
factory.lint_rule_provider().await?,
factory.module_graph_creator().await?.clone(),
cli_options.start_dir.clone(),
&workspace_lint_options,
);
let paths_with_options_batches =
resolve_paths_with_options_batches(cli_options, &lint_flags)?;
for paths_with_options in paths_with_options_batches {
linter
.lint_files(
cli_options,
paths_with_options.options,
deno_lint_config.clone(),
paths_with_options.dir,
paths_with_options.paths,
)
.await?;
}
linter.finish()
};
if !success {
deno_runtime::exit(1);
} }
linter.finish()
};
if !success {
deno_runtime::exit(1);
} }
Ok(()) Ok(())
} }
async fn lint_with_watch_inner(
flags: Arc<Flags>,
lint_flags: LintFlags,
watcher_communicator: Arc<WatcherCommunicator>,
changed_paths: Option<Vec<PathBuf>>,
) -> Result<(), AnyError> {
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
let lint_config = cli_options.resolve_deno_lint_config()?;
let mut paths_with_options_batches =
resolve_paths_with_options_batches(cli_options, &lint_flags)?;
for paths_with_options in &mut paths_with_options_batches {
_ = watcher_communicator.watch_paths(paths_with_options.paths.clone());
let files = std::mem::take(&mut paths_with_options.paths);
paths_with_options.paths = if let Some(paths) = &changed_paths {
// lint all files on any changed (https://github.com/denoland/deno/issues/12446)
files
.iter()
.any(|path| {
canonicalize_path(path)
.map(|p| paths.contains(&p))
.unwrap_or(false)
})
.then_some(files)
.unwrap_or_else(|| [].to_vec())
} else {
files
};
}
let mut linter = WorkspaceLinter::new(
factory.caches()?.clone(),
factory.lint_rule_provider().await?,
factory.module_graph_creator().await?.clone(),
cli_options.start_dir.clone(),
&cli_options.resolve_workspace_lint_options(&lint_flags)?,
);
for paths_with_options in paths_with_options_batches {
linter
.lint_files(
cli_options,
paths_with_options.options,
lint_config.clone(),
paths_with_options.dir,
paths_with_options.paths,
)
.await?;
}
linter.finish();
Ok(())
}
async fn lint_with_watch(
flags: Arc<Flags>,
lint_flags: LintFlags,
) -> Result<(), AnyError> {
let watch_flags = lint_flags.watch.as_ref().unwrap();
file_watcher::watch_func(
flags,
file_watcher::PrintConfig::new("Lint", !watch_flags.no_clear_screen),
move |flags, watcher_communicator, changed_paths| {
let lint_flags = lint_flags.clone();
watcher_communicator.show_path_changed(changed_paths.clone());
Ok(lint_with_watch_inner(
flags,
lint_flags,
watcher_communicator,
changed_paths,
))
},
)
.await
}
struct PathsWithOptions { struct PathsWithOptions {
dir: WorkspaceDirectory, dir: WorkspaceDirectory,
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
@ -269,7 +276,7 @@ impl WorkspaceLinter {
&mut self, &mut self,
cli_options: &Arc<CliOptions>, cli_options: &Arc<CliOptions>,
lint_options: LintOptions, lint_options: LintOptions,
lint_config: LintConfig, lint_config: DenoLintConfig,
member_dir: WorkspaceDirectory, member_dir: WorkspaceDirectory,
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
@ -294,112 +301,63 @@ impl WorkspaceLinter {
deno_lint_config: lint_config, deno_lint_config: lint_config,
})); }));
let has_error = self.has_error.clone();
let reporter_lock = self.reporter_lock.clone();
let mut futures = Vec::with_capacity(2); let mut futures = Vec::with_capacity(2);
if linter.has_package_rules() { if linter.has_package_rules() {
if self.workspace_module_graph.is_none() { if let Some(fut) = self.run_package_rules(&linter, &member_dir, &paths) {
let module_graph_creator = self.module_graph_creator.clone(); futures.push(fut);
let packages = self.workspace_dir.jsr_packages_for_publish();
self.workspace_module_graph = Some(
async move {
module_graph_creator
.create_and_validate_publish_graph(&packages, true)
.await
.map(Rc::new)
.map_err(Rc::new)
}
.boxed_local()
.shared_local(),
);
}
let workspace_module_graph_future =
self.workspace_module_graph.as_ref().unwrap().clone();
let publish_config = member_dir.maybe_package_config();
if let Some(publish_config) = publish_config {
let has_error = self.has_error.clone();
let reporter_lock = self.reporter_lock.clone();
let linter = linter.clone();
let path_urls = paths
.iter()
.filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
.collect::<HashSet<_>>();
futures.push(
async move {
let graph = workspace_module_graph_future
.await
.map_err(|err| anyhow!("{:#}", err))?;
let export_urls =
publish_config.config_file.resolve_export_value_urls()?;
if !export_urls.iter().any(|url| path_urls.contains(url)) {
return Ok(()); // entrypoint is not specified, so skip
}
let diagnostics = linter.lint_package(&graph, &export_urls);
if !diagnostics.is_empty() {
has_error.raise();
let mut reporter = reporter_lock.lock();
for diagnostic in &diagnostics {
reporter.visit_diagnostic(diagnostic);
}
}
Ok(())
}
.boxed_local(),
);
} }
} }
futures.push({ let maybe_incremental_cache_ = maybe_incremental_cache.clone();
let has_error = self.has_error.clone(); let linter = linter.clone();
let reporter_lock = self.reporter_lock.clone(); let cli_options = cli_options.clone();
let maybe_incremental_cache = maybe_incremental_cache.clone(); let fut = async move {
let linter = linter.clone(); let operation = move |file_path: PathBuf| {
let cli_options = cli_options.clone(); let file_text = deno_ast::strip_bom(fs::read_to_string(&file_path)?);
async move {
run_parallelized(paths, {
move |file_path| {
let file_text =
deno_ast::strip_bom(fs::read_to_string(&file_path)?);
// don't bother rechecking this file if it didn't have any diagnostics before // don't bother rechecking this file if it didn't have any diagnostics before
if let Some(incremental_cache) = &maybe_incremental_cache { if let Some(incremental_cache) = &maybe_incremental_cache_ {
if incremental_cache.is_file_same(&file_path, &file_text) { if incremental_cache.is_file_same(&file_path, &file_text) {
return Ok(()); return Ok(());
}
}
let r = linter.lint_file(
&file_path,
file_text,
cli_options.ext_flag().as_deref(),
);
if let Ok((file_source, file_diagnostics)) = &r {
if let Some(incremental_cache) = &maybe_incremental_cache {
if file_diagnostics.is_empty() {
// update the incremental cache if there were no diagnostics
incremental_cache.update_file(
&file_path,
// ensure the returned text is used here as it may have been modified via --fix
file_source.text(),
)
}
}
}
let success = handle_lint_result(
&file_path.to_string_lossy(),
r,
reporter_lock.clone(),
);
if !success {
has_error.raise();
}
Ok(())
} }
}) }
.await
} let r = linter.lint_file(
.boxed_local() &file_path,
}); file_text,
cli_options.ext_flag().as_deref(),
);
if let Ok((file_source, file_diagnostics)) = &r {
if let Some(incremental_cache) = &maybe_incremental_cache_ {
if file_diagnostics.is_empty() {
// update the incremental cache if there were no diagnostics
incremental_cache.update_file(
&file_path,
// ensure the returned text is used here as it may have been modified via --fix
file_source.text(),
)
}
}
}
let success = handle_lint_result(
&file_path.to_string_lossy(),
r,
reporter_lock.clone(),
);
if !success {
has_error.raise();
}
Ok(())
};
run_parallelized(paths, operation).await
}
.boxed_local();
futures.push(fut);
if lint_options.fix { if lint_options.fix {
// run sequentially when using `--fix` to lower the chances of weird // run sequentially when using `--fix` to lower the chances of weird
@ -419,6 +377,63 @@ impl WorkspaceLinter {
Ok(()) Ok(())
} }
fn run_package_rules(
&mut self,
linter: &Arc<CliLinter>,
member_dir: &WorkspaceDirectory,
paths: &[PathBuf],
) -> Option<LocalBoxFuture<Result<(), AnyError>>> {
if self.workspace_module_graph.is_none() {
let module_graph_creator = self.module_graph_creator.clone();
let packages = self.workspace_dir.jsr_packages_for_publish();
self.workspace_module_graph = Some(
async move {
module_graph_creator
.create_and_validate_publish_graph(&packages, true)
.await
.map(Rc::new)
.map_err(Rc::new)
}
.boxed_local()
.shared_local(),
);
}
let workspace_module_graph_future =
self.workspace_module_graph.as_ref().unwrap().clone();
let maybe_publish_config = member_dir.maybe_package_config();
let publish_config = maybe_publish_config?;
let has_error = self.has_error.clone();
let reporter_lock = self.reporter_lock.clone();
let linter = linter.clone();
let path_urls = paths
.iter()
.filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
.collect::<HashSet<_>>();
let fut = async move {
let graph = workspace_module_graph_future
.await
.map_err(|err| anyhow!("{:#}", err))?;
let export_urls =
publish_config.config_file.resolve_export_value_urls()?;
if !export_urls.iter().any(|url| path_urls.contains(url)) {
return Ok(()); // entrypoint is not specified, so skip
}
let diagnostics = linter.lint_package(&graph, &export_urls);
if !diagnostics.is_empty() {
has_error.raise();
let mut reporter = reporter_lock.lock();
for diagnostic in &diagnostics {
reporter.visit_diagnostic(diagnostic);
}
}
Ok(())
}
.boxed_local();
Some(fut)
}
pub fn finish(self) -> bool { pub fn finish(self) -> bool {
debug!("Found {} files", self.file_count); debug!("Found {} files", self.file_count);
self.reporter_lock.lock().close(self.file_count); self.reporter_lock.lock().close(self.file_count);
@ -438,7 +453,7 @@ fn collect_lint_files(
.ignore_node_modules() .ignore_node_modules()
.use_gitignore() .use_gitignore()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned))
.collect_file_patterns(&deno_config::fs::RealDenoConfigFs, files) .collect_file_patterns(&CliSys::default(), files)
} }
#[allow(clippy::print_stdout)] #[allow(clippy::print_stdout)]
@ -494,10 +509,27 @@ pub fn print_rules_list(json: bool, maybe_rules_tags: Option<Vec<String>>) {
/// Treats input as TypeScript. /// Treats input as TypeScript.
/// Compatible with `--json` flag. /// Compatible with `--json` flag.
fn lint_stdin( fn lint_stdin(
file_path: &Path, cli_options: &Arc<CliOptions>,
configured_rules: ConfiguredRules, lint_rule_provider: LintRuleProvider,
deno_lint_config: LintConfig, workspace_lint_options: WorkspaceLintOptions,
) -> Result<(ParsedSource, Vec<LintDiagnostic>), AnyError> { lint_flags: LintFlags,
deno_lint_config: DenoLintConfig,
) -> Result<bool, AnyError> {
let start_dir = &cli_options.start_dir;
let reporter_lock = Arc::new(Mutex::new(create_reporter(
workspace_lint_options.reporter_kind,
)));
let lint_config = start_dir
.to_lint_config(FilePatterns::new_with_base(start_dir.dir_path()))?;
let lint_options = LintOptions::resolve(lint_config, &lint_flags);
let configured_rules = lint_rule_provider.resolve_lint_rules_err_empty(
lint_options.rules,
start_dir.maybe_deno_json().map(|c| c.as_ref()),
)?;
let mut file_path = cli_options.initial_cwd().join(STDIN_FILE_NAME);
if let Some(ext) = cli_options.ext_flag() {
file_path.set_extension(ext);
}
let mut source_code = String::new(); let mut source_code = String::new();
if stdin().read_to_string(&mut source_code).is_err() { if stdin().read_to_string(&mut source_code).is_err() {
return Err(generic_error("Failed to read from stdin")); return Err(generic_error("Failed to read from stdin"));
@ -509,9 +541,14 @@ fn lint_stdin(
deno_lint_config, deno_lint_config,
}); });
linter let r = linter
.lint_file(file_path, deno_ast::strip_bom(source_code), None) .lint_file(&file_path, deno_ast::strip_bom(source_code), None)
.map_err(AnyError::from) .map_err(AnyError::from);
let success =
handle_lint_result(&file_path.to_string_lossy(), r, reporter_lock.clone());
reporter_lock.lock().close(1);
Ok(success)
} }
fn handle_lint_result( fn handle_lint_result(

View file

@ -26,6 +26,7 @@ use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::serde_json::Value; use deno_core::serde_json::Value;
use deno_core::url::Url; use deno_core::url::Url;
use deno_runtime::deno_fetch;
use deno_terminal::colors; use deno_terminal::colors;
use http_body_util::BodyExt; use http_body_util::BodyExt;
use serde::Deserialize; use serde::Deserialize;
@ -911,9 +912,7 @@ async fn publish_package(
package.config package.config
); );
let body = http_body_util::Full::new(package.tarball.bytes.clone()) let body = deno_fetch::ReqBody::full(package.tarball.bytes.clone());
.map_err(|never| match never {})
.boxed();
let response = http_client let response = http_client
.post(url.parse()?, body)? .post(url.parse()?, body)?
.header( .header(

View file

@ -6,6 +6,7 @@ use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::sys::CliSys;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_config::glob::FileCollector; use deno_config::glob::FileCollector;
@ -323,11 +324,11 @@ fn collect_paths(
file_patterns: FilePatterns, file_patterns: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> { ) -> Result<Vec<PathBuf>, AnyError> {
FileCollector::new(|e| { FileCollector::new(|e| {
if !e.metadata.is_file { if !e.metadata.file_type().is_file() {
if let Ok(specifier) = ModuleSpecifier::from_file_path(e.path) { if let Ok(specifier) = ModuleSpecifier::from_file_path(e.path) {
diagnostics_collector.push(PublishDiagnostic::UnsupportedFileType { diagnostics_collector.push(PublishDiagnostic::UnsupportedFileType {
specifier, specifier,
kind: if e.metadata.is_symlink { kind: if e.metadata.file_type().is_symlink() {
"symlink".to_string() "symlink".to_string()
} else { } else {
"Unknown".to_string() "Unknown".to_string()
@ -345,5 +346,5 @@ fn collect_paths(
.ignore_node_modules() .ignore_node_modules()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned))
.use_gitignore() .use_gitignore()
.collect_file_patterns(&deno_config::fs::RealDenoConfigFs, file_patterns) .collect_file_patterns(&CliSys::default(), file_patterns)
} }

View file

@ -4,6 +4,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -14,6 +15,7 @@ use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::Version; use deno_semver::Version;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use deps::KeyPath; use deps::KeyPath;
@ -23,12 +25,11 @@ use jsonc_parser::cst::CstRootNode;
use jsonc_parser::json; use jsonc_parser::json;
use crate::args::AddFlags; use crate::args::AddFlags;
use crate::args::CacheSetting;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::RemoveFlags; use crate::args::RemoveFlags;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::jsr::JsrFetchResolver; use crate::jsr::JsrFetchResolver;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
@ -283,7 +284,7 @@ fn package_json_dependency_entry(
(npm_package.into(), selected.version_req) (npm_package.into(), selected.version_req)
} else { } else {
( (
selected.import_name, selected.import_name.into_string(),
format!("npm:{}@{}", npm_package, selected.version_req), format!("npm:{}@{}", npm_package, selected.version_req),
) )
} }
@ -292,7 +293,7 @@ fn package_json_dependency_entry(
let scope_replaced = jsr_package.replace('/', "__"); let scope_replaced = jsr_package.replace('/', "__");
let version_req = let version_req =
format!("npm:@jsr/{scope_replaced}@{}", selected.version_req); format!("npm:@jsr/{scope_replaced}@{}", selected.version_req);
(selected.import_name, version_req) (selected.import_name.into_string(), version_req)
} else { } else {
(selected.package_name, selected.version_req) (selected.package_name, selected.version_req)
} }
@ -411,18 +412,19 @@ pub async fn add(
let http_client = cli_factory.http_client_provider(); let http_client = cli_factory.http_client_provider();
let deps_http_cache = cli_factory.global_http_cache()?; let deps_http_cache = cli_factory.global_http_cache()?;
let mut deps_file_fetcher = FileFetcher::new( let deps_file_fetcher = CliFileFetcher::new(
deps_http_cache.clone(), deps_http_cache.clone(),
CacheSetting::ReloadAll,
true,
http_client.clone(), http_client.clone(),
cli_factory.sys(),
Default::default(), Default::default(),
None, None,
true,
CacheSetting::ReloadAll,
log::Level::Trace,
); );
let npmrc = cli_factory.cli_options().unwrap().npmrc(); let npmrc = cli_factory.cli_options().unwrap().npmrc();
deps_file_fetcher.set_download_log_level(log::Level::Trace);
let deps_file_fetcher = Arc::new(deps_file_fetcher); let deps_file_fetcher = Arc::new(deps_file_fetcher);
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone())); let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
let npm_resolver = let npm_resolver =
@ -549,10 +551,10 @@ pub async fn add(
} }
struct SelectedPackage { struct SelectedPackage {
import_name: String, import_name: StackString,
package_name: String, package_name: String,
version_req: String, version_req: String,
selected_version: String, selected_version: StackString,
} }
enum NotFoundHelp { enum NotFoundHelp {
@ -683,7 +685,7 @@ async fn find_package_and_select_version_for_req(
import_name: add_package_req.alias, import_name: add_package_req.alias,
package_name: prefixed_name, package_name: prefixed_name,
version_req: format!("{}{}", range_symbol, &nv.version), version_req: format!("{}{}", range_symbol, &nv.version),
selected_version: nv.version.to_string(), selected_version: nv.version.to_custom_string::<StackString>(),
})) }))
} }
@ -705,7 +707,7 @@ enum AddRmPackageReqValue {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct AddRmPackageReq { pub struct AddRmPackageReq {
alias: String, alias: StackString,
value: AddRmPackageReqValue, value: AddRmPackageReqValue,
} }
@ -753,7 +755,11 @@ impl AddRmPackageReq {
return Ok(Err(PackageReq::from_str(entry_text)?)); return Ok(Err(PackageReq::from_str(entry_text)?));
} }
(maybe_prefix.unwrap(), Some(alias.to_string()), entry_text) (
maybe_prefix.unwrap(),
Some(StackString::from(alias)),
entry_text,
)
} }
None => return Ok(Err(PackageReq::from_str(entry_text)?)), None => return Ok(Err(PackageReq::from_str(entry_text)?)),
}, },
@ -765,7 +771,7 @@ impl AddRmPackageReq {
JsrPackageReqReference::from_str(&format!("jsr:{}", entry_text))?; JsrPackageReqReference::from_str(&format!("jsr:{}", entry_text))?;
let package_req = req_ref.into_inner().req; let package_req = req_ref.into_inner().req;
Ok(Ok(AddRmPackageReq { Ok(Ok(AddRmPackageReq {
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()), alias: maybe_alias.unwrap_or_else(|| package_req.name.clone()),
value: AddRmPackageReqValue::Jsr(package_req), value: AddRmPackageReqValue::Jsr(package_req),
})) }))
} }
@ -785,7 +791,7 @@ impl AddRmPackageReq {
); );
} }
Ok(Ok(AddRmPackageReq { Ok(Ok(AddRmPackageReq {
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()), alias: maybe_alias.unwrap_or_else(|| package_req.name.clone()),
value: AddRmPackageReqValue::Npm(package_req), value: AddRmPackageReqValue::Npm(package_req),
})) }))
} }
@ -878,14 +884,14 @@ mod test {
assert_eq!( assert_eq!(
AddRmPackageReq::parse("jsr:foo").unwrap().unwrap(), AddRmPackageReq::parse("jsr:foo").unwrap().unwrap(),
AddRmPackageReq { AddRmPackageReq {
alias: "foo".to_string(), alias: "foo".into(),
value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap()) value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap())
} }
); );
assert_eq!( assert_eq!(
AddRmPackageReq::parse("alias@jsr:foo").unwrap().unwrap(), AddRmPackageReq::parse("alias@jsr:foo").unwrap().unwrap(),
AddRmPackageReq { AddRmPackageReq {
alias: "alias".to_string(), alias: "alias".into(),
value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap()) value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap())
} }
); );
@ -894,7 +900,7 @@ mod test {
.unwrap() .unwrap()
.unwrap(), .unwrap(),
AddRmPackageReq { AddRmPackageReq {
alias: "@alias/pkg".to_string(), alias: "@alias/pkg".into(),
value: AddRmPackageReqValue::Npm( value: AddRmPackageReqValue::Npm(
PackageReq::from_str("foo@latest").unwrap() PackageReq::from_str("foo@latest").unwrap()
) )
@ -905,7 +911,7 @@ mod test {
.unwrap() .unwrap()
.unwrap(), .unwrap(),
AddRmPackageReq { AddRmPackageReq {
alias: "@alias/pkg".to_string(), alias: "@alias/pkg".into(),
value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap()) value: AddRmPackageReqValue::Jsr(PackageReq::from_str("foo").unwrap())
} }
); );
@ -914,7 +920,7 @@ mod test {
.unwrap() .unwrap()
.unwrap(), .unwrap(),
AddRmPackageReq { AddRmPackageReq {
alias: "alias".to_string(), alias: "alias".into(),
value: AddRmPackageReqValue::Jsr( value: AddRmPackageReqValue::Jsr(
PackageReq::from_str("foo@^1.5.0").unwrap() PackageReq::from_str("foo@^1.5.0").unwrap()
) )

View file

@ -3,7 +3,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
@ -28,6 +27,8 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::package::PackageReqReference; use deno_semver::package::PackageReqReference;
use deno_semver::StackString;
use deno_semver::Version;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use import_map::ImportMap; use import_map::ImportMap;
use import_map::ImportMapWithDiagnostics; use import_map::ImportMapWithDiagnostics;
@ -42,6 +43,7 @@ use crate::jsr::JsrFetchResolver;
use crate::module_loader::ModuleLoadPreparer; use crate::module_loader::ModuleLoadPreparer;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
use crate::util::sync::AtomicFlag;
use super::ConfigUpdater; use super::ConfigUpdater;
@ -138,13 +140,7 @@ pub enum KeyPart {
Scopes, Scopes,
Dependencies, Dependencies,
DevDependencies, DevDependencies,
String(String), String(StackString),
}
impl From<String> for KeyPart {
fn from(value: String) -> Self {
KeyPart::String(value)
}
} }
impl From<PackageJsonDepKind> for KeyPart { impl From<PackageJsonDepKind> for KeyPart {
@ -163,7 +159,7 @@ impl KeyPart {
KeyPart::Scopes => "scopes", KeyPart::Scopes => "scopes",
KeyPart::Dependencies => "dependencies", KeyPart::Dependencies => "dependencies",
KeyPart::DevDependencies => "devDependencies", KeyPart::DevDependencies => "devDependencies",
KeyPart::String(s) => s, KeyPart::String(s) => s.as_str(),
} }
} }
} }
@ -216,12 +212,12 @@ fn import_map_entries(
.chain(import_map.scopes().flat_map(|scope| { .chain(import_map.scopes().flat_map(|scope| {
let path = KeyPath::from_parts([ let path = KeyPath::from_parts([
KeyPart::Scopes, KeyPart::Scopes,
scope.raw_key.to_string().into(), KeyPart::String(scope.raw_key.into()),
]); ]);
scope.imports.entries().map(move |entry| { scope.imports.entries().map(move |entry| {
let mut full_path = path.clone(); let mut full_path = path.clone();
full_path.push(KeyPart::String(entry.raw_key.to_string())); full_path.push(KeyPart::String(entry.raw_key.into()));
(full_path, entry) (full_path, entry)
}) })
})) }))
@ -337,7 +333,7 @@ fn add_deps_from_package_json(
package_json: &PackageJsonRc, package_json: &PackageJsonRc,
mut filter: impl DepFilter, mut filter: impl DepFilter,
package_dep_kind: PackageJsonDepKind, package_dep_kind: PackageJsonDepKind,
package_json_deps: PackageJsonDepsMap, package_json_deps: &PackageJsonDepsMap,
deps: &mut Vec<Dep>, deps: &mut Vec<Dep>,
) { ) {
for (k, v) in package_json_deps { for (k, v) in package_json_deps {
@ -352,7 +348,7 @@ fn add_deps_from_package_json(
deno_package_json::PackageJsonDepValue::Req(req) => { deno_package_json::PackageJsonDepValue::Req(req) => {
let alias = k.as_str(); let alias = k.as_str();
let alias = (alias != req.name).then(|| alias.to_string()); let alias = (alias != req.name).then(|| alias.to_string());
if !filter.should_include(alias.as_deref(), &req, DepKind::Npm) { if !filter.should_include(alias.as_deref(), req, DepKind::Npm) {
continue; continue;
} }
let id = DepId(deps.len()); let id = DepId(deps.len());
@ -361,9 +357,12 @@ fn add_deps_from_package_json(
kind: DepKind::Npm, kind: DepKind::Npm,
location: DepLocation::PackageJson( location: DepLocation::PackageJson(
package_json.clone(), package_json.clone(),
KeyPath::from_parts([package_dep_kind.into(), k.into()]), KeyPath::from_parts([
package_dep_kind.into(),
KeyPart::String(k.clone()),
]),
), ),
req, req: req.clone(),
alias, alias,
}) })
} }
@ -376,14 +375,14 @@ fn add_deps_from_package_json(
package_json, package_json,
filter, filter,
PackageJsonDepKind::Normal, PackageJsonDepKind::Normal,
package_json_deps.dependencies, &package_json_deps.dependencies,
deps, deps,
); );
iterate( iterate(
package_json, package_json,
filter, filter,
PackageJsonDepKind::Dev, PackageJsonDepKind::Dev,
package_json_deps.dev_dependencies, &package_json_deps.dev_dependencies,
deps, deps,
); );
} }
@ -447,7 +446,7 @@ pub struct DepManager {
pending_changes: Vec<Change>, pending_changes: Vec<Change>,
dependencies_resolved: AtomicBool, dependencies_resolved: AtomicFlag,
module_load_preparer: Arc<ModuleLoadPreparer>, module_load_preparer: Arc<ModuleLoadPreparer>,
// TODO(nathanwhit): probably shouldn't be pub // TODO(nathanwhit): probably shouldn't be pub
pub(crate) jsr_fetch_resolver: Arc<JsrFetchResolver>, pub(crate) jsr_fetch_resolver: Arc<JsrFetchResolver>,
@ -489,7 +488,7 @@ impl DepManager {
resolved_versions: Vec::new(), resolved_versions: Vec::new(),
latest_versions: Vec::new(), latest_versions: Vec::new(),
jsr_fetch_resolver, jsr_fetch_resolver,
dependencies_resolved: AtomicBool::new(false), dependencies_resolved: AtomicFlag::lowered(),
module_load_preparer, module_load_preparer,
npm_fetch_resolver, npm_fetch_resolver,
npm_resolver, npm_resolver,
@ -530,10 +529,7 @@ impl DepManager {
} }
async fn run_dependency_resolution(&self) -> Result<(), AnyError> { async fn run_dependency_resolution(&self) -> Result<(), AnyError> {
if self if self.dependencies_resolved.is_raised() {
.dependencies_resolved
.load(std::sync::atomic::Ordering::Relaxed)
{
return Ok(()); return Ok(());
} }
@ -556,9 +552,7 @@ impl DepManager {
} }
DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req), DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req),
}) { }) {
self self.dependencies_resolved.raise();
.dependencies_resolved
.store(true, std::sync::atomic::Ordering::Relaxed);
graph_permit.commit(); graph_permit.commit();
return Ok(()); return Ok(());
} }
@ -613,6 +607,7 @@ impl DepManager {
) )
.await?; .await?;
self.dependencies_resolved.raise();
graph_permit.commit(); graph_permit.commit();
Ok(()) Ok(())
@ -655,10 +650,6 @@ impl DepManager {
if self.latest_versions.len() == self.deps.len() { if self.latest_versions.len() == self.deps.len() {
return Ok(self.latest_versions.clone()); return Ok(self.latest_versions.clone());
} }
let latest_tag_req = deno_semver::VersionReq::from_raw_text_and_inner(
"latest".into(),
deno_semver::RangeSetOrTag::Tag("latest".into()),
);
let mut latest_versions = Vec::with_capacity(self.deps.len()); let mut latest_versions = Vec::with_capacity(self.deps.len());
let npm_sema = Semaphore::new(32); let npm_sema = Semaphore::new(32);
@ -670,14 +661,25 @@ impl DepManager {
DepKind::Npm => futs.push_back( DepKind::Npm => futs.push_back(
async { async {
let semver_req = &dep.req; let semver_req = &dep.req;
let latest_req = PackageReq {
name: dep.req.name.clone(),
version_req: latest_tag_req.clone(),
};
let _permit = npm_sema.acquire().await; let _permit = npm_sema.acquire().await;
let semver_compatible = let semver_compatible =
self.npm_fetch_resolver.req_to_nv(semver_req).await; self.npm_fetch_resolver.req_to_nv(semver_req).await;
let latest = self.npm_fetch_resolver.req_to_nv(&latest_req).await; let info =
self.npm_fetch_resolver.package_info(&semver_req.name).await;
let latest = info
.and_then(|info| {
let latest_tag = info.dist_tags.get("latest")?;
let lower_bound = &semver_compatible.as_ref()?.version;
if latest_tag > lower_bound {
Some(latest_tag.clone())
} else {
latest_version(Some(latest_tag), info.versions.keys())
}
})
.map(|version| PackageNv {
name: semver_req.name.clone(),
version,
});
PackageLatestVersion { PackageLatestVersion {
latest, latest,
semver_compatible, semver_compatible,
@ -688,14 +690,29 @@ impl DepManager {
DepKind::Jsr => futs.push_back( DepKind::Jsr => futs.push_back(
async { async {
let semver_req = &dep.req; let semver_req = &dep.req;
let latest_req = PackageReq {
name: dep.req.name.clone(),
version_req: deno_semver::WILDCARD_VERSION_REQ.clone(),
};
let _permit = jsr_sema.acquire().await; let _permit = jsr_sema.acquire().await;
let semver_compatible = let semver_compatible =
self.jsr_fetch_resolver.req_to_nv(semver_req).await; self.jsr_fetch_resolver.req_to_nv(semver_req).await;
let latest = self.jsr_fetch_resolver.req_to_nv(&latest_req).await; let info =
self.jsr_fetch_resolver.package_info(&semver_req.name).await;
let latest = info
.and_then(|info| {
let lower_bound = &semver_compatible.as_ref()?.version;
latest_version(
Some(lower_bound),
info.versions.iter().filter_map(|(version, version_info)| {
if !version_info.yanked {
Some(version)
} else {
None
}
}),
)
})
.map(|version| PackageNv {
name: semver_req.name.clone(),
version,
});
PackageLatestVersion { PackageLatestVersion {
latest, latest,
semver_compatible, semver_compatible,
@ -893,3 +910,18 @@ fn parse_req_reference(
DepKind::Jsr => JsrPackageReqReference::from_str(input)?.into_inner(), DepKind::Jsr => JsrPackageReqReference::from_str(input)?.into_inner(),
}) })
} }
fn latest_version<'a>(
start: Option<&Version>,
versions: impl IntoIterator<Item = &'a Version>,
) -> Option<Version> {
let mut best = start;
for version in versions {
match best {
Some(best_version) if version > best_version => best = Some(version),
None => best = Some(version),
_ => {}
}
}
best.cloned()
}

View file

@ -3,19 +3,20 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use deno_terminal::colors; use deno_terminal::colors;
use crate::args::CacheSetting;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::OutdatedFlags; use crate::args::OutdatedFlags;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::jsr::JsrFetchResolver; use crate::jsr::JsrFetchResolver;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
use crate::tools::registry::pm::deps::DepKind; use crate::tools::registry::pm::deps::DepKind;
@ -31,7 +32,7 @@ struct OutdatedPackage {
latest: String, latest: String,
semver_compatible: String, semver_compatible: String,
current: String, current: String,
name: String, name: StackString,
} }
#[allow(clippy::print_stdout)] #[allow(clippy::print_stdout)]
@ -181,15 +182,16 @@ pub async fn outdated(
let workspace = cli_options.workspace(); let workspace = cli_options.workspace();
let http_client = factory.http_client_provider(); let http_client = factory.http_client_provider();
let deps_http_cache = factory.global_http_cache()?; let deps_http_cache = factory.global_http_cache()?;
let mut file_fetcher = FileFetcher::new( let file_fetcher = CliFileFetcher::new(
deps_http_cache.clone(), deps_http_cache.clone(),
CacheSetting::RespectHeaders,
true,
http_client.clone(), http_client.clone(),
factory.sys(),
Default::default(), Default::default(),
None, None,
true,
CacheSetting::RespectHeaders,
log::Level::Trace,
); );
file_fetcher.set_download_log_level(log::Level::Trace);
let file_fetcher = Arc::new(file_fetcher); let file_fetcher = Arc::new(file_fetcher);
let npm_fetch_resolver = Arc::new(NpmFetchResolver::new( let npm_fetch_resolver = Arc::new(NpmFetchResolver::new(
file_fetcher.clone(), file_fetcher.clone(),

View file

@ -658,12 +658,12 @@ mod tests {
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use super::*; use super::*;
use crate::sys::CliSys;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_config::workspace::ResolverWorkspaceJsrPackage; use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_node::PackageJson;
use deno_semver::Version; use deno_semver::Version;
use import_map::ImportMapWithDiagnostics; use import_map::ImportMapWithDiagnostics;
@ -722,10 +722,9 @@ mod tests {
vec![Arc::new(package_json)], vec![Arc::new(package_json)],
deno_config::workspace::PackageJsonDepResolution::Enabled, deno_config::workspace::PackageJsonDepResolution::Enabled,
); );
let fs = Arc::new(RealFs);
let unfurler = SpecifierUnfurler::new( let unfurler = SpecifierUnfurler::new(
Some(Arc::new(CliSloppyImportsResolver::new( Some(Arc::new(CliSloppyImportsResolver::new(
SloppyImportsCachedFs::new(fs), SloppyImportsCachedFs::new(CliSys::default()),
))), ))),
Arc::new(workspace_resolver), Arc::new(workspace_resolver),
true, true,
@ -863,10 +862,10 @@ const warn2 = await import(`${expr}`);
], ],
deno_config::workspace::PackageJsonDepResolution::Enabled, deno_config::workspace::PackageJsonDepResolution::Enabled,
); );
let fs = Arc::new(RealFs); let sys = CliSys::default();
let unfurler = SpecifierUnfurler::new( let unfurler = SpecifierUnfurler::new(
Some(Arc::new(CliSloppyImportsResolver::new( Some(Arc::new(CliSloppyImportsResolver::new(
SloppyImportsCachedFs::new(fs), SloppyImportsCachedFs::new(sys),
))), ))),
Arc::new(workspace_resolver), Arc::new(workspace_resolver),
true, true,

View file

@ -11,7 +11,8 @@ use crate::args::ReplFlags;
use crate::cdp; use crate::cdp;
use crate::colors; use crate::colors;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::TextDecodedFile;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_core::serde_json; use deno_core::serde_json;
@ -143,7 +144,7 @@ async fn read_line_and_poll(
async fn read_eval_file( async fn read_eval_file(
cli_options: &CliOptions, cli_options: &CliOptions,
file_fetcher: &FileFetcher, file_fetcher: &CliFileFetcher,
eval_file: &str, eval_file: &str,
) -> Result<Arc<str>, AnyError> { ) -> Result<Arc<str>, AnyError> {
let specifier = let specifier =
@ -151,7 +152,7 @@ async fn read_eval_file(
let file = file_fetcher.fetch_bypass_permissions(&specifier).await?; let file = file_fetcher.fetch_bypass_permissions(&specifier).await?;
Ok(file.into_text_decoded()?.source) Ok(TextDecodedFile::decode(file)?.source)
} }
#[allow(clippy::print_stdout)] #[allow(clippy::print_stdout)]

View file

@ -3,6 +3,7 @@
use std::io::Read; use std::io::Read;
use std::sync::Arc; use std::sync::Arc;
use deno_cache_dir::file_fetcher::File;
use deno_config::deno_json::NodeModulesDirMode; use deno_config::deno_json::NodeModulesDirMode;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_runtime::WorkerExecutionMode; use deno_runtime::WorkerExecutionMode;
@ -11,7 +12,6 @@ use crate::args::EvalFlags;
use crate::args::Flags; use crate::args::Flags;
use crate::args::WatchFlagsWithPaths; use crate::args::WatchFlagsWithPaths;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::File;
use crate::util; use crate::util;
use crate::util::file_watcher::WatcherRestartMode; use crate::util::file_watcher::WatcherRestartMode;
@ -97,7 +97,7 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
// Save a fake file into file fetcher cache // Save a fake file into file fetcher cache
// to allow module access by TS compiler // to allow module access by TS compiler
file_fetcher.insert_memory_files(File { file_fetcher.insert_memory_files(File {
specifier: main_module.clone(), url: main_module.clone(),
maybe_headers: None, maybe_headers: None,
source: source.into(), source: source.into(),
}); });
@ -184,7 +184,7 @@ pub async fn eval_command(
// Save a fake file into file fetcher cache // Save a fake file into file fetcher cache
// to allow module access by TS compiler. // to allow module access by TS compiler.
file_fetcher.insert_memory_files(File { file_fetcher.insert_memory_files(File {
specifier: main_module.clone(), url: main_module.clone(),
maybe_headers: None, maybe_headers: None,
source: source_code.into_bytes().into(), source: source_code.into_bytes().into(),
}); });

View file

@ -25,7 +25,6 @@ use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_core::url::Url; use deno_core::url::Url;
use deno_path_util::normalize_path; use deno_path_util::normalize_path;
use deno_runtime::deno_node::NodeResolver;
use deno_task_shell::KillSignal; use deno_task_shell::KillSignal;
use deno_task_shell::ShellCommand; use deno_task_shell::ShellCommand;
use indexmap::IndexMap; use indexmap::IndexMap;
@ -36,6 +35,7 @@ use crate::args::Flags;
use crate::args::TaskFlags; use crate::args::TaskFlags;
use crate::colors; use crate::colors;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::task_runner; use crate::task_runner;
use crate::task_runner::run_future_forwarding_signals; use crate::task_runner::run_future_forwarding_signals;
@ -94,7 +94,7 @@ pub async fn execute_script(
return Ok(0); return Ok(0);
}; };
let task_regex = arg_to_regex(task_name)?; let task_name_filter = arg_to_task_name_filter(task_name)?;
let mut packages_task_info: Vec<PackageTaskInfo> = vec![]; let mut packages_task_info: Vec<PackageTaskInfo> = vec![];
for folder in workspace.config_folders() { for folder in workspace.config_folders() {
@ -137,12 +137,20 @@ pub async fn execute_script(
// Match tasks in deno.json // Match tasks in deno.json
for name in tasks_config.task_names() { for name in tasks_config.task_names() {
if task_regex.is_match(name) && !visited.contains(name) { let matches_filter = match &task_name_filter {
TaskNameFilter::Exact(n) => *n == name,
TaskNameFilter::Regex(re) => re.is_match(name),
};
if matches_filter && !visited.contains(name) {
matched.insert(name.to_string()); matched.insert(name.to_string());
visit_task(&tasks_config, &mut visited, name); visit_task(&tasks_config, &mut visited, name);
} }
} }
if matched.is_empty() {
continue;
}
packages_task_info.push(PackageTaskInfo { packages_task_info.push(PackageTaskInfo {
matched_tasks: matched matched_tasks: matched
.iter() .iter()
@ -223,7 +231,7 @@ pub async fn execute_script(
&Url::from_directory_path(cli_options.initial_cwd()).unwrap(), &Url::from_directory_path(cli_options.initial_cwd()).unwrap(),
"", "",
&TaskDefinition { &TaskDefinition {
command: task_flags.task.as_ref().unwrap().to_string(), command: Some(task_flags.task.as_ref().unwrap().to_string()),
dependencies: vec![], dependencies: vec![],
description: None, description: None,
}, },
@ -259,7 +267,7 @@ struct RunSingleOptions<'a> {
struct TaskRunner<'a> { struct TaskRunner<'a> {
task_flags: &'a TaskFlags, task_flags: &'a TaskFlags,
npm_resolver: &'a dyn CliNpmResolver, npm_resolver: &'a dyn CliNpmResolver,
node_resolver: &'a NodeResolver, node_resolver: &'a CliNodeResolver,
env_vars: HashMap<String, String>, env_vars: HashMap<String, String>,
cli_options: &'a CliOptions, cli_options: &'a CliOptions,
concurrency: usize, concurrency: usize,
@ -440,6 +448,16 @@ impl<'a> TaskRunner<'a> {
kill_signal: KillSignal, kill_signal: KillSignal,
argv: &'a [String], argv: &'a [String],
) -> Result<i32, deno_core::anyhow::Error> { ) -> Result<i32, deno_core::anyhow::Error> {
let Some(command) = &definition.command else {
log::info!(
"{} {} {}",
colors::green("Task"),
colors::cyan(task_name),
colors::gray("(no command)")
);
return Ok(0);
};
if let Some(npm_resolver) = self.npm_resolver.as_managed() { if let Some(npm_resolver) = self.npm_resolver.as_managed() {
npm_resolver.ensure_top_level_package_json_install().await?; npm_resolver.ensure_top_level_package_json_install().await?;
npm_resolver npm_resolver
@ -461,7 +479,7 @@ impl<'a> TaskRunner<'a> {
self self
.run_single(RunSingleOptions { .run_single(RunSingleOptions {
task_name, task_name,
script: &definition.command, script: command,
cwd: &cwd, cwd: &cwd,
custom_commands, custom_commands,
kill_signal, kill_signal,
@ -829,7 +847,7 @@ fn print_available_tasks(
is_deno: false, is_deno: false,
name: name.to_string(), name: name.to_string(),
task: deno_config::deno_json::TaskDefinition { task: deno_config::deno_json::TaskDefinition {
command: script.to_string(), command: Some(script.to_string()),
dependencies: vec![], dependencies: vec![],
description: None, description: None,
}, },
@ -865,11 +883,13 @@ fn print_available_tasks(
)?; )?;
} }
} }
writeln!( if let Some(command) = &desc.task.command {
writer, writeln!(
" {}", writer,
strip_ansi_codes_and_escape_control_chars(&desc.task.command) " {}",
)?; strip_ansi_codes_and_escape_control_chars(command)
)?;
};
if !desc.task.dependencies.is_empty() { if !desc.task.dependencies.is_empty() {
let dependencies = desc let dependencies = desc
.task .task
@ -902,3 +922,41 @@ fn strip_ansi_codes_and_escape_control_chars(s: &str) -> String {
}) })
.collect() .collect()
} }
fn arg_to_task_name_filter(input: &str) -> Result<TaskNameFilter, AnyError> {
if !input.contains("*") {
return Ok(TaskNameFilter::Exact(input));
}
let mut regex_str = regex::escape(input);
regex_str = regex_str.replace("\\*", ".*");
let re = Regex::new(&regex_str)?;
Ok(TaskNameFilter::Regex(re))
}
#[derive(Debug)]
enum TaskNameFilter<'s> {
Exact(&'s str),
Regex(regex::Regex),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arg_to_task_name_filter() {
assert!(matches!(
arg_to_task_name_filter("test").unwrap(),
TaskNameFilter::Exact("test")
));
assert!(matches!(
arg_to_task_name_filter("test-").unwrap(),
TaskNameFilter::Exact("test-")
));
assert!(matches!(
arg_to_task_name_filter("test*").unwrap(),
TaskNameFilter::Regex(_)
));
}
}

View file

@ -7,10 +7,10 @@ use crate::args::TestReporterConfig;
use crate::colors; use crate::colors;
use crate::display; use crate::display;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::file_fetcher::File; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::FileFetcher;
use crate::graph_util::has_graph_root_local_dependent_changed; use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::ops; use crate::ops;
use crate::sys::CliSys;
use crate::util::extract::extract_doc_tests; use crate::util::extract::extract_doc_tests;
use crate::util::file_watcher; use crate::util::file_watcher;
use crate::util::fs::collect_specifiers; use crate::util::fs::collect_specifiers;
@ -21,6 +21,7 @@ use crate::worker::CliMainWorkerFactory;
use crate::worker::CoverageCollector; use crate::worker::CoverageCollector;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::File;
use deno_config::glob::FilePatterns; use deno_config::glob::FilePatterns;
use deno_config::glob::WalkEntry; use deno_config::glob::WalkEntry;
use deno_core::anyhow; use deno_core::anyhow;
@ -616,7 +617,10 @@ async fn configure_main_worker(
WorkerExecutionMode::Test, WorkerExecutionMode::Test,
specifier.clone(), specifier.clone(),
permissions_container, permissions_container,
vec![ops::testing::deno_test::init_ops(worker_sender.sender)], vec![
ops::testing::deno_test::init_ops(worker_sender.sender),
ops::lint::deno_lint::init_ops(),
],
Stdio { Stdio {
stdin: StdioPipe::inherit(), stdin: StdioPipe::inherit(),
stdout: StdioPipe::file(worker_sender.stdout), stdout: StdioPipe::file(worker_sender.stdout),
@ -1191,7 +1195,7 @@ static HAS_TEST_RUN_SIGINT_HANDLER: AtomicBool = AtomicBool::new(false);
async fn test_specifiers( async fn test_specifiers(
worker_factory: Arc<CliMainWorkerFactory>, worker_factory: Arc<CliMainWorkerFactory>,
permissions: &Permissions, permissions: &Permissions,
permission_desc_parser: &Arc<RuntimePermissionDescriptorParser>, permission_desc_parser: &Arc<RuntimePermissionDescriptorParser<CliSys>>,
specifiers: Vec<ModuleSpecifier>, specifiers: Vec<ModuleSpecifier>,
options: TestSpecifiersOptions, options: TestSpecifiersOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
@ -1514,7 +1518,7 @@ fn collect_specifiers_with_test_mode(
/// as well. /// as well.
async fn fetch_specifiers_with_test_mode( async fn fetch_specifiers_with_test_mode(
cli_options: &CliOptions, cli_options: &CliOptions,
file_fetcher: &FileFetcher, file_fetcher: &CliFileFetcher,
member_patterns: impl Iterator<Item = FilePatterns>, member_patterns: impl Iterator<Item = FilePatterns>,
doc: &bool, doc: &bool,
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> { ) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
@ -1822,7 +1826,7 @@ pub async fn run_tests_with_watch(
/// Extracts doc tests from files specified by the given specifiers. /// Extracts doc tests from files specified by the given specifiers.
async fn get_doc_tests( async fn get_doc_tests(
specifiers_with_mode: &[(Url, TestMode)], specifiers_with_mode: &[(Url, TestMode)],
file_fetcher: &FileFetcher, file_fetcher: &CliFileFetcher,
) -> Result<Vec<File>, AnyError> { ) -> Result<Vec<File>, AnyError> {
let specifiers_needing_extraction = specifiers_with_mode let specifiers_needing_extraction = specifiers_with_mode
.iter() .iter()
@ -1847,7 +1851,7 @@ fn get_target_specifiers(
specifiers_with_mode specifiers_with_mode
.into_iter() .into_iter()
.filter_map(|(s, mode)| mode.needs_test_run().then_some(s)) .filter_map(|(s, mode)| mode.needs_test_run().then_some(s))
.chain(doc_tests.iter().map(|d| d.specifier.clone())) .chain(doc_tests.iter().map(|d| d.url.clone()))
.collect() .collect()
} }

View file

@ -21,6 +21,7 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::unsync::spawn; use deno_core::unsync::spawn;
use deno_core::url::Url; use deno_core::url::Url;
use deno_semver::SmallStackString;
use deno_semver::Version; use deno_semver::Version;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::borrow::Cow; use std::borrow::Cow;
@ -255,7 +256,7 @@ async fn print_release_notes(
let is_deno_2_rc = new_semver.major == 2 let is_deno_2_rc = new_semver.major == 2
&& new_semver.minor == 0 && new_semver.minor == 0
&& new_semver.patch == 0 && new_semver.patch == 0
&& new_semver.pre.first() == Some(&"rc".to_string()); && new_semver.pre.first().map(|s| s.as_str()) == Some("rc");
if is_deno_2_rc || is_switching_from_deno1_to_deno2 { if is_deno_2_rc || is_switching_from_deno1_to_deno2 {
log::info!( log::info!(
@ -674,7 +675,7 @@ impl RequestedVersion {
); );
}; };
if semver.pre.contains(&"rc".to_string()) { if semver.pre.contains(&SmallStackString::from_static("rc")) {
(ReleaseChannel::Rc, passed_version) (ReleaseChannel::Rc, passed_version)
} else { } else {
(ReleaseChannel::Stable, passed_version) (ReleaseChannel::Stable, passed_version)

View file

@ -136063,6 +136063,7 @@ var unprefixedNodeCoreModuleList = [
"https", "https",
"http2", "http2",
"inspector", "inspector",
"inspector/promises",
"module", "module",
"net", "net",
"os", "os",

View file

@ -41,6 +41,13 @@ delete Object.prototype.__proto__;
"listen", "listen",
"listenDatagram", "listenDatagram",
"openKv", "openKv",
"connectQuic",
"listenQuic",
"QuicBidirectionalStream",
"QuicConn",
"QuicListener",
"QuicReceiveStream",
"QuicSendStream",
]); ]);
const unstableMsgSuggestion = const unstableMsgSuggestion =
"If not, try changing the 'lib' compiler option to include 'deno.unstable' " + "If not, try changing the 'lib' compiler option to include 'deno.unstable' " +

View file

@ -133,6 +133,12 @@ pub struct Diagnostic {
pub file_name: Option<String>, pub file_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub related_information: Option<Vec<Diagnostic>>, pub related_information: Option<Vec<Diagnostic>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reports_deprecated: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reports_unnecessary: Option<bool>,
#[serde(flatten)]
pub other: deno_core::serde_json::Map<String, deno_core::serde_json::Value>,
} }
impl Diagnostic { impl Diagnostic {

View file

@ -4,9 +4,10 @@ use crate::args::TsConfig;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::cache::ModuleInfoCache; use crate::cache::ModuleInfoCache;
use crate::node; use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::sys::CliSys;
use crate::util::checksum; use crate::util::checksum;
use crate::util::path::mapped_specifier_for_tsc; use crate::util::path::mapped_specifier_for_tsc;
use crate::worker::create_isolate_create_params; use crate::worker::create_isolate_create_params;
@ -35,12 +36,11 @@ use deno_graph::Module;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_graph::ResolutionResolved; use deno_graph::ResolutionResolved;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::NodeResolver;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use node_resolver::errors::NodeJsErrorCode; use node_resolver::errors::NodeJsErrorCode;
use node_resolver::errors::NodeJsErrorCoded; use node_resolver::errors::NodeJsErrorCoded;
use node_resolver::errors::PackageSubpathResolveError; use node_resolver::errors::PackageSubpathResolveError;
use node_resolver::resolve_specifier_into_node_modules;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -380,7 +380,7 @@ impl TypeCheckingCjsTracker {
#[derive(Debug)] #[derive(Debug)]
pub struct RequestNpmState { pub struct RequestNpmState {
pub cjs_tracker: Arc<TypeCheckingCjsTracker>, pub cjs_tracker: Arc<TypeCheckingCjsTracker>,
pub node_resolver: Arc<NodeResolver>, pub node_resolver: Arc<CliNodeResolver>,
pub npm_resolver: Arc<dyn CliNpmResolver>, pub npm_resolver: Arc<dyn CliNpmResolver>,
} }
@ -660,9 +660,9 @@ fn op_load_inner(
None None
} else { } else {
// means it's Deno code importing an npm module // means it's Deno code importing an npm module
let specifier = node::resolve_specifier_into_node_modules( let specifier = resolve_specifier_into_node_modules(
&CliSys::default(),
&module.specifier, &module.specifier,
&deno_fs::RealFs,
); );
Some(Cow::Owned(load_from_node_modules( Some(Cow::Owned(load_from_node_modules(
&specifier, &specifier,
@ -924,9 +924,9 @@ fn resolve_graph_specifier_types(
Some(Module::External(module)) => { Some(Module::External(module)) => {
// we currently only use "External" for when the module is in an npm package // we currently only use "External" for when the module is in an npm package
Ok(state.maybe_npm.as_ref().map(|_| { Ok(state.maybe_npm.as_ref().map(|_| {
let specifier = node::resolve_specifier_into_node_modules( let specifier = resolve_specifier_into_node_modules(
&CliSys::default(),
&module.specifier, &module.specifier,
&deno_fs::RealFs,
); );
into_specifier_and_media_type(Some(specifier)) into_specifier_and_media_type(Some(specifier))
})) }))
@ -1444,6 +1444,9 @@ mod tests {
source_line: None, source_line: None,
file_name: None, file_name: None,
related_information: None, related_information: None,
reports_deprecated: None,
reports_unnecessary: None,
other: Default::default(),
}]), }]),
stats: Stats(vec![("a".to_string(), 12)]) stats: Stats(vec![("a".to_string(), 12)])
}) })

View file

@ -13,6 +13,7 @@ use deno_ast::swc::visit::VisitMut;
use deno_ast::swc::visit::VisitWith as _; use deno_ast::swc::visit::VisitWith as _;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::SourceRangedForSpanned as _; use deno_ast::SourceRangedForSpanned as _;
use deno_cache_dir::file_fetcher::File;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use regex::Regex; use regex::Regex;
@ -20,7 +21,7 @@ use std::collections::BTreeSet;
use std::fmt::Write as _; use std::fmt::Write as _;
use std::sync::Arc; use std::sync::Arc;
use crate::file_fetcher::File; use crate::file_fetcher::TextDecodedFile;
use crate::util::path::mapped_specifier_for_tsc; use crate::util::path::mapped_specifier_for_tsc;
/// Extracts doc tests from a given file, transforms them into pseudo test /// Extracts doc tests from a given file, transforms them into pseudo test
@ -52,7 +53,7 @@ fn extract_inner(
file: File, file: File,
wrap_kind: WrapKind, wrap_kind: WrapKind,
) -> Result<Vec<File>, AnyError> { ) -> Result<Vec<File>, AnyError> {
let file = file.into_text_decoded()?; let file = TextDecodedFile::decode(file)?;
let exports = match deno_ast::parse_program(deno_ast::ParseParams { let exports = match deno_ast::parse_program(deno_ast::ParseParams {
specifier: file.specifier.clone(), specifier: file.specifier.clone(),
@ -230,7 +231,7 @@ fn extract_files_from_regex_blocks(
.unwrap_or(file_specifier); .unwrap_or(file_specifier);
Some(File { Some(File {
specifier: file_specifier, url: file_specifier,
maybe_headers: None, maybe_headers: None,
source: file_source.into_bytes().into(), source: file_source.into_bytes().into(),
}) })
@ -558,7 +559,7 @@ fn generate_pseudo_file(
exports: &ExportCollector, exports: &ExportCollector,
wrap_kind: WrapKind, wrap_kind: WrapKind,
) -> Result<File, AnyError> { ) -> Result<File, AnyError> {
let file = file.into_text_decoded()?; let file = TextDecodedFile::decode(file)?;
let parsed = deno_ast::parse_program(deno_ast::ParseParams { let parsed = deno_ast::parse_program(deno_ast::ParseParams {
specifier: file.specifier.clone(), specifier: file.specifier.clone(),
@ -594,7 +595,7 @@ fn generate_pseudo_file(
log::debug!("{}:\n{}", file.specifier, source); log::debug!("{}:\n{}", file.specifier, source);
Ok(File { Ok(File {
specifier: file.specifier, url: file.specifier,
maybe_headers: None, maybe_headers: None,
source: source.into_bytes().into(), source: source.into_bytes().into(),
}) })
@ -1199,14 +1200,14 @@ Deno.test("file:///main.ts$3-7.ts", async ()=>{
for test in tests { for test in tests {
let file = File { let file = File {
specifier: ModuleSpecifier::parse(test.input.specifier).unwrap(), url: ModuleSpecifier::parse(test.input.specifier).unwrap(),
maybe_headers: None, maybe_headers: None,
source: test.input.source.as_bytes().into(), source: test.input.source.as_bytes().into(),
}; };
let got_decoded = extract_doc_tests(file) let got_decoded = extract_doc_tests(file)
.unwrap() .unwrap()
.into_iter() .into_iter()
.map(|f| f.into_text_decoded().unwrap()) .map(|f| TextDecodedFile::decode(f).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let expected = test let expected = test
.expected .expected
@ -1435,14 +1436,14 @@ add('1', '2');
for test in tests { for test in tests {
let file = File { let file = File {
specifier: ModuleSpecifier::parse(test.input.specifier).unwrap(), url: ModuleSpecifier::parse(test.input.specifier).unwrap(),
maybe_headers: None, maybe_headers: None,
source: test.input.source.as_bytes().into(), source: test.input.source.as_bytes().into(),
}; };
let got_decoded = extract_snippet_files(file) let got_decoded = extract_snippet_files(file)
.unwrap() .unwrap()
.into_iter() .into_iter()
.map(|f| f.into_text_decoded().unwrap()) .map(|f| TextDecodedFile::decode(f).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let expected = test let expected = test
.expected .expected

View file

@ -1,9 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::fs::OpenOptions;
use std::io::Error; use std::io::Error;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::io::Write;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
@ -19,185 +17,12 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::unsync::spawn_blocking; use deno_core::unsync::spawn_blocking;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_runtime::deno_fs::FileSystem;
use crate::util::path::get_atomic_file_path; use crate::sys::CliSys;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
use crate::util::progress_bar::ProgressMessagePrompt; use crate::util::progress_bar::ProgressMessagePrompt;
/// Writes the file to the file system at a temporary path, then
/// renames it to the destination in a single sys call in order
/// to never leave the file system in a corrupted state.
///
/// This also handles creating the directory if a NotFound error
/// occurs.
pub fn atomic_write_file_with_retries<T: AsRef<[u8]>>(
file_path: &Path,
data: T,
mode: u32,
) -> std::io::Result<()> {
struct RealAtomicWriteFileFs {
mode: u32,
}
impl AtomicWriteFileFs for RealAtomicWriteFileFs {
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()> {
write_file(path, bytes, self.mode)
}
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()> {
std::fs::rename(from, to)
}
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
std::fs::remove_file(path)
}
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()> {
std::fs::create_dir_all(dir_path)
}
fn path_exists(&self, path: &Path) -> bool {
path.exists()
}
}
atomic_write_file_with_retries_and_fs(
&RealAtomicWriteFileFs { mode },
file_path,
data.as_ref(),
)
}
pub trait AtomicWriteFileFs {
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()>;
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()>;
fn remove_file(&self, path: &Path) -> std::io::Result<()>;
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()>;
fn path_exists(&self, path: &Path) -> bool;
}
pub struct AtomicWriteFileFsAdapter<'a> {
pub fs: &'a dyn FileSystem,
pub write_mode: u32,
}
impl<'a> AtomicWriteFileFs for AtomicWriteFileFsAdapter<'a> {
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()> {
self
.fs
.write_file_sync(
path,
deno_runtime::deno_fs::OpenOptions::write(
true,
false,
false,
Some(self.write_mode),
),
None,
bytes,
)
.map_err(|e| e.into_io_error())
}
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()> {
self.fs.rename_sync(from, to).map_err(|e| e.into_io_error())
}
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
self
.fs
.remove_sync(path, false)
.map_err(|e| e.into_io_error())
}
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()> {
self
.fs
.mkdir_sync(dir_path, /* recursive */ true, None)
.map_err(|e| e.into_io_error())
}
fn path_exists(&self, path: &Path) -> bool {
self.fs.exists_sync(path)
}
}
pub fn atomic_write_file_with_retries_and_fs<T: AsRef<[u8]>>(
fs: &impl AtomicWriteFileFs,
file_path: &Path,
data: T,
) -> std::io::Result<()> {
let mut count = 0;
loop {
match atomic_write_file(fs, file_path, data.as_ref()) {
Ok(()) => return Ok(()),
Err(err) => {
if count >= 5 {
// too many retries, return the error
return Err(err);
}
count += 1;
let sleep_ms = std::cmp::min(50, 10 * count);
std::thread::sleep(std::time::Duration::from_millis(sleep_ms));
}
}
}
}
/// Writes the file to the file system at a temporary path, then
/// renames it to the destination in a single sys call in order
/// to never leave the file system in a corrupted state.
///
/// This also handles creating the directory if a NotFound error
/// occurs.
fn atomic_write_file(
fs: &impl AtomicWriteFileFs,
file_path: &Path,
data: &[u8],
) -> std::io::Result<()> {
fn atomic_write_file_raw(
fs: &impl AtomicWriteFileFs,
temp_file_path: &Path,
file_path: &Path,
data: &[u8],
) -> std::io::Result<()> {
fs.write_file(temp_file_path, data)?;
fs.rename_file(temp_file_path, file_path)
.inspect_err(|_err| {
// clean up the created temp file on error
let _ = fs.remove_file(temp_file_path);
})
}
let temp_file_path = get_atomic_file_path(file_path);
if let Err(write_err) =
atomic_write_file_raw(fs, &temp_file_path, file_path, data)
{
if write_err.kind() == ErrorKind::NotFound {
let parent_dir_path = file_path.parent().unwrap();
match fs.create_dir_all(parent_dir_path) {
Ok(()) => {
return atomic_write_file_raw(fs, &temp_file_path, file_path, data)
.map_err(|err| add_file_context_to_err(file_path, err));
}
Err(create_err) => {
if !fs.path_exists(parent_dir_path) {
return Err(Error::new(
create_err.kind(),
format!(
"{:#} (for '{}')\nCheck the permission of the directory.",
create_err,
parent_dir_path.display()
),
));
}
}
}
}
return Err(add_file_context_to_err(file_path, write_err));
}
Ok(())
}
/// Creates a std::fs::File handling if the parent does not exist. /// Creates a std::fs::File handling if the parent does not exist.
pub fn create_file(file_path: &Path) -> std::io::Result<std::fs::File> { pub fn create_file(file_path: &Path) -> std::io::Result<std::fs::File> {
match std::fs::File::create(file_path) { match std::fs::File::create(file_path) {
@ -236,45 +61,6 @@ fn add_file_context_to_err(file_path: &Path, err: Error) -> Error {
) )
} }
pub fn write_file<T: AsRef<[u8]>>(
filename: &Path,
data: T,
mode: u32,
) -> std::io::Result<()> {
write_file_2(filename, data, true, mode, true, false)
}
pub fn write_file_2<T: AsRef<[u8]>>(
filename: &Path,
data: T,
update_mode: bool,
mode: u32,
is_create: bool,
is_append: bool,
) -> std::io::Result<()> {
let mut file = OpenOptions::new()
.read(false)
.write(true)
.append(is_append)
.truncate(!is_append)
.create(is_create)
.open(filename)?;
if update_mode {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mode = mode & 0o777;
let permissions = PermissionsExt::from_mode(mode);
file.set_permissions(permissions)?;
}
#[cfg(not(unix))]
let _ = mode;
}
file.write_all(data.as_ref())
}
/// Similar to `std::fs::canonicalize()` but strips UNC prefixes on Windows. /// Similar to `std::fs::canonicalize()` but strips UNC prefixes on Windows.
pub fn canonicalize_path(path: &Path) -> Result<PathBuf, Error> { pub fn canonicalize_path(path: &Path) -> Result<PathBuf, Error> {
Ok(deno_path_util::strip_unc_prefix(path.canonicalize()?)) Ok(deno_path_util::strip_unc_prefix(path.canonicalize()?))
@ -289,16 +75,10 @@ pub fn canonicalize_path(path: &Path) -> Result<PathBuf, Error> {
pub fn canonicalize_path_maybe_not_exists( pub fn canonicalize_path_maybe_not_exists(
path: &Path, path: &Path,
) -> Result<PathBuf, Error> { ) -> Result<PathBuf, Error> {
deno_path_util::canonicalize_path_maybe_not_exists(path, &canonicalize_path) deno_path_util::fs::canonicalize_path_maybe_not_exists(
} &CliSys::default(),
path,
pub fn canonicalize_path_maybe_not_exists_with_fs( )
path: &Path,
fs: &dyn FileSystem,
) -> Result<PathBuf, Error> {
deno_path_util::canonicalize_path_maybe_not_exists(path, &|path| {
fs.realpath_sync(path).map_err(|err| err.into_io_error())
})
} }
/// Collects module specifiers that satisfy the given predicate as a file path, by recursively walking `include`. /// Collects module specifiers that satisfy the given predicate as a file path, by recursively walking `include`.
@ -346,7 +126,7 @@ pub fn collect_specifiers(
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.set_vendor_folder(vendor_folder) .set_vendor_folder(vendor_folder)
.collect_file_patterns(&deno_config::fs::RealDenoConfigFs, files)?; .collect_file_patterns(&CliSys::default(), files)?;
let mut collected_files_as_urls = collected_files let mut collected_files_as_urls = collected_files
.iter() .iter()
.map(|f| specifier_from_file_path(f).unwrap()) .map(|f| specifier_from_file_path(f).unwrap())
@ -418,7 +198,11 @@ mod clone_dir_imp {
from: &std::path::Path, from: &std::path::Path,
to: &std::path::Path, to: &std::path::Path,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), deno_core::error::AnyError> {
if let Err(e) = super::hard_link_dir_recursive(from, to) { use crate::sys::CliSys;
if let Err(e) =
deno_npm_cache::hard_link_dir_recursive(&CliSys::default(), from, to)
{
log::debug!("Failed to hard link dir {:?} to {:?}: {}", from, to, e); log::debug!("Failed to hard link dir {:?} to {:?}: {}", from, to, e);
super::copy_dir_recursive(from, to)?; super::copy_dir_recursive(from, to)?;
} }
@ -465,84 +249,6 @@ pub fn copy_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> {
Ok(()) Ok(())
} }
/// Hardlinks the files in one directory to another directory.
///
/// Note: Does not handle symlinks.
pub fn hard_link_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> {
std::fs::create_dir_all(to)
.with_context(|| format!("Creating {}", to.display()))?;
let read_dir = std::fs::read_dir(from)
.with_context(|| format!("Reading {}", from.display()))?;
for entry in read_dir {
let entry = entry?;
let file_type = entry.file_type()?;
let new_from = from.join(entry.file_name());
let new_to = to.join(entry.file_name());
if file_type.is_dir() {
hard_link_dir_recursive(&new_from, &new_to).with_context(|| {
format!("Dir {} to {}", new_from.display(), new_to.display())
})?;
} else if file_type.is_file() {
// note: chance for race conditions here between attempting to create,
// then removing, then attempting to create. There doesn't seem to be
// a way to hard link with overwriting in Rust, but maybe there is some
// way with platform specific code. The workaround here is to handle
// scenarios where something else might create or remove files.
if let Err(err) = std::fs::hard_link(&new_from, &new_to) {
if err.kind() == ErrorKind::AlreadyExists {
if let Err(err) = std::fs::remove_file(&new_to) {
if err.kind() == ErrorKind::NotFound {
// Assume another process/thread created this hard link to the file we are wanting
// to remove then sleep a little bit to let the other process/thread move ahead
// faster to reduce contention.
std::thread::sleep(Duration::from_millis(10));
} else {
return Err(err).with_context(|| {
format!(
"Removing file to hard link {} to {}",
new_from.display(),
new_to.display()
)
});
}
}
// Always attempt to recreate the hardlink. In contention scenarios, the other process
// might have been killed or exited after removing the file, but before creating the hardlink
if let Err(err) = std::fs::hard_link(&new_from, &new_to) {
// Assume another process/thread created this hard link to the file we are wanting
// to now create then sleep a little bit to let the other process/thread move ahead
// faster to reduce contention.
if err.kind() == ErrorKind::AlreadyExists {
std::thread::sleep(Duration::from_millis(10));
} else {
return Err(err).with_context(|| {
format!(
"Hard linking {} to {}",
new_from.display(),
new_to.display()
)
});
}
}
} else {
return Err(err).with_context(|| {
format!(
"Hard linking {} to {}",
new_from.display(),
new_to.display()
)
});
}
}
}
}
Ok(())
}
pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> { pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> {
let err_mapper = |err: Error, kind: Option<ErrorKind>| { let err_mapper = |err: Error, kind: Option<ErrorKind>| {
Error::new( Error::new(

View file

@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::Write;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
@ -52,19 +51,6 @@ pub fn get_extension(file_path: &Path) -> Option<String> {
.map(|e| e.to_lowercase()); .map(|e| e.to_lowercase());
} }
pub fn get_atomic_file_path(file_path: &Path) -> PathBuf {
let rand = gen_rand_path_component();
let extension = format!("{rand}.tmp");
file_path.with_extension(extension)
}
fn gen_rand_path_component() -> String {
(0..4).fold(String::with_capacity(8), |mut output, _| {
write!(&mut output, "{:02x}", rand::random::<u8>()).unwrap();
output
})
}
/// TypeScript figures out the type of file based on the extension, but we take /// TypeScript figures out the type of file based on the extension, but we take
/// other factors into account like the file headers. The hack here is to map the /// other factors into account like the file headers. The hack here is to map the
/// specifier passed to TypeScript to a new specifier with the file extension. /// specifier passed to TypeScript to a new specifier with the file extension.

View file

@ -140,23 +140,23 @@ mod tests {
#[test] #[test]
fn test_source_map_from_code() { fn test_source_map_from_code() {
let to_string = let to_string =
|bytes: Vec<u8>| -> String { String::from_utf8(bytes).unwrap() }; |bytes: Vec<u8>| -> String { String::from_utf8(bytes.to_vec()).unwrap() };
assert_eq!( assert_eq!(
source_map_from_code( source_map_from_code(
b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc=", b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc="
).map(to_string), ).map(to_string),
Some("testingtesting".to_string()) Some("testingtesting".to_string())
); );
assert_eq!( assert_eq!(
source_map_from_code( source_map_from_code(
b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc=\n \n", b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc=\n \n"
).map(to_string), ).map(to_string),
Some("testingtesting".to_string()) Some("testingtesting".to_string())
); );
assert_eq!( assert_eq!(
source_map_from_code( source_map_from_code(
b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc=\n test\n", b"test\n//# sourceMappingURL=data:application/json;base64,dGVzdGluZ3Rlc3Rpbmc=\n test\n"
), ).map(to_string),
None None
); );
assert_eq!( assert_eq!(
@ -164,7 +164,7 @@ mod tests {
b"\"use strict\"; b"\"use strict\";
throw new Error(\"Hello world!\"); throw new Error(\"Hello world!\");
//# sourceMappingURL=data:application/json;base64,{", //# sourceMappingURL=data:application/json;base64,{"
), ),
None None
); );

View file

@ -23,8 +23,6 @@ use deno_runtime::deno_fs;
use deno_runtime::deno_node::NodeExtInitServices; use deno_runtime::deno_node::NodeExtInitServices;
use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::NodeRequireLoaderRc; use deno_runtime::deno_node::NodeRequireLoaderRc;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_node::PackageJsonResolver;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_tls::RootCertStoreProvider; use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_web::BlobStore; use deno_runtime::deno_web::BlobStore;
@ -53,7 +51,10 @@ use crate::args::DenoSubcommand;
use crate::args::NpmCachingStrategy; use crate::args::NpmCachingStrategy;
use crate::args::StorageKeyResolver; use crate::args::StorageKeyResolver;
use crate::errors; use crate::errors;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::sys::CliSys;
use crate::util::checksum; use crate::util::checksum;
use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherCommunicator;
use crate::util::file_watcher::WatcherRestartMode; use crate::util::file_watcher::WatcherRestartMode;
@ -145,13 +146,14 @@ struct SharedWorkerState {
maybe_inspector_server: Option<Arc<InspectorServer>>, maybe_inspector_server: Option<Arc<InspectorServer>>,
maybe_lockfile: Option<Arc<CliLockfile>>, maybe_lockfile: Option<Arc<CliLockfile>>,
module_loader_factory: Box<dyn ModuleLoaderFactory>, module_loader_factory: Box<dyn ModuleLoaderFactory>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
pkg_json_resolver: Arc<PackageJsonResolver>, pkg_json_resolver: Arc<CliPackageJsonResolver>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>, root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
root_permissions: PermissionsContainer, root_permissions: PermissionsContainer,
shared_array_buffer_store: SharedArrayBufferStore, shared_array_buffer_store: SharedArrayBufferStore,
storage_key_resolver: StorageKeyResolver, storage_key_resolver: StorageKeyResolver,
sys: CliSys,
options: CliMainWorkerOptions, options: CliMainWorkerOptions,
subcommand: DenoSubcommand, subcommand: DenoSubcommand,
otel_config: OtelConfig, otel_config: OtelConfig,
@ -162,12 +164,13 @@ impl SharedWorkerState {
pub fn create_node_init_services( pub fn create_node_init_services(
&self, &self,
node_require_loader: NodeRequireLoaderRc, node_require_loader: NodeRequireLoaderRc,
) -> NodeExtInitServices { ) -> NodeExtInitServices<CliSys> {
NodeExtInitServices { NodeExtInitServices {
node_require_loader, node_require_loader,
node_resolver: self.node_resolver.clone(), node_resolver: self.node_resolver.clone(),
npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(), npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(),
pkg_json_resolver: self.pkg_json_resolver.clone(), pkg_json_resolver: self.pkg_json_resolver.clone(),
sys: self.sys.clone(),
} }
} }
@ -418,12 +421,13 @@ impl CliMainWorkerFactory {
maybe_inspector_server: Option<Arc<InspectorServer>>, maybe_inspector_server: Option<Arc<InspectorServer>>,
maybe_lockfile: Option<Arc<CliLockfile>>, maybe_lockfile: Option<Arc<CliLockfile>>,
module_loader_factory: Box<dyn ModuleLoaderFactory>, module_loader_factory: Box<dyn ModuleLoaderFactory>,
node_resolver: Arc<NodeResolver>, node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>, npm_resolver: Arc<dyn CliNpmResolver>,
pkg_json_resolver: Arc<PackageJsonResolver>, pkg_json_resolver: Arc<CliPackageJsonResolver>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>, root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
root_permissions: PermissionsContainer, root_permissions: PermissionsContainer,
storage_key_resolver: StorageKeyResolver, storage_key_resolver: StorageKeyResolver,
sys: CliSys,
subcommand: DenoSubcommand, subcommand: DenoSubcommand,
options: CliMainWorkerOptions, options: CliMainWorkerOptions,
otel_config: OtelConfig, otel_config: OtelConfig,
@ -448,6 +452,7 @@ impl CliMainWorkerFactory {
root_permissions, root_permissions,
shared_array_buffer_store: Default::default(), shared_array_buffer_store: Default::default(),
storage_key_resolver, storage_key_resolver,
sys,
options, options,
subcommand, subcommand,
otel_config, otel_config,
@ -612,6 +617,7 @@ impl CliMainWorkerFactory {
serve_port: shared.options.serve_port, serve_port: shared.options.serve_port,
serve_host: shared.options.serve_host.clone(), serve_host: shared.options.serve_host.clone(),
otel_config: shared.otel_config.clone(), otel_config: shared.otel_config.clone(),
close_on_idle: true,
}, },
extensions: custom_extensions, extensions: custom_extensions,
startup_snapshot: crate::js::deno_isolate_init(), startup_snapshot: crate::js::deno_isolate_init(),
@ -655,7 +661,10 @@ impl CliMainWorkerFactory {
"40_test_common.js", "40_test_common.js",
"40_test.js", "40_test.js",
"40_bench.js", "40_bench.js",
"40_jupyter.js" "40_jupyter.js",
// TODO(bartlomieju): probably shouldn't include these files here?
"40_lint_selector.js",
"40_lint.js"
); );
} }
@ -812,6 +821,7 @@ fn create_web_worker_callback(
serve_port: shared.options.serve_port, serve_port: shared.options.serve_port,
serve_host: shared.options.serve_host.clone(), serve_host: shared.options.serve_host.clone(),
otel_config: shared.otel_config.clone(), otel_config: shared.otel_config.clone(),
close_on_idle: args.close_on_idle,
}, },
extensions: vec![], extensions: vec![],
startup_snapshot: crate::js::deno_isolate_init(), startup_snapshot: crate::js::deno_isolate_init(),
@ -864,14 +874,15 @@ mod tests {
let main_module = let main_module =
resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap(); resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap();
let fs = Arc::new(RealFs); let fs = Arc::new(RealFs);
let permission_desc_parser = let permission_desc_parser = Arc::new(
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone())); RuntimePermissionDescriptorParser::new(crate::sys::CliSys::default()),
);
let options = WorkerOptions { let options = WorkerOptions {
startup_snapshot: crate::js::deno_isolate_init(), startup_snapshot: crate::js::deno_isolate_init(),
..Default::default() ..Default::default()
}; };
MainWorker::bootstrap_from_options( MainWorker::bootstrap_from_options::<CliSys>(
main_module, main_module,
WorkerServiceOptions { WorkerServiceOptions {
module_loader: Rc::new(FsModuleLoader), module_loader: Rc::new(FsModuleLoader),

Some files were not shown because too many files have changed in this diff Show more