0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00

Merge remote-tracking branch 'upstream/main' into show-remote-modules-size

This commit is contained in:
HasanAlrimawi 2024-12-23 11:09:04 +02:00
commit e98e110b0a
144 changed files with 10972 additions and 803 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 = 31; 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: '31-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' key: '32-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '31-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: '31-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: '31-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

234
Cargo.lock generated
View file

@ -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",
] ]
@ -677,6 +677,28 @@ 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"
@ -1224,7 +1252,7 @@ dependencies = [
"boxed_error", "boxed_error",
"bytes", "bytes",
"cache_control", "cache_control",
"capacity_builder", "capacity_builder 0.5.0",
"chrono", "chrono",
"clap", "clap",
"clap_complete", "clap_complete",
@ -1391,7 +1419,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_bench_util" name = "deno_bench_util"
version = "0.177.0" version = "0.178.0"
dependencies = [ dependencies = [
"bencher", "bencher",
"deno_core", "deno_core",
@ -1400,7 +1428,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_broadcast_channel" name = "deno_broadcast_channel"
version = "0.177.0" version = "0.178.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1411,7 +1439,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_cache" name = "deno_cache"
version = "0.115.0" version = "0.116.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1452,7 +1480,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_canvas" name = "deno_canvas"
version = "0.52.0" version = "0.53.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_webgpu", "deno_webgpu",
@ -1463,9 +1491,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_config" name = "deno_config"
version = "0.39.3" version = "0.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce717af3fe6788dae63965d58d5637fd62be8fe4f345f189137ffc06c51837d2" checksum = "8afa3beb6b9e0604cfe0380d30f88c5b758d44e228d5a5fc42ae637ccfb7d089"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_package_json", "deno_package_json",
@ -1487,16 +1515,16 @@ dependencies = [
[[package]] [[package]]
name = "deno_console" name = "deno_console"
version = "0.183.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",
@ -1504,7 +1532,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",
@ -1536,7 +1564,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]] [[package]]
name = "deno_cron" name = "deno_cron"
version = "0.63.0" version = "0.64.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1549,7 +1577,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_crypto" name = "deno_crypto"
version = "0.197.0" version = "0.198.0"
dependencies = [ dependencies = [
"aes", "aes",
"aes-gcm", "aes-gcm",
@ -1639,7 +1667,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_fetch" name = "deno_fetch"
version = "0.207.0" version = "0.208.0"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"bytes", "bytes",
@ -1651,6 +1679,7 @@ dependencies = [
"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",
@ -1667,14 +1696,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.170.0" version = "0.171.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1694,7 +1723,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_fs" name = "deno_fs"
version = "0.93.0" version = "0.94.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base32", "base32",
@ -1717,12 +1746,13 @@ dependencies = [
[[package]] [[package]]
name = "deno_graph" name = "deno_graph"
version = "0.86.3" version = "0.86.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc78ed0b4bbcb4197300f0d6e7d1edc2d2c5019cdb9dedba7ff229158441885b" checksum = "f669d96d63841d9ba10f86b161d898678ce05bc1e3c9ee1c1f7449a68eed2b64"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"capacity_builder 0.5.0",
"data-url", "data-url",
"deno_ast", "deno_ast",
"deno_semver", "deno_semver",
@ -1747,7 +1777,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_http" name = "deno_http"
version = "0.181.0" version = "0.182.0"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"async-trait", "async-trait",
@ -1786,7 +1816,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_io" name = "deno_io"
version = "0.93.0" version = "0.94.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1807,7 +1837,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_kv" name = "deno_kv"
version = "0.91.0" version = "0.92.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1857,9 +1887,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",
@ -1880,7 +1910,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_napi" name = "deno_napi"
version = "0.114.0" version = "0.115.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1908,7 +1938,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_net" name = "deno_net"
version = "0.175.0" version = "0.176.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1916,6 +1946,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",
@ -1925,7 +1956,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_node" name = "deno_node"
version = "0.120.0" version = "0.122.0"
dependencies = [ dependencies = [
"aead-gcm-stream", "aead-gcm-stream",
"aes", "aes",
@ -2017,12 +2048,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",
@ -2044,6 +2076,7 @@ dependencies = [
"boxed_error", "boxed_error",
"deno_cache_dir", "deno_cache_dir",
"deno_core", "deno_core",
"deno_error",
"deno_npm", "deno_npm",
"deno_semver", "deno_semver",
"deno_unsync", "deno_unsync",
@ -2065,9 +2098,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",
@ -2081,10 +2114,11 @@ dependencies = [
[[package]] [[package]]
name = "deno_package_json" name = "deno_package_json"
version = "0.2.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80b0a3d81c592624a1ae15332a04b4dc2b7c163ef1dfc7c60171f736d1babdf5" checksum = "81d72db99fdebfc371d7be16972c18a47daa7a29cb5fbb3900ab2114b1f42d96"
dependencies = [ dependencies = [
"boxed_error",
"deno_error", "deno_error",
"deno_path_util", "deno_path_util",
"deno_semver", "deno_semver",
@ -2111,7 +2145,7 @@ dependencies = [
name = "deno_permissions" name = "deno_permissions"
version = "0.43.0" version = "0.43.0"
dependencies = [ dependencies = [
"capacity_builder", "capacity_builder 0.5.0",
"deno_core", "deno_core",
"deno_path_util", "deno_path_util",
"deno_terminal 0.2.0", "deno_terminal 0.2.0",
@ -2216,11 +2250,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",
@ -2248,7 +2285,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_telemetry" name = "deno_telemetry"
version = "0.5.0" version = "0.6.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -2289,7 +2326,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_tls" name = "deno_tls"
version = "0.170.0" version = "0.171.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_native_certs", "deno_native_certs",
@ -2322,7 +2359,7 @@ dependencies = [
"serde_json", "serde_json",
"tokio", "tokio",
"tokio-util", "tokio-util",
"tower", "tower 0.4.13",
"tracing", "tracing",
] ]
@ -2339,7 +2376,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_url" name = "deno_url"
version = "0.183.0" version = "0.184.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_console", "deno_console",
@ -2351,7 +2388,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_web" name = "deno_web"
version = "0.214.0" version = "0.215.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64-simd 0.8.0", "base64-simd 0.8.0",
@ -2373,7 +2410,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webgpu" name = "deno_webgpu"
version = "0.150.0" version = "0.151.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"raw-window-handle", "raw-window-handle",
@ -2386,7 +2423,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webidl" name = "deno_webidl"
version = "0.183.0" version = "0.184.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_core", "deno_core",
@ -2394,7 +2431,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_websocket" name = "deno_websocket"
version = "0.188.0" version = "0.189.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"deno_core", "deno_core",
@ -2416,7 +2453,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webstorage" name = "deno_webstorage"
version = "0.178.0" version = "0.179.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_web", "deno_web",
@ -2887,6 +2924,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"
@ -3823,6 +3869,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"
@ -4023,9 +4080,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",
@ -4552,9 +4609,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"
@ -4930,7 +4987,7 @@ dependencies = [
[[package]] [[package]]
name = "napi_sym" name = "napi_sym"
version = "0.113.0" version = "0.114.0"
dependencies = [ dependencies = [
"quote", "quote",
"serde", "serde",
@ -5906,49 +5963,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]]
@ -6425,6 +6487,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"
@ -6708,9 +6773,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",
@ -6986,6 +7051,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"
@ -7976,7 +8047,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",
@ -8002,6 +8073,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"
@ -8030,9 +8116,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"
@ -8506,6 +8592,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"
@ -8533,7 +8629,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",
@ -8565,7 +8661,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.177.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.41.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.2" deno_path_util = "=0.2.2"
deno_permissions = { version = "0.43.0", path = "./runtime/permissions" } deno_permissions = { version = "0.43.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.192.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.113.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,29 +69,29 @@ 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.177.0", path = "./ext/broadcast_channel" } deno_broadcast_channel = { version = "0.178.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.115.0", path = "./ext/cache" } deno_cache = { version = "0.116.0", path = "./ext/cache" }
deno_canvas = { version = "0.52.0", path = "./ext/canvas" } deno_canvas = { version = "0.53.0", path = "./ext/canvas" }
deno_console = { version = "0.183.0", path = "./ext/console" } deno_console = { version = "0.184.0", path = "./ext/console" }
deno_cron = { version = "0.63.0", path = "./ext/cron" } deno_cron = { version = "0.64.0", path = "./ext/cron" }
deno_crypto = { version = "0.197.0", path = "./ext/crypto" } deno_crypto = { version = "0.198.0", path = "./ext/crypto" }
deno_fetch = { version = "0.207.0", path = "./ext/fetch" } deno_fetch = { version = "0.208.0", path = "./ext/fetch" }
deno_ffi = { version = "0.170.0", path = "./ext/ffi" } deno_ffi = { version = "0.171.0", path = "./ext/ffi" }
deno_fs = { version = "0.93.0", path = "./ext/fs" } deno_fs = { version = "0.94.0", path = "./ext/fs" }
deno_http = { version = "0.181.0", path = "./ext/http" } deno_http = { version = "0.182.0", path = "./ext/http" }
deno_io = { version = "0.93.0", path = "./ext/io" } deno_io = { version = "0.94.0", path = "./ext/io" }
deno_kv = { version = "0.91.0", path = "./ext/kv" } deno_kv = { version = "0.92.0", path = "./ext/kv" }
deno_napi = { version = "0.114.0", path = "./ext/napi" } deno_napi = { version = "0.115.0", path = "./ext/napi" }
deno_net = { version = "0.175.0", path = "./ext/net" } deno_net = { version = "0.176.0", path = "./ext/net" }
deno_node = { version = "0.120.0", path = "./ext/node" } deno_node = { version = "0.122.0", path = "./ext/node" }
deno_telemetry = { version = "0.5.0", path = "./ext/telemetry" } deno_telemetry = { version = "0.6.0", path = "./ext/telemetry" }
deno_tls = { version = "0.170.0", path = "./ext/tls" } deno_tls = { version = "0.171.0", path = "./ext/tls" }
deno_url = { version = "0.183.0", path = "./ext/url" } deno_url = { version = "0.184.0", path = "./ext/url" }
deno_web = { version = "0.214.0", path = "./ext/web" } deno_web = { version = "0.215.0", path = "./ext/web" }
deno_webgpu = { version = "0.150.0", path = "./ext/webgpu" } deno_webgpu = { version = "0.151.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.183.0", path = "./ext/webidl" } deno_webidl = { version = "0.184.0", path = "./ext/webidl" }
deno_websocket = { version = "0.188.0", path = "./ext/websocket" } deno_websocket = { version = "0.189.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.178.0", path = "./ext/webstorage" } deno_webstorage = { version = "0.179.0", path = "./ext/webstorage" }
# resolvers # resolvers
deno_npm_cache = { version = "0.3.0", path = "./resolvers/npm_cache" } deno_npm_cache = { version = "0.3.0", path = "./resolvers/npm_cache" }
@ -108,7 +108,7 @@ 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.3" 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()
@ -120,7 +120,7 @@ data-encoding = "2.3.3"
data-url = "=0.3.1" data-url = "=0.3.1"
deno_cache_dir = "=0.15.0" deno_cache_dir = "=0.15.0"
deno_error = "=0.5.2" deno_error = "=0.5.2"
deno_package_json = { version = "0.2.1", default-features = false } deno_package_json = { version = "0.3.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"
@ -149,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
@ -202,7 +202,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.177.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

@ -74,7 +74,7 @@ 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_error.workspace = true deno_error.workspace = true
deno_graph = { version = "=0.86.3" } deno_graph = { version = "=0.86.5" }
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

View file

@ -31,6 +31,7 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
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;
@ -992,24 +993,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!(
@ -1363,9 +1364,9 @@ impl CliOptions {
Ok(DenoLintConfig { 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),
}) })
} }
@ -1946,15 +1947,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

@ -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

@ -52,6 +52,7 @@ use deno_runtime::deno_node;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq; use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::SmallStackString;
use import_map::ImportMapError; use import_map::ImportMapError;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use std::collections::HashSet; use std::collections::HashSet;
@ -680,7 +681,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>(),
); );
} }
} }

View file

@ -145,9 +145,7 @@ impl HttpClient {
} }
pub fn get(&self, url: Url) -> Result<RequestBuilder, http::Error> { pub fn get(&self, url: Url) -> Result<RequestBuilder, http::Error> {
let body = http_body_util::Empty::new() let body = deno_fetch::ReqBody::empty();
.map_err(|never| match never {})
.boxed();
let mut req = http::Request::new(body); let mut req = http::Request::new(body);
*req.uri_mut() = url.as_str().parse()?; *req.uri_mut() = url.as_str().parse()?;
Ok(RequestBuilder { Ok(RequestBuilder {
@ -179,9 +177,7 @@ impl HttpClient {
S: serde::Serialize, S: serde::Serialize,
{ {
let json = deno_core::serde_json::to_vec(ser)?; let json = deno_core::serde_json::to_vec(ser)?;
let body = http_body_util::Full::new(json.into()) let body = deno_fetch::ReqBody::full(json.into());
.map_err(|never| match never {})
.boxed();
let builder = self.post(url, body)?; let builder = self.post(url, body)?;
Ok(builder.header( Ok(builder.header(
http::header::CONTENT_TYPE, http::header::CONTENT_TYPE,
@ -194,9 +190,7 @@ impl HttpClient {
url: &Url, url: &Url,
headers: HeaderMap, headers: HeaderMap,
) -> Result<http::Response<ResBody>, SendError> { ) -> Result<http::Response<ResBody>, SendError> {
let body = http_body_util::Empty::new() let body = deno_fetch::ReqBody::empty();
.map_err(|never| match never {})
.boxed();
let mut request = http::Request::new(body); let mut request = http::Request::new(body);
*request.uri_mut() = http::Uri::try_from(url.as_str())?; *request.uri_mut() = http::Uri::try_from(url.as_str())?;
*request.headers_mut() = headers; *request.headers_mut() = headers;

1097
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

@ -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;
@ -278,9 +280,16 @@ impl<'a> TsResponseImportMapper<'a> {
{ {
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 };
@ -290,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?;
@ -603,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.
@ -622,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

@ -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

@ -18,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;
@ -33,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>,
} }
@ -59,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(
@ -125,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();
@ -144,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());
@ -216,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();
} }
@ -226,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
} }

View file

@ -1855,20 +1855,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 +1904,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
@ -3793,7 +3781,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

@ -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

@ -996,7 +996,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 +1008,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(

View file

@ -560,11 +560,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

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

@ -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

@ -38,6 +38,7 @@ use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder;
use deno_runtime::deno_fs; 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;
@ -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();
@ -1012,10 +1015,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)) => {

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

@ -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

@ -91,6 +91,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 +99,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 +205,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") {
@ -256,6 +265,7 @@ pub struct StandaloneData {
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 +293,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 +316,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 +348,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,11 +372,12 @@ 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,
}; };
@ -372,6 +394,7 @@ pub fn extract_standalone(
}, },
npm_snapshot, npm_snapshot,
root_path, root_path,
source_maps,
vfs, vfs,
})) }))
} }
@ -451,7 +474,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 +577,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>,
@ -616,71 +639,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);
@ -713,6 +746,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 {
@ -765,7 +820,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(),
@ -832,6 +887,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,
) )
@ -926,10 +982,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)
@ -948,11 +1004,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
@ -960,10 +1016,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);
@ -973,11 +1026,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());
@ -988,7 +1037,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

@ -55,6 +55,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;
@ -122,6 +123,7 @@ struct SharedModuleLoaderState {
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 +398,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 +501,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 {
@ -590,6 +635,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
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(None));
@ -841,6 +887,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,
}), }),

View file

@ -6,6 +6,8 @@ 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;
@ -20,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";
@ -33,21 +38,22 @@ 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> {
let metadata = serde_json::to_string(metadata)?; let metadata = serde_json::to_string(metadata)?;
let npm_snapshot = let npm_snapshot =
npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default(); npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default();
let remote_modules_len = Cell::new(0_u64); let serialized_vfs = serde_json::to_string(&vfs.entries)?;
let serialized_vfs = serde_json::to_string(&vfs.root)?;
let bytes = capacity_builder::BytesBuilder::build(|builder| { let bytes = capacity_builder::BytesBuilder::build(|builder| {
builder.append(MAGIC_BYTES); builder.append(MAGIC_BYTES);
@ -63,10 +69,7 @@ pub fn serialize_binary_data_section(
} }
// 3. Remote modules // 3. Remote modules
{ {
builder.append_le(remote_modules_len.get()); // this will be properly initialized on the second pass
let start_index = builder.len();
remote_modules.write(builder); remote_modules.write(builder);
remote_modules_len.set((builder.len() - start_index) as u64);
} }
// 4. VFS // 4. VFS
{ {
@ -78,6 +81,16 @@ pub fn serialize_binary_data_section(
builder.append(file); builder.append(file);
} }
} }
// 5. Source maps
{
builder.append_le(source_map_store.data.len() as u32);
for (specifier, source_map) in &source_map_store.data {
builder.append_le(specifier.len() as u32);
builder.append(specifier);
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
@ -91,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.");
@ -115,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)?;
@ -154,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,
})) }))
} }
@ -162,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>) {
@ -188,12 +226,15 @@ impl RemoteModulesStoreBuilder {
} }
} }
fn write<'a>(&'a self, builder: &mut capacity_builder::BytesBuilder<'a>) { fn write<'a, TBytes: capacity_builder::BytesType>(
&'a self,
builder: &mut capacity_builder::BytesBuilder<'a, TBytes>,
) {
builder.append_le(self.specifiers.len() as u32); builder.append_le(self.specifiers.len() as u32);
builder.append_le(self.redirects.len() as u32); builder.append_le(self.redirects.len() as u32);
for (specifier, offset) in &self.specifiers { for (specifier, offset) in &self.specifiers {
builder.append_le(specifier.len() as u32); builder.append_le(specifier.len() as u32);
builder.append(specifier.as_bytes()); builder.append(specifier);
builder.append_le(*offset); builder.append_le(*offset);
} }
for (from, to) in &self.redirects { for (from, to) in &self.redirects {
@ -202,10 +243,32 @@ impl RemoteModulesStoreBuilder {
builder.append_le(to.len() as u32); builder.append_le(to.len() as u32);
builder.append(to); builder.append(to);
} }
for (media_type, data) in &self.data { builder.append_le(
self
.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(serialize_media_type(*media_type));
builder.append_le(data.len() as u64); builder.append_le(data.len() as u32);
builder.append(data); 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);
}
} }
} }
} }
@ -234,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,
@ -280,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),
@ -291,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)?;
@ -334,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>(
@ -370,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 {
@ -386,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 => {
@ -475,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)?)))
} }
} }
@ -630,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

@ -67,7 +67,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 +95,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 +208,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 +245,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 +311,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 +327,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 +375,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 +417,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 +445,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 +471,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 +497,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 +687,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 +751,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 +812,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 +827,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();
} }
@ -961,27 +949,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,20 +1167,13 @@ 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))
@ -1706,7 +1730,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,
}, },

View file

@ -198,7 +198,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
@ -625,7 +625,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

@ -343,14 +343,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

@ -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

@ -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;
} }

View file

@ -0,0 +1,518 @@
// 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);
#[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,
prop_count: usize,
) -> NodeRef;
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 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>,
}
/// 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 + 1],
prop_map: vec![0; prop_size + 1],
};
ctx.str_table.insert("");
// Placeholder node is always 0
ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0);
ctx.kind_map[0] = 0;
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] = type_str;
ctx.prop_map[1] = parent_str;
ctx.prop_map[2] = range_str;
ctx.prop_map[3] = 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,
{
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,
) -> NodeRef {
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);
NodeRef(offset)
}
/// 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,
prop_count: usize,
) -> NodeRef
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;
}
}
self.append_node(n, parent, span, prop_count)
}
/// 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,515 @@
// 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::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 three must be in sync with JS. The
// order here for these 3 fields is important.
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::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_count: u8 = AstNode::TSEnumBody.into();
let prop_count: u8 = AstProp::Value.into();
Self {
ctx: SerializeCtx::new(kind_count, prop_count),
}
}
}
impl AstBufSerializer<AstNode, AstProp> for TsEsTreeBuilder {
fn header(
&mut self,
kind: AstNode,
parent: NodeRef,
span: &Span,
prop_count: usize,
) -> NodeRef {
self.ctx.header(kind, parent, span, prop_count)
}
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

@ -51,10 +51,13 @@ 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;

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

@ -15,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;
@ -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)
} }
@ -549,10 +550,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 +684,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 +706,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 +754,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 +770,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 +790,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 +883,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 +899,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 +910,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 +919,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

@ -27,6 +27,7 @@ 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::Version;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use import_map::ImportMap; use import_map::ImportMap;
@ -139,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 {
@ -164,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(),
} }
} }
} }
@ -217,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)
}) })
})) }))
@ -338,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 {
@ -353,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());
@ -362,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,
}) })
} }
@ -377,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,
); );
} }

View file

@ -8,6 +8,7 @@ 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;
@ -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)]

View file

@ -231,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,
}, },
@ -448,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
@ -469,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,
@ -837,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,
}, },
@ -873,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

View file

@ -616,7 +616,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),

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

@ -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

@ -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

@ -612,6 +612,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 +656,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 +816,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(),

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_broadcast_channel" name = "deno_broadcast_channel"
version = "0.177.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

@ -2,7 +2,7 @@
[package] [package]
name = "deno_cache" name = "deno_cache"
version = "0.115.0" version = "0.116.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_canvas" name = "deno_canvas"
version = "0.52.0" version = "0.53.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_console" name = "deno_console"
version = "0.183.0" version = "0.184.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_cron" name = "deno_cron"
version = "0.63.0" version = "0.64.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_crypto" name = "deno_crypto"
version = "0.197.0" version = "0.198.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -13,6 +13,7 @@
import { core, primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const { const {
BadResourcePrototype,
isAnyArrayBuffer, isAnyArrayBuffer,
isArrayBuffer, isArrayBuffer,
isStringObject, isStringObject,
@ -26,6 +27,7 @@ const {
JSONParse, JSONParse,
ObjectDefineProperties, ObjectDefineProperties,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
PromisePrototypeCatch,
TypedArrayPrototypeGetBuffer, TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteLength, TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetByteOffset, TypedArrayPrototypeGetByteOffset,
@ -160,7 +162,18 @@ class InnerBody {
) )
) { ) {
readableStreamThrowIfErrored(this.stream); readableStreamThrowIfErrored(this.stream);
return readableStreamCollectIntoUint8Array(this.stream); return PromisePrototypeCatch(
readableStreamCollectIntoUint8Array(this.stream),
(e) => {
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, e)) {
// TODO(kt3k): We probably like to pass e as `cause` if BadResource supports it.
throw new e.constructor(
"Cannot read body as underlying resource unavailable",
);
}
throw e;
},
);
} else { } else {
this.streamOrStatic.consumed = true; this.streamOrStatic.consumed = true;
return this.streamOrStatic.body; return this.streamOrStatic.body;

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_fetch" name = "deno_fetch"
version = "0.207.0" version = "0.208.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -23,6 +23,7 @@ deno_permissions.workspace = true
deno_tls.workspace = true deno_tls.workspace = true
dyn-clone = "1" dyn-clone = "1"
error_reporter = "1" error_reporter = "1"
h2.workspace = true
hickory-resolver.workspace = true hickory-resolver.workspace = true
http.workspace = true http.workspace = true
http-body-util.workspace = true http-body-util.workspace = true

View file

@ -10,6 +10,7 @@ use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::min; use std::cmp::min;
use std::convert::From; use std::convert::From;
use std::future;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
@ -66,6 +67,7 @@ use http::header::USER_AGENT;
use http::Extensions; use http::Extensions;
use http::Method; use http::Method;
use http::Uri; use http::Uri;
use http_body_util::combinators::BoxBody;
use http_body_util::BodyExt; use http_body_util::BodyExt;
use hyper::body::Frame; use hyper::body::Frame;
use hyper_util::client::legacy::connect::HttpConnector; use hyper_util::client::legacy::connect::HttpConnector;
@ -75,6 +77,7 @@ use hyper_util::rt::TokioExecutor;
use hyper_util::rt::TokioTimer; use hyper_util::rt::TokioTimer;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use tower::retry;
use tower::ServiceExt; use tower::ServiceExt;
use tower_http::decompression::Decompression; use tower_http::decompression::Decompression;
@ -476,9 +479,7 @@ where
// If a body is passed, we use it, and don't return a body for streaming. // If a body is passed, we use it, and don't return a body for streaming.
con_len = Some(data.len() as u64); con_len = Some(data.len() as u64);
http_body_util::Full::new(data.to_vec().into()) ReqBody::full(data.to_vec().into())
.map_err(|never| match never {})
.boxed()
} }
(_, Some(resource)) => { (_, Some(resource)) => {
let resource = state let resource = state
@ -491,7 +492,7 @@ where
} }
_ => {} _ => {}
} }
ReqBody::new(ResourceToBodyAdapter::new(resource)) ReqBody::streaming(ResourceToBodyAdapter::new(resource))
} }
(None, None) => unreachable!(), (None, None) => unreachable!(),
} }
@ -501,9 +502,7 @@ where
if matches!(method, Method::POST | Method::PUT) { if matches!(method, Method::POST | Method::PUT) {
con_len = Some(0); con_len = Some(0);
} }
http_body_util::Empty::new() ReqBody::empty()
.map_err(|never| match never {})
.boxed()
}; };
let mut request = http::Request::new(body); let mut request = http::Request::new(body);
@ -1066,7 +1065,8 @@ pub fn create_http_client(
} }
let pooled_client = builder.build(connector); let pooled_client = builder.build(connector);
let decompress = Decompression::new(pooled_client).gzip(true).br(true); let retry_client = retry::Retry::new(FetchRetry, pooled_client);
let decompress = Decompression::new(retry_client).gzip(true).br(true);
Ok(Client { Ok(Client {
inner: decompress, inner: decompress,
@ -1083,7 +1083,12 @@ pub fn op_utf8_to_byte_string(#[string] input: String) -> ByteString {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Client { pub struct Client {
inner: Decompression<hyper_util::client::legacy::Client<Connector, ReqBody>>, inner: Decompression<
retry::Retry<
FetchRetry,
hyper_util::client::legacy::Client<Connector, ReqBody>,
>,
>,
// Used to check whether to include a proxy-authorization header // Used to check whether to include a proxy-authorization header
proxies: Arc<proxy::Proxies>, proxies: Arc<proxy::Proxies>,
user_agent: HeaderValue, user_agent: HeaderValue,
@ -1174,10 +1179,70 @@ impl Client {
} }
} }
pub type ReqBody = // This is a custom enum to allow the retry policy to clone the variants that could be retried.
http_body_util::combinators::BoxBody<Bytes, deno_core::error::AnyError>; pub enum ReqBody {
pub type ResBody = Full(http_body_util::Full<Bytes>),
http_body_util::combinators::BoxBody<Bytes, deno_core::error::AnyError>; Empty(http_body_util::Empty<Bytes>),
Streaming(BoxBody<Bytes, deno_core::error::AnyError>),
}
pub type ResBody = BoxBody<Bytes, deno_core::error::AnyError>;
impl ReqBody {
pub fn full(bytes: Bytes) -> Self {
ReqBody::Full(http_body_util::Full::new(bytes))
}
pub fn empty() -> Self {
ReqBody::Empty(http_body_util::Empty::new())
}
pub fn streaming<B>(body: B) -> Self
where
B: hyper::body::Body<Data = Bytes, Error = deno_core::error::AnyError>
+ Send
+ Sync
+ 'static,
{
ReqBody::Streaming(BoxBody::new(body))
}
}
impl hyper::body::Body for ReqBody {
type Data = Bytes;
type Error = deno_core::error::AnyError;
fn poll_frame(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
match &mut *self {
ReqBody::Full(ref mut b) => {
Pin::new(b).poll_frame(cx).map_err(|never| match never {})
}
ReqBody::Empty(ref mut b) => {
Pin::new(b).poll_frame(cx).map_err(|never| match never {})
}
ReqBody::Streaming(ref mut b) => Pin::new(b).poll_frame(cx),
}
}
fn is_end_stream(&self) -> bool {
match self {
ReqBody::Full(ref b) => b.is_end_stream(),
ReqBody::Empty(ref b) => b.is_end_stream(),
ReqBody::Streaming(ref b) => b.is_end_stream(),
}
}
fn size_hint(&self) -> hyper::body::SizeHint {
match self {
ReqBody::Full(ref b) => b.size_hint(),
ReqBody::Empty(ref b) => b.size_hint(),
ReqBody::Streaming(ref b) => b.size_hint(),
}
}
}
/// Copied from https://github.com/seanmonstar/reqwest/blob/b9d62a0323d96f11672a61a17bf8849baec00275/src/async_impl/request.rs#L572 /// Copied from https://github.com/seanmonstar/reqwest/blob/b9d62a0323d96f11672a61a17bf8849baec00275/src/async_impl/request.rs#L572
/// Check the request URL for a "username:password" type authority, and if /// Check the request URL for a "username:password" type authority, and if
@ -1214,3 +1279,102 @@ pub fn extract_authority(url: &mut Url) -> Option<(String, Option<String>)> {
fn op_fetch_promise_is_settled(promise: v8::Local<v8::Promise>) -> bool { fn op_fetch_promise_is_settled(promise: v8::Local<v8::Promise>) -> bool {
promise.state() != v8::PromiseState::Pending promise.state() != v8::PromiseState::Pending
} }
/// Deno.fetch's retry policy.
#[derive(Clone, Debug)]
struct FetchRetry;
/// Marker extension that a request has been retried once.
#[derive(Clone, Debug)]
struct Retried;
impl<ResBody, E>
retry::Policy<http::Request<ReqBody>, http::Response<ResBody>, E>
for FetchRetry
where
E: std::error::Error + 'static,
{
/// Don't delay retries.
type Future = future::Ready<()>;
fn retry(
&mut self,
req: &mut http::Request<ReqBody>,
result: &mut Result<http::Response<ResBody>, E>,
) -> Option<Self::Future> {
if req.extensions().get::<Retried>().is_some() {
// only retry once
return None;
}
match result {
Ok(..) => {
// never retry a Response
None
}
Err(err) => {
if is_error_retryable(&*err) {
req.extensions_mut().insert(Retried);
Some(future::ready(()))
} else {
None
}
}
}
}
fn clone_request(
&mut self,
req: &http::Request<ReqBody>,
) -> Option<http::Request<ReqBody>> {
let body = match req.body() {
ReqBody::Full(b) => ReqBody::Full(b.clone()),
ReqBody::Empty(b) => ReqBody::Empty(*b),
ReqBody::Streaming(..) => return None,
};
let mut clone = http::Request::new(body);
*clone.method_mut() = req.method().clone();
*clone.uri_mut() = req.uri().clone();
*clone.headers_mut() = req.headers().clone();
*clone.extensions_mut() = req.extensions().clone();
Some(clone)
}
}
fn is_error_retryable(err: &(dyn std::error::Error + 'static)) -> bool {
// Note: hyper doesn't promise it will always be this h2 version. Keep up to date.
if let Some(err) = find_source::<h2::Error>(err) {
// They sent us a graceful shutdown, try with a new connection!
if err.is_go_away()
&& err.is_remote()
&& err.reason() == Some(h2::Reason::NO_ERROR)
{
return true;
}
// REFUSED_STREAM was sent from the server, which is safe to retry.
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.7-3.2
if err.is_reset()
&& err.is_remote()
&& err.reason() == Some(h2::Reason::REFUSED_STREAM)
{
return true;
}
}
false
}
fn find_source<'a, E: std::error::Error + 'static>(
err: &'a (dyn std::error::Error + 'static),
) -> Option<&'a E> {
let mut err = Some(err);
while let Some(src) = err {
if let Some(found) = src.downcast_ref::<E>() {
return Some(found);
}
err = src.source();
}
None
}

View file

@ -133,11 +133,7 @@ async fn rust_test_client_with_resolver(
let req = http::Request::builder() let req = http::Request::builder()
.uri(format!("https://{}/foo", src_addr)) .uri(format!("https://{}/foo", src_addr))
.body( .body(crate::ReqBody::empty())
http_body_util::Empty::new()
.map_err(|err| match err {})
.boxed(),
)
.unwrap(); .unwrap();
let resp = client.send(req).await.unwrap(); let resp = client.send(req).await.unwrap();
assert_eq!(resp.status(), http::StatusCode::OK); assert_eq!(resp.status(), http::StatusCode::OK);

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_ffi" name = "deno_ffi"
version = "0.170.0" version = "0.171.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -77,6 +77,7 @@ const {
Error, Error,
Function, Function,
MathTrunc, MathTrunc,
Number,
ObjectEntries, ObjectEntries,
ObjectDefineProperty, ObjectDefineProperty,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
@ -373,12 +374,12 @@ function parseFileInfo(response) {
isDirectory: response.isDirectory, isDirectory: response.isDirectory,
isSymlink: response.isSymlink, isSymlink: response.isSymlink,
size: response.size, size: response.size,
mtime: response.mtimeSet === true ? new Date(response.mtime) : null, mtime: response.mtimeSet === true ? new Date(Number(response.mtime)) : null,
atime: response.atimeSet === true ? new Date(response.atime) : null, atime: response.atimeSet === true ? new Date(Number(response.atime)) : null,
birthtime: response.birthtimeSet === true birthtime: response.birthtimeSet === true
? new Date(response.birthtime) ? new Date(response.birthtime)
: null, : null,
ctime: response.ctimeSet === true ? new Date(response.ctime) : null, ctime: response.ctimeSet === true ? new Date(Number(response.ctime)) : null,
dev: response.dev, dev: response.dev,
mode: response.mode, mode: response.mode,
ino: unix ? response.ino : null, ino: unix ? response.ino : null,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_fs" name = "deno_fs"
version = "0.93.0" version = "0.94.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_http" name = "deno_http"
version = "0.181.0" version = "0.182.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_io" name = "deno_io"
version = "0.93.0" version = "0.94.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_kv" name = "deno_kv"
version = "0.91.0" version = "0.92.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -122,9 +122,7 @@ impl RemoteTransport for FetchClient {
headers: http::HeaderMap, headers: http::HeaderMap,
body: Bytes, body: Bytes,
) -> Result<(Url, http::StatusCode, Self::Response), anyhow::Error> { ) -> Result<(Url, http::StatusCode, Self::Response), anyhow::Error> {
let body = http_body_util::Full::new(body) let body = deno_fetch::ReqBody::full(body);
.map_err(|never| match never {})
.boxed();
let mut req = http::Request::new(body); let mut req = http::Request::new(body);
*req.method_mut() = http::Method::POST; *req.method_mut() = http::Method::POST;
*req.uri_mut() = url.as_str().parse()?; *req.uri_mut() = url.as_str().parse()?;

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_napi" name = "deno_napi"
version = "0.114.0" version = "0.115.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "napi_sym" name = "napi_sym"
version = "0.113.0" version = "0.114.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

367
ext/net/03_quic.js Normal file
View file

@ -0,0 +1,367 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core, primordials } from "ext:core/mod.js";
import {
op_quic_accept,
op_quic_accept_bi,
op_quic_accept_incoming,
op_quic_accept_uni,
op_quic_close_connection,
op_quic_close_endpoint,
op_quic_connect,
op_quic_connection_closed,
op_quic_connection_get_protocol,
op_quic_connection_get_remote_addr,
op_quic_endpoint_get_addr,
op_quic_get_send_stream_priority,
op_quic_incoming_accept,
op_quic_incoming_ignore,
op_quic_incoming_local_ip,
op_quic_incoming_refuse,
op_quic_incoming_remote_addr,
op_quic_incoming_remote_addr_validated,
op_quic_listen,
op_quic_max_datagram_size,
op_quic_open_bi,
op_quic_open_uni,
op_quic_read_datagram,
op_quic_send_datagram,
op_quic_set_send_stream_priority,
} from "ext:core/ops";
import {
getWritableStreamResourceBacking,
ReadableStream,
readableStreamForRid,
WritableStream,
writableStreamForRid,
} from "ext:deno_web/06_streams.js";
import { loadTlsKeyPair } from "ext:deno_net/02_tls.js";
const {
BadResourcePrototype,
} = core;
const {
Uint8Array,
TypedArrayPrototypeSubarray,
SymbolAsyncIterator,
SafePromisePrototypeFinally,
ObjectPrototypeIsPrototypeOf,
} = primordials;
class QuicSendStream extends WritableStream {
get sendOrder() {
return op_quic_get_send_stream_priority(
getWritableStreamResourceBacking(this).rid,
);
}
set sendOrder(p) {
op_quic_set_send_stream_priority(
getWritableStreamResourceBacking(this).rid,
p,
);
}
}
class QuicReceiveStream extends ReadableStream {}
function readableStream(rid, closed) {
// stream can be indirectly closed by closing connection.
SafePromisePrototypeFinally(closed, () => {
core.tryClose(rid);
});
return readableStreamForRid(rid, true, QuicReceiveStream);
}
function writableStream(rid, closed) {
// stream can be indirectly closed by closing connection.
SafePromisePrototypeFinally(closed, () => {
core.tryClose(rid);
});
return writableStreamForRid(rid, true, QuicSendStream);
}
class QuicBidirectionalStream {
#readable;
#writable;
constructor(txRid, rxRid, closed) {
this.#readable = readableStream(rxRid, closed);
this.#writable = writableStream(txRid, closed);
}
get readable() {
return this.#readable;
}
get writable() {
return this.#writable;
}
}
async function* bidiStream(conn, closed) {
try {
while (true) {
const r = await op_quic_accept_bi(conn);
yield new QuicBidirectionalStream(r[0], r[1], closed);
}
} catch (error) {
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
return;
}
throw error;
}
}
async function* uniStream(conn, closed) {
try {
while (true) {
const uniRid = await op_quic_accept_uni(conn);
yield readableStream(uniRid, closed);
}
} catch (error) {
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
return;
}
throw error;
}
}
class QuicConn {
#resource;
#bidiStream = null;
#uniStream = null;
#closed;
constructor(resource) {
this.#resource = resource;
this.#closed = op_quic_connection_closed(this.#resource);
core.unrefOpPromise(this.#closed);
}
get protocol() {
return op_quic_connection_get_protocol(this.#resource);
}
get remoteAddr() {
return op_quic_connection_get_remote_addr(this.#resource);
}
async createBidirectionalStream(
{ sendOrder, waitUntilAvailable } = { __proto__: null },
) {
const { 0: txRid, 1: rxRid } = await op_quic_open_bi(
this.#resource,
waitUntilAvailable ?? false,
);
if (sendOrder !== null && sendOrder !== undefined) {
op_quic_set_send_stream_priority(txRid, sendOrder);
}
return new QuicBidirectionalStream(txRid, rxRid, this.#closed);
}
async createUnidirectionalStream(
{ sendOrder, waitUntilAvailable } = { __proto__: null },
) {
const rid = await op_quic_open_uni(
this.#resource,
waitUntilAvailable ?? false,
);
if (sendOrder !== null && sendOrder !== undefined) {
op_quic_set_send_stream_priority(rid, sendOrder);
}
return writableStream(rid, this.#closed);
}
get incomingBidirectionalStreams() {
if (this.#bidiStream === null) {
this.#bidiStream = ReadableStream.from(
bidiStream(this.#resource, this.#closed),
);
}
return this.#bidiStream;
}
get incomingUnidirectionalStreams() {
if (this.#uniStream === null) {
this.#uniStream = ReadableStream.from(
uniStream(this.#resource, this.#closed),
);
}
return this.#uniStream;
}
get maxDatagramSize() {
return op_quic_max_datagram_size(this.#resource);
}
async readDatagram(p) {
const view = p || new Uint8Array(this.maxDatagramSize);
const nread = await op_quic_read_datagram(this.#resource, view);
return TypedArrayPrototypeSubarray(view, 0, nread);
}
async sendDatagram(data) {
await op_quic_send_datagram(this.#resource, data);
}
get closed() {
core.refOpPromise(this.#closed);
return this.#closed;
}
close({ closeCode, reason }) {
op_quic_close_connection(this.#resource, closeCode, reason);
}
}
class QuicIncoming {
#incoming;
constructor(incoming) {
this.#incoming = incoming;
}
get localIp() {
return op_quic_incoming_local_ip(this.#incoming);
}
get remoteAddr() {
return op_quic_incoming_remote_addr(this.#incoming);
}
get remoteAddressValidated() {
return op_quic_incoming_remote_addr_validated(this.#incoming);
}
async accept() {
const conn = await op_quic_incoming_accept(this.#incoming);
return new QuicConn(conn);
}
refuse() {
op_quic_incoming_refuse(this.#incoming);
}
ignore() {
op_quic_incoming_ignore(this.#incoming);
}
}
class QuicListener {
#endpoint;
constructor(endpoint) {
this.#endpoint = endpoint;
}
get addr() {
return op_quic_endpoint_get_addr(this.#endpoint);
}
async accept() {
const conn = await op_quic_accept(this.#endpoint);
return new QuicConn(conn);
}
async incoming() {
const incoming = await op_quic_accept_incoming(this.#endpoint);
return new QuicIncoming(incoming);
}
async next() {
let conn;
try {
conn = await this.accept();
} catch (error) {
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
return { value: undefined, done: true };
}
throw error;
}
return { value: conn, done: false };
}
[SymbolAsyncIterator]() {
return this;
}
close({ closeCode, reason }) {
op_quic_close_endpoint(this.#endpoint, closeCode, reason);
}
}
async function listenQuic(
{
hostname,
port,
cert,
key,
alpnProtocols,
keepAliveInterval,
maxIdleTimeout,
maxConcurrentBidirectionalStreams,
maxConcurrentUnidirectionalStreams,
},
) {
hostname = hostname || "0.0.0.0";
const keyPair = loadTlsKeyPair("Deno.listenQuic", { cert, key });
const endpoint = await op_quic_listen(
{ hostname, port },
{ alpnProtocols },
{
keepAliveInterval,
maxIdleTimeout,
maxConcurrentBidirectionalStreams,
maxConcurrentUnidirectionalStreams,
},
keyPair,
);
return new QuicListener(endpoint);
}
async function connectQuic(
{
hostname,
port,
serverName,
caCerts,
cert,
key,
alpnProtocols,
keepAliveInterval,
maxIdleTimeout,
maxConcurrentBidirectionalStreams,
maxConcurrentUnidirectionalStreams,
congestionControl,
},
) {
const keyPair = loadTlsKeyPair("Deno.connectQuic", { cert, key });
const conn = await op_quic_connect(
{ hostname, port },
{
caCerts,
alpnProtocols,
serverName,
},
{
keepAliveInterval,
maxIdleTimeout,
maxConcurrentBidirectionalStreams,
maxConcurrentUnidirectionalStreams,
congestionControl,
},
keyPair,
);
return new QuicConn(conn);
}
export {
connectQuic,
listenQuic,
QuicBidirectionalStream,
QuicConn,
QuicIncoming,
QuicListener,
QuicReceiveStream,
QuicSendStream,
};

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_net" name = "deno_net"
version = "0.175.0" version = "0.176.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -20,6 +20,7 @@ deno_tls.workspace = true
hickory-proto = "0.25.0-alpha.4" hickory-proto = "0.25.0-alpha.4"
hickory-resolver.workspace = true hickory-resolver.workspace = true
pin-project.workspace = true pin-project.workspace = true
quinn = { version = "0.11.6", default-features = false, features = ["runtime-tokio", "rustls", "ring"] }
rustls-tokio-stream.workspace = true rustls-tokio-stream.workspace = true
serde.workspace = true serde.workspace = true
socket2.workspace = true socket2.workspace = true

View file

@ -450,5 +450,293 @@ declare namespace Deno {
options?: StartTlsOptions, options?: StartTlsOptions,
): Promise<TlsConn>; ): Promise<TlsConn>;
/**
* **UNSTABLE**: New API, yet to be vetted.
* @experimental
* @category Network
*/
export interface QuicTransportOptions {
/** Period of inactivity before sending a keep-alive packet. Keep-alive
* packets prevent an inactive but otherwise healthy connection from timing
* out. Only one side of any given connection needs keep-alive enabled for
* the connection to be preserved.
* @default {undefined}
*/
keepAliveInterval?: number;
/** Maximum duration of inactivity to accept before timing out the
* connection. The true idle timeout is the minimum of this and the peers
* own max idle timeout.
* @default {undefined}
*/
maxIdleTimeout?: number;
/** Maximum number of incoming bidirectional streams that may be open
* concurrently.
* @default {100}
*/
maxConcurrentBidirectionalStreams?: number;
/** Maximum number of incoming unidirectional streams that may be open
* concurrently.
* @default {100}
*/
maxConcurrentUnidirectionalStreams?: number;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
* @experimental
* @category Network
*/
export interface ListenQuicOptions extends QuicTransportOptions {
/** The port to connect to. */
port: number;
/**
* A literal IP address or host name that can be resolved to an IP address.
* @default {"0.0.0.0"}
*/
hostname?: string;
/** Server private key in PEM format */
key: string;
/** Cert chain in PEM format */
cert: string;
/** Application-Layer Protocol Negotiation (ALPN) protocols to announce to
* the client. QUIC requires the use of ALPN.
*/
alpnProtocols: string[];
}
/**
* **UNSTABLE**: New API, yet to be vetted.
* Listen announces on the local transport address over QUIC.
*
* ```ts
* const lstnr = await Deno.listenQuic({ port: 443, cert: "...", key: "...", alpnProtocols: ["h3"] });
* ```
*
* Requires `allow-net` permission.
*
* @experimental
* @tags allow-net
* @category Network
*/
export function listenQuic(options: ListenQuicOptions): Promise<QuicListener>;
/**
* **UNSTABLE**: New API, yet to be vetted.
* @experimental
* @category Network
*/
export interface ConnectQuicOptions extends QuicTransportOptions {
/** The port to connect to. */
port: number;
/** A literal IP address or host name that can be resolved to an IP address. */
hostname: string;
/** The name used for validating the certificate provided by the server. If
* not provided, defaults to `hostname`. */
serverName?: string | undefined;
/** Application-Layer Protocol Negotiation (ALPN) protocols supported by
* the client. QUIC requires the use of ALPN.
*/
alpnProtocols: string[];
/** A list of root certificates that will be used in addition to the
* default root certificates to verify the peer's certificate.
*
* Must be in PEM format. */
caCerts?: string[];
/**
* The congestion control algorithm used when sending data over this connection.
*/
congestionControl?: "throughput" | "low-latency";
}
/**
* **UNSTABLE**: New API, yet to be vetted.
* Establishes a secure connection over QUIC using a hostname and port. The
* cert file is optional and if not included Mozilla's root certificates will
* be used. See also https://github.com/ctz/webpki-roots for specifics.
*
* ```ts
* const caCert = await Deno.readTextFile("./certs/my_custom_root_CA.pem");
* const conn1 = await Deno.connectQuic({ hostname: "example.com", port: 443, alpnProtocols: ["h3"] });
* const conn2 = await Deno.connectQuic({ caCerts: [caCert], hostname: "example.com", port: 443, alpnProtocols: ["h3"] });
* ```
*
* Requires `allow-net` permission.
*
* @experimental
* @tags allow-net
* @category Network
*/
export function connectQuic(options: ConnectQuicOptions): Promise<QuicConn>;
/**
* **UNSTABLE**: New API, yet to be vetted.
* @experimental
* @category Network
*/
export interface QuicCloseInfo {
/** A number representing the error code for the error. */
closeCode: number;
/** A string representing the reason for closing the connection. */
reason: string;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
* An incoming connection for which the server has not yet begun its part of the handshake.
*
* @experimental
* @category Network
*/
export interface QuicIncoming {
/**
* The local IP address which was used when the peer established the connection.
*/
readonly localIp: string;
/**
* The peers UDP address.
*/
readonly remoteAddr: NetAddr;
/**
* Whether the socket address that is initiating this connection has proven that they can receive traffic.
*/
readonly remoteAddressValidated: boolean;
/**
* Accept this incoming connection.
*/
accept(): Promise<QuicConn>;
/**
* Refuse this incoming connection.
*/
refuse(): void;
/**
* Ignore this incoming connection attempt, not sending any packet in response.
*/
ignore(): void;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
* Specialized listener that accepts QUIC connections.
*
* @experimental
* @category Network
*/
export interface QuicListener extends AsyncIterable<QuicConn> {
/** Return the address of the `QuicListener`. */
readonly addr: NetAddr;
/** Waits for and resolves to the next connection to the `QuicListener`. */
accept(): Promise<QuicConn>;
/** Waits for and resolves to the next incoming request to the `QuicListener`. */
incoming(): Promise<QuicIncoming>;
/** Close closes the listener. Any pending accept promises will be rejected
* with errors. */
close(info: QuicCloseInfo): void;
[Symbol.asyncIterator](): AsyncIterableIterator<QuicConn>;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
* @category Network
*/
export interface QuicSendStreamOptions {
/** Indicates the send priority of this stream relative to other streams for
* which the value has been set.
* @default {undefined}
*/
sendOrder?: number;
/** Wait until there is sufficient flow credit to create the stream.
* @default {false}
*/
waitUntilAvailable?: boolean;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
* @category Network
*/
export interface QuicConn {
/** Close closes the listener. Any pending accept promises will be rejected
* with errors. */
close(info: QuicCloseInfo): void;
/** Opens and returns a bidirectional stream. */
createBidirectionalStream(
options?: QuicSendStreamOptions,
): Promise<QuicBidirectionalStream>;
/** Opens and returns a unidirectional stream. */
createUnidirectionalStream(
options?: QuicSendStreamOptions,
): Promise<QuicSendStream>;
/** Send a datagram. The provided data cannot be larger than
* `maxDatagramSize`. */
sendDatagram(data: Uint8Array): Promise<void>;
/** Receive a datagram. If no buffer is provider, one will be allocated.
* The size of the provided buffer should be at least `maxDatagramSize`. */
readDatagram(buffer?: Uint8Array): Promise<Uint8Array>;
/** Return the remote address for the connection. Clients may change
* addresses at will, for example when switching to a cellular internet
* connection.
*/
readonly remoteAddr: NetAddr;
/** The negotiated ALPN protocol, if provided. */
readonly protocol: string | undefined;
/** Returns a promise that resolves when the connection is closed. */
readonly closed: Promise<QuicCloseInfo>;
/** A stream of bidirectional streams opened by the peer. */
readonly incomingBidirectionalStreams: ReadableStream<
QuicBidirectionalStream
>;
/** A stream of unidirectional streams opened by the peer. */
readonly incomingUnidirectionalStreams: ReadableStream<QuicReceiveStream>;
/** Returns the datagram stream for sending and receiving datagrams. */
readonly maxDatagramSize: number;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
* @category Network
*/
export interface QuicBidirectionalStream {
/** Returns a QuicReceiveStream instance that can be used to read incoming data. */
readonly readable: QuicReceiveStream;
/** Returns a QuicSendStream instance that can be used to write outgoing data. */
readonly writable: QuicSendStream;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
* @category Network
*/
export interface QuicSendStream extends WritableStream<Uint8Array> {
/** Indicates the send priority of this stream relative to other streams for
* which the value has been set. */
sendOrder: number;
}
/**
* **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
* @category Network
*/
export interface QuicReceiveStream extends ReadableStream<Uint8Array> {}
export {}; // only export exports export {}; // only export exports
} }

View file

@ -5,6 +5,7 @@ pub mod ops;
pub mod ops_tls; pub mod ops_tls;
#[cfg(unix)] #[cfg(unix)]
pub mod ops_unix; pub mod ops_unix;
mod quic;
pub mod raw; pub mod raw;
pub mod resolve_addr; pub mod resolve_addr;
pub mod tcp; pub mod tcp;
@ -158,8 +159,34 @@ deno_core::extension!(deno_net,
ops_unix::op_node_unstable_net_listen_unixpacket<P>, ops_unix::op_node_unstable_net_listen_unixpacket<P>,
ops_unix::op_net_recv_unixpacket, ops_unix::op_net_recv_unixpacket,
ops_unix::op_net_send_unixpacket<P>, ops_unix::op_net_send_unixpacket<P>,
quic::op_quic_accept,
quic::op_quic_accept_bi,
quic::op_quic_accept_incoming,
quic::op_quic_accept_uni,
quic::op_quic_close_connection,
quic::op_quic_close_endpoint,
quic::op_quic_connection_closed,
quic::op_quic_connection_get_protocol,
quic::op_quic_connection_get_remote_addr,
quic::op_quic_connect<P>,
quic::op_quic_endpoint_get_addr,
quic::op_quic_get_send_stream_priority,
quic::op_quic_incoming_accept,
quic::op_quic_incoming_refuse,
quic::op_quic_incoming_ignore,
quic::op_quic_incoming_local_ip,
quic::op_quic_incoming_remote_addr,
quic::op_quic_incoming_remote_addr_validated,
quic::op_quic_listen<P>,
quic::op_quic_max_datagram_size,
quic::op_quic_open_bi,
quic::op_quic_open_uni,
quic::op_quic_read_datagram,
quic::op_quic_send_datagram,
quic::op_quic_set_send_stream_priority,
], ],
esm = [ "01_net.js", "02_tls.js" ], esm = [ "01_net.js", "02_tls.js", "03_quic.js" ],
options = { options = {
root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>, root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
unsafely_ignore_certificate_errors: Option<Vec<String>>, unsafely_ignore_certificate_errors: Option<Vec<String>>,

660
ext/net/quic.rs Normal file
View file

@ -0,0 +1,660 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::resolve_addr::resolve_addr;
use crate::DefaultTlsOptions;
use crate::NetPermissions;
use crate::UnsafelyIgnoreCertificateErrors;
use deno_core::error::bad_resource;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::task::noop_waker_ref;
use deno_core::op2;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
use deno_core::BufView;
use deno_core::GarbageCollected;
use deno_core::JsBuffer;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::WriteOutcome;
use deno_tls::create_client_config;
use deno_tls::SocketUse;
use deno_tls::TlsKeys;
use deno_tls::TlsKeysHolder;
use quinn::crypto::rustls::QuicClientConfig;
use quinn::crypto::rustls::QuicServerConfig;
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
use std::cell::RefCell;
use std::future::Future;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
use std::net::SocketAddrV4;
use std::net::SocketAddrV6;
use std::pin::pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
use std::time::Duration;
#[derive(Debug, Deserialize, Serialize)]
struct Addr {
hostname: String,
port: u16,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ListenArgs {
alpn_protocols: Option<Vec<String>>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct TransportConfig {
keep_alive_interval: Option<u64>,
max_idle_timeout: Option<u64>,
max_concurrent_bidirectional_streams: Option<u32>,
max_concurrent_unidirectional_streams: Option<u32>,
preferred_address_v4: Option<SocketAddrV4>,
preferred_address_v6: Option<SocketAddrV6>,
congestion_control: Option<String>,
}
impl TryInto<quinn::TransportConfig> for TransportConfig {
type Error = AnyError;
fn try_into(self) -> Result<quinn::TransportConfig, AnyError> {
let mut cfg = quinn::TransportConfig::default();
if let Some(interval) = self.keep_alive_interval {
cfg.keep_alive_interval(Some(Duration::from_millis(interval)));
}
if let Some(timeout) = self.max_idle_timeout {
cfg.max_idle_timeout(Some(Duration::from_millis(timeout).try_into()?));
}
if let Some(max) = self.max_concurrent_bidirectional_streams {
cfg.max_concurrent_bidi_streams(max.into());
}
if let Some(max) = self.max_concurrent_unidirectional_streams {
cfg.max_concurrent_uni_streams(max.into());
}
if let Some(v) = self.congestion_control {
let controller: Option<
Arc<dyn quinn::congestion::ControllerFactory + Send + Sync + 'static>,
> = match v.as_str() {
"low-latency" => {
Some(Arc::new(quinn::congestion::BbrConfig::default()))
}
"throughput" => {
Some(Arc::new(quinn::congestion::CubicConfig::default()))
}
_ => None,
};
if let Some(controller) = controller {
cfg.congestion_controller_factory(controller);
}
}
Ok(cfg)
}
}
struct EndpointResource(quinn::Endpoint, Arc<QuicServerConfig>);
impl GarbageCollected for EndpointResource {}
#[op2(async)]
#[cppgc]
pub(crate) async fn op_quic_listen<NP>(
state: Rc<RefCell<OpState>>,
#[serde] addr: Addr,
#[serde] args: ListenArgs,
#[serde] transport_config: TransportConfig,
#[cppgc] keys: &TlsKeysHolder,
) -> Result<EndpointResource, AnyError>
where
NP: NetPermissions + 'static,
{
state
.borrow_mut()
.borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenQuic()")?;
let addr = resolve_addr(&addr.hostname, addr.port)
.await?
.next()
.ok_or_else(|| generic_error("No resolved address found"))?;
let TlsKeys::Static(deno_tls::TlsKey(cert, key)) = keys.take() else {
unreachable!()
};
let mut crypto =
quinn::rustls::ServerConfig::builder_with_protocol_versions(&[
&quinn::rustls::version::TLS13,
])
.with_no_client_auth()
.with_single_cert(cert.clone(), key.clone_key())?;
if let Some(alpn_protocols) = args.alpn_protocols {
crypto.alpn_protocols = alpn_protocols
.into_iter()
.map(|alpn| alpn.into_bytes())
.collect();
}
let server_config = Arc::new(QuicServerConfig::try_from(crypto)?);
let mut config = quinn::ServerConfig::with_crypto(server_config.clone());
config.preferred_address_v4(transport_config.preferred_address_v4);
config.preferred_address_v6(transport_config.preferred_address_v6);
config.transport_config(Arc::new(transport_config.try_into()?));
let endpoint = quinn::Endpoint::server(config, addr)?;
Ok(EndpointResource(endpoint, server_config))
}
#[op2]
#[serde]
pub(crate) fn op_quic_endpoint_get_addr(
#[cppgc] endpoint: &EndpointResource,
) -> Result<Addr, AnyError> {
let addr = endpoint.0.local_addr()?;
let addr = Addr {
hostname: format!("{}", addr.ip()),
port: addr.port(),
};
Ok(addr)
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CloseInfo {
close_code: u64,
reason: String,
}
#[op2(fast)]
pub(crate) fn op_quic_close_endpoint(
#[cppgc] endpoint: &EndpointResource,
#[bigint] close_code: u64,
#[string] reason: String,
) -> Result<(), AnyError> {
endpoint
.0
.close(quinn::VarInt::from_u64(close_code)?, reason.as_bytes());
Ok(())
}
struct ConnectionResource(quinn::Connection);
impl GarbageCollected for ConnectionResource {}
#[op2(async)]
#[cppgc]
pub(crate) async fn op_quic_accept(
#[cppgc] endpoint: &EndpointResource,
) -> Result<ConnectionResource, AnyError> {
match endpoint.0.accept().await {
Some(incoming) => {
let conn = incoming.accept()?.await?;
Ok(ConnectionResource(conn))
}
None => Err(bad_resource("QuicListener is closed")),
}
}
struct IncomingResource(
RefCell<Option<quinn::Incoming>>,
Arc<QuicServerConfig>,
);
impl GarbageCollected for IncomingResource {}
#[op2(async)]
#[cppgc]
pub(crate) async fn op_quic_accept_incoming(
#[cppgc] endpoint: &EndpointResource,
) -> Result<IncomingResource, AnyError> {
match endpoint.0.accept().await {
Some(incoming) => Ok(IncomingResource(
RefCell::new(Some(incoming)),
endpoint.1.clone(),
)),
None => Err(bad_resource("QuicListener is closed")),
}
}
#[op2]
#[string]
pub(crate) fn op_quic_incoming_local_ip(
#[cppgc] incoming_resource: &IncomingResource,
) -> Result<Option<String>, AnyError> {
let Some(incoming) = incoming_resource.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
Ok(incoming.local_ip().map(|ip| ip.to_string()))
}
#[op2]
#[serde]
pub(crate) fn op_quic_incoming_remote_addr(
#[cppgc] incoming_resource: &IncomingResource,
) -> Result<Addr, AnyError> {
let Some(incoming) = incoming_resource.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
let addr = incoming.remote_address();
Ok(Addr {
hostname: format!("{}", addr.ip()),
port: addr.port(),
})
}
#[op2(fast)]
pub(crate) fn op_quic_incoming_remote_addr_validated(
#[cppgc] incoming_resource: &IncomingResource,
) -> Result<bool, AnyError> {
let Some(incoming) = incoming_resource.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
Ok(incoming.remote_address_validated())
}
#[op2(async)]
#[cppgc]
pub(crate) async fn op_quic_incoming_accept(
#[cppgc] incoming_resource: &IncomingResource,
#[serde] transport_config: Option<TransportConfig>,
) -> Result<ConnectionResource, AnyError> {
let Some(incoming) = incoming_resource.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
let conn = match transport_config {
Some(transport_config) => {
let mut config =
quinn::ServerConfig::with_crypto(incoming_resource.1.clone());
config.preferred_address_v4(transport_config.preferred_address_v4);
config.preferred_address_v6(transport_config.preferred_address_v6);
config.transport_config(Arc::new(transport_config.try_into()?));
incoming.accept_with(Arc::new(config))?.await?
}
None => incoming.accept()?.await?,
};
Ok(ConnectionResource(conn))
}
#[op2]
#[serde]
pub(crate) fn op_quic_incoming_refuse(
#[cppgc] incoming: &IncomingResource,
) -> Result<(), AnyError> {
let Some(incoming) = incoming.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
incoming.refuse();
Ok(())
}
#[op2]
#[serde]
pub(crate) fn op_quic_incoming_ignore(
#[cppgc] incoming: &IncomingResource,
) -> Result<(), AnyError> {
let Some(incoming) = incoming.0.borrow_mut().take() else {
return Err(bad_resource("QuicIncoming already used"));
};
incoming.ignore();
Ok(())
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ConnectArgs {
ca_certs: Option<Vec<String>>,
alpn_protocols: Option<Vec<String>>,
server_name: Option<String>,
}
#[op2(async)]
#[cppgc]
pub(crate) async fn op_quic_connect<NP>(
state: Rc<RefCell<OpState>>,
#[serde] addr: Addr,
#[serde] args: ConnectArgs,
#[serde] transport_config: TransportConfig,
#[cppgc] key_pair: &TlsKeysHolder,
) -> Result<ConnectionResource, AnyError>
where
NP: NetPermissions + 'static,
{
state
.borrow_mut()
.borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectQuic()")?;
let sock_addr = resolve_addr(&addr.hostname, addr.port)
.await?
.next()
.ok_or_else(|| generic_error("No resolved address found"))?;
let root_cert_store = state
.borrow()
.borrow::<DefaultTlsOptions>()
.root_cert_store()?;
let unsafely_ignore_certificate_errors = state
.borrow()
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
.and_then(|it| it.0.clone());
let ca_certs = args
.ca_certs
.unwrap_or_default()
.into_iter()
.map(|s| s.into_bytes())
.collect::<Vec<_>>();
let mut tls_config = create_client_config(
root_cert_store,
ca_certs,
unsafely_ignore_certificate_errors,
key_pair.take(),
SocketUse::GeneralSsl,
)?;
if let Some(alpn_protocols) = args.alpn_protocols {
tls_config.alpn_protocols =
alpn_protocols.into_iter().map(|s| s.into_bytes()).collect();
}
let client_config = QuicClientConfig::try_from(tls_config)?;
let mut client_config = quinn::ClientConfig::new(Arc::new(client_config));
client_config.transport_config(Arc::new(transport_config.try_into()?));
let local_addr = match sock_addr.ip() {
IpAddr::V4(_) => IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)),
IpAddr::V6(_) => IpAddr::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
};
let conn = quinn::Endpoint::client((local_addr, 0).into())?
.connect_with(
client_config,
sock_addr,
&args.server_name.unwrap_or(addr.hostname),
)?
.await?;
Ok(ConnectionResource(conn))
}
#[op2]
#[string]
pub(crate) fn op_quic_connection_get_protocol(
#[cppgc] connection: &ConnectionResource,
) -> Option<String> {
connection
.0
.handshake_data()
.and_then(|h| h.downcast::<quinn::crypto::rustls::HandshakeData>().ok())
.and_then(|h| h.protocol)
.map(|p| String::from_utf8_lossy(&p).into_owned())
}
#[op2]
#[serde]
pub(crate) fn op_quic_connection_get_remote_addr(
#[cppgc] connection: &ConnectionResource,
) -> Result<Addr, AnyError> {
let addr = connection.0.remote_address();
Ok(Addr {
hostname: format!("{}", addr.ip()),
port: addr.port(),
})
}
#[op2(fast)]
pub(crate) fn op_quic_close_connection(
#[cppgc] connection: &ConnectionResource,
#[bigint] close_code: u64,
#[string] reason: String,
) -> Result<(), AnyError> {
connection
.0
.close(quinn::VarInt::from_u64(close_code)?, reason.as_bytes());
Ok(())
}
#[op2(async)]
#[serde]
pub(crate) async fn op_quic_connection_closed(
#[cppgc] connection: &ConnectionResource,
) -> Result<CloseInfo, AnyError> {
let e = connection.0.closed().await;
match e {
quinn::ConnectionError::LocallyClosed => Ok(CloseInfo {
close_code: 0,
reason: "".into(),
}),
quinn::ConnectionError::ApplicationClosed(i) => Ok(CloseInfo {
close_code: i.error_code.into(),
reason: String::from_utf8_lossy(&i.reason).into_owned(),
}),
e => Err(e.into()),
}
}
struct SendStreamResource(AsyncRefCell<quinn::SendStream>);
impl SendStreamResource {
fn new(stream: quinn::SendStream) -> Self {
Self(AsyncRefCell::new(stream))
}
}
impl Resource for SendStreamResource {
fn name(&self) -> Cow<str> {
"quicSendStream".into()
}
fn write(self: Rc<Self>, view: BufView) -> AsyncResult<WriteOutcome> {
Box::pin(async move {
let mut r = RcRef::map(self, |r| &r.0).borrow_mut().await;
let nwritten = r.write(&view).await?;
Ok(WriteOutcome::Partial { nwritten, view })
})
}
}
struct RecvStreamResource(AsyncRefCell<quinn::RecvStream>);
impl RecvStreamResource {
fn new(stream: quinn::RecvStream) -> Self {
Self(AsyncRefCell::new(stream))
}
}
impl Resource for RecvStreamResource {
fn name(&self) -> Cow<str> {
"quicReceiveStream".into()
}
fn read(self: Rc<Self>, limit: usize) -> AsyncResult<BufView> {
Box::pin(async move {
let mut r = RcRef::map(self, |r| &r.0).borrow_mut().await;
let mut data = vec![0; limit];
let nread = r.read(&mut data).await?.unwrap_or(0);
data.truncate(nread);
Ok(BufView::from(data))
})
}
}
#[op2(async)]
#[serde]
pub(crate) async fn op_quic_accept_bi(
#[cppgc] connection: &ConnectionResource,
state: Rc<RefCell<OpState>>,
) -> Result<(ResourceId, ResourceId), AnyError> {
match connection.0.accept_bi().await {
Ok((tx, rx)) => {
let mut state = state.borrow_mut();
let tx_rid = state.resource_table.add(SendStreamResource::new(tx));
let rx_rid = state.resource_table.add(RecvStreamResource::new(rx));
Ok((tx_rid, rx_rid))
}
Err(e) => match e {
quinn::ConnectionError::LocallyClosed
| quinn::ConnectionError::ApplicationClosed(..) => {
Err(bad_resource("QuicConn is closed"))
}
_ => Err(e.into()),
},
}
}
#[op2(async)]
#[serde]
pub(crate) async fn op_quic_open_bi(
#[cppgc] connection: &ConnectionResource,
state: Rc<RefCell<OpState>>,
wait_for_available: bool,
) -> Result<(ResourceId, ResourceId), AnyError> {
let (tx, rx) = if wait_for_available {
connection.0.open_bi().await?
} else {
let waker = noop_waker_ref();
let mut cx = Context::from_waker(waker);
match pin!(connection.0.open_bi()).poll(&mut cx) {
Poll::Ready(r) => r?,
Poll::Pending => {
return Err(generic_error("Connection has reached the maximum number of outgoing concurrent bidirectional streams"));
}
}
};
let mut state = state.borrow_mut();
let tx_rid = state.resource_table.add(SendStreamResource::new(tx));
let rx_rid = state.resource_table.add(RecvStreamResource::new(rx));
Ok((tx_rid, rx_rid))
}
#[op2(async)]
#[serde]
pub(crate) async fn op_quic_accept_uni(
#[cppgc] connection: &ConnectionResource,
state: Rc<RefCell<OpState>>,
) -> Result<ResourceId, AnyError> {
match connection.0.accept_uni().await {
Ok(rx) => {
let rid = state
.borrow_mut()
.resource_table
.add(RecvStreamResource::new(rx));
Ok(rid)
}
Err(e) => match e {
quinn::ConnectionError::LocallyClosed
| quinn::ConnectionError::ApplicationClosed(..) => {
Err(bad_resource("QuicConn is closed"))
}
_ => Err(e.into()),
},
}
}
#[op2(async)]
#[serde]
pub(crate) async fn op_quic_open_uni(
#[cppgc] connection: &ConnectionResource,
state: Rc<RefCell<OpState>>,
wait_for_available: bool,
) -> Result<ResourceId, AnyError> {
let tx = if wait_for_available {
connection.0.open_uni().await?
} else {
let waker = noop_waker_ref();
let mut cx = Context::from_waker(waker);
match pin!(connection.0.open_uni()).poll(&mut cx) {
Poll::Ready(r) => r?,
Poll::Pending => {
return Err(generic_error("Connection has reached the maximum number of outgoing concurrent unidirectional streams"));
}
}
};
let rid = state
.borrow_mut()
.resource_table
.add(SendStreamResource::new(tx));
Ok(rid)
}
#[op2(async)]
pub(crate) async fn op_quic_send_datagram(
#[cppgc] connection: &ConnectionResource,
#[buffer] buf: JsBuffer,
) -> Result<(), AnyError> {
connection.0.send_datagram_wait(buf.to_vec().into()).await?;
Ok(())
}
#[op2(async)]
pub(crate) async fn op_quic_read_datagram(
#[cppgc] connection: &ConnectionResource,
#[buffer] mut buf: JsBuffer,
) -> Result<u32, AnyError> {
let data = connection.0.read_datagram().await?;
buf[0..data.len()].copy_from_slice(&data);
Ok(data.len() as _)
}
#[op2(fast)]
pub(crate) fn op_quic_max_datagram_size(
#[cppgc] connection: &ConnectionResource,
) -> Result<u32, AnyError> {
Ok(connection.0.max_datagram_size().unwrap_or(0) as _)
}
#[op2(fast)]
pub(crate) fn op_quic_get_send_stream_priority(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<i32, AnyError> {
let resource = state
.borrow()
.resource_table
.get::<SendStreamResource>(rid)?;
let r = RcRef::map(resource, |r| &r.0).try_borrow();
match r {
Some(s) => Ok(s.priority()?),
None => Err(generic_error("Unable to get priority")),
}
}
#[op2(fast)]
pub(crate) fn op_quic_set_send_stream_priority(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
priority: i32,
) -> Result<(), AnyError> {
let resource = state
.borrow()
.resource_table
.get::<SendStreamResource>(rid)?;
let r = RcRef::map(resource, |r| &r.0).try_borrow();
match r {
Some(s) => {
s.set_priority(priority)?;
Ok(())
}
None => Err(generic_error("Unable to set priority")),
}
}

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_node" name = "deno_node"
version = "0.120.0" version = "0.122.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -73,12 +73,17 @@ pub fn cpu_info() -> Option<Vec<CpuInfo>> {
cpu_speed = 2_400_000_000; cpu_speed = 2_400_000_000;
} }
extern "C" {
fn mach_host_self() -> std::ffi::c_uint;
static mut mach_task_self_: std::ffi::c_uint;
}
let mut num_cpus: libc::natural_t = 0; let mut num_cpus: libc::natural_t = 0;
let mut info: *mut libc::processor_cpu_load_info_data_t = let mut info: *mut libc::processor_cpu_load_info_data_t =
std::ptr::null_mut(); std::ptr::null_mut();
let mut msg_type: libc::mach_msg_type_number_t = 0; let mut msg_type: libc::mach_msg_type_number_t = 0;
if libc::host_processor_info( if libc::host_processor_info(
libc::mach_host_self(), mach_host_self(),
libc::PROCESSOR_CPU_LOAD_INFO, libc::PROCESSOR_CPU_LOAD_INFO,
&mut num_cpus, &mut num_cpus,
&mut info as *mut _ as *mut libc::processor_info_array_t, &mut info as *mut _ as *mut libc::processor_info_array_t,
@ -111,7 +116,7 @@ pub fn cpu_info() -> Option<Vec<CpuInfo>> {
} }
libc::vm_deallocate( libc::vm_deallocate(
libc::mach_task_self(), mach_task_self_,
info.as_ptr() as libc::vm_address_t, info.as_ptr() as libc::vm_address_t,
msg_type as _, msg_type as _,
); );

View file

@ -67,9 +67,9 @@ generate_builtin_node_module_lists! {
"process", "process",
"punycode", "punycode",
"querystring", "querystring",
"repl",
"readline", "readline",
"readline/promises", "readline/promises",
"repl",
"stream", "stream",
"stream/consumers", "stream/consumers",
"stream/promises", "stream/promises",
@ -90,3 +90,10 @@ generate_builtin_node_module_lists! {
"worker_threads", "worker_threads",
"zlib", "zlib",
} }
#[test]
fn test_builtins_are_sorted() {
let mut builtins_list = SUPPORTED_BUILTIN_NODE_MODULES.to_vec();
builtins_list.sort();
assert_eq!(SUPPORTED_BUILTIN_NODE_MODULES, builtins_list);
}

View file

@ -30,50 +30,58 @@ export function access(
mode = getValidMode(mode, "access"); mode = getValidMode(mode, "access");
const cb = makeCallback(callback); const cb = makeCallback(callback);
Deno.lstat(path).then((info) => { Deno.lstat(path).then(
if (info.mode === null) { (info) => {
// If the file mode is unavailable, we pretend it has if (info.mode === null) {
// the permission // If the file mode is unavailable, we pretend it has
cb(null); // the permission
return; cb(null);
} return;
const m = +mode || 0; }
let fileMode = +info.mode || 0; let m = +mode || 0;
if (Deno.build.os !== "windows" && info.uid === Deno.uid()) { let fileMode = +info.mode || 0;
// If the user is the owner of the file, then use the owner bits of
// the file permission if (Deno.build.os === "windows") {
fileMode >>= 6; m &= ~fs.X_OK; // Ignore the X_OK bit on Windows
} } else if (info.uid === Deno.uid()) {
// TODO(kt3k): Also check the case when the user belong to the group // If the user is the owner of the file, then use the owner bits of
// of the file // the file permission
if ((m & fileMode) === m) { fileMode >>= 6;
// all required flags exist }
cb(null);
} else { // TODO(kt3k): Also check the case when the user belong to the group
// some required flags don't // of the file
// deno-lint-ignore no-explicit-any
const e: any = new Error(`EACCES: permission denied, access '${path}'`); if ((m & fileMode) === m) {
e.path = path; // all required flags exist
e.syscall = "access"; cb(null);
e.errno = codeMap.get("EACCES"); } else {
e.code = "EACCES"; // some required flags don't
cb(e); // deno-lint-ignore no-explicit-any
} const e: any = new Error(`EACCES: permission denied, access '${path}'`);
}, (err) => { e.path = path;
if (err instanceof Deno.errors.NotFound) { e.syscall = "access";
// deno-lint-ignore no-explicit-any e.errno = codeMap.get("EACCES");
const e: any = new Error( e.code = "EACCES";
`ENOENT: no such file or directory, access '${path}'`, cb(e);
); }
e.path = path; },
e.syscall = "access"; (err) => {
e.errno = codeMap.get("ENOENT"); if (err instanceof Deno.errors.NotFound) {
e.code = "ENOENT"; // deno-lint-ignore no-explicit-any
cb(e); const e: any = new Error(
} else { `ENOENT: no such file or directory, access '${path}'`,
cb(err); );
} e.path = path;
}); e.syscall = "access";
e.errno = codeMap.get("ENOENT");
e.code = "ENOENT";
cb(e);
} else {
cb(err);
}
},
);
} }
export const accessPromise = promisify(access) as ( export const accessPromise = promisify(access) as (
@ -91,9 +99,11 @@ export function accessSync(path: string | Buffer | URL, mode?: number) {
// the permission // the permission
return; return;
} }
const m = +mode! || 0; let m = +mode! || 0;
let fileMode = +info.mode! || 0; let fileMode = +info.mode! || 0;
if (Deno.build.os !== "windows" && info.uid === Deno.uid()) { if (Deno.build.os === "windows") {
m &= ~fs.X_OK; // Ignore the X_OK bit on Windows
} else if (info.uid === Deno.uid()) {
// If the user is the owner of the file, then use the owner bits of // If the user is the owner of the file, then use the owner bits of
// the file permission // the file permission
fileMode >>= 6; fileMode >>= 6;

View file

@ -16,16 +16,24 @@ export function ftruncate(
: undefined; : undefined;
const callback: CallbackWithError = typeof lenOrCallback === "function" const callback: CallbackWithError = typeof lenOrCallback === "function"
? lenOrCallback ? lenOrCallback
: maybeCallback as CallbackWithError; : (maybeCallback as CallbackWithError);
if (!callback) throw new Error("No callback function supplied"); if (!callback) throw new Error("No callback function supplied");
new FsFile(fd, Symbol.for("Deno.internal.FsFile")).truncate(len).then( new FsFile(fd, Symbol.for("Deno.internal.FsFile"))
() => callback(null), .truncate(len)
callback, .then(() => callback(null), callback);
);
} }
export function ftruncateSync(fd: number, len?: number) { export function ftruncateSync(fd: number, len?: number) {
new FsFile(fd, Symbol.for("Deno.internal.FsFile")).truncateSync(len); new FsFile(fd, Symbol.for("Deno.internal.FsFile")).truncateSync(len);
} }
export function ftruncatePromise(fd: number, len?: number): Promise<void> {
return new Promise((resolve, reject) => {
ftruncate(fd, len, (err) => {
if (err) reject(err);
else resolve();
});
});
}

View file

@ -13,6 +13,7 @@ import {
ReadOptions, ReadOptions,
TextOptionsArgument, TextOptionsArgument,
} from "ext:deno_node/_fs/_fs_common.ts"; } from "ext:deno_node/_fs/_fs_common.ts";
import { ftruncatePromise } from "ext:deno_node/_fs/_fs_ftruncate.ts";
import { core } from "ext:core/mod.js"; import { core } from "ext:core/mod.js";
interface WriteResult { interface WriteResult {
@ -73,6 +74,10 @@ export class FileHandle extends EventEmitter {
} }
} }
truncate(len?: number): Promise<void> {
return fsCall(ftruncatePromise, this, len);
}
readFile( readFile(
opt?: TextOptionsArgument | BinaryOptionsArgument | FileOptionsArgument, opt?: TextOptionsArgument | BinaryOptionsArgument | FileOptionsArgument,
): Promise<string | Buffer> { ): Promise<string | Buffer> {
@ -85,11 +90,7 @@ export class FileHandle extends EventEmitter {
length: number, length: number,
position: number, position: number,
): Promise<WriteResult>; ): Promise<WriteResult>;
write( write(str: string, position: number, encoding: string): Promise<WriteResult>;
str: string,
position: number,
encoding: string,
): Promise<WriteResult>;
write( write(
bufferOrStr: Uint8Array | string, bufferOrStr: Uint8Array | string,
offsetOrPosition: number, offsetOrPosition: number,
@ -120,16 +121,10 @@ export class FileHandle extends EventEmitter {
const encoding = lengthOrEncoding; const encoding = lengthOrEncoding;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
write( write(this.fd, str, position, encoding, (err, bytesWritten, buffer) => {
this.fd, if (err) reject(err);
str, else resolve({ buffer, bytesWritten });
position, });
encoding,
(err, bytesWritten, buffer) => {
if (err) reject(err);
else resolve({ buffer, bytesWritten });
},
);
}); });
} }
} }

View file

@ -21,7 +21,7 @@ import {
nodeWorkerThreadCloseCb, nodeWorkerThreadCloseCb,
refMessagePort, refMessagePort,
serializeJsMessageData, serializeJsMessageData,
unrefPollForMessages, unrefParentPort,
} from "ext:deno_web/13_message_port.js"; } from "ext:deno_web/13_message_port.js";
import * as webidl from "ext:deno_webidl/00_webidl.js"; import * as webidl from "ext:deno_webidl/00_webidl.js";
import { notImplemented } from "ext:deno_node/_utils.ts"; import { notImplemented } from "ext:deno_node/_utils.ts";
@ -451,10 +451,10 @@ internals.__initWorkerThreads = (
parentPort.emit("close"); parentPort.emit("close");
}); });
parentPort.unref = () => { parentPort.unref = () => {
parentPort[unrefPollForMessages] = true; parentPort[unrefParentPort] = true;
}; };
parentPort.ref = () => { parentPort.ref = () => {
parentPort[unrefPollForMessages] = false; parentPort[unrefParentPort] = false;
}; };
if (isWorkerThread) { if (isWorkerThread) {

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_telemetry" name = "deno_telemetry"
version = "0.5.0" version = "0.6.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_tls" name = "deno_tls"
version = "0.170.0" version = "0.171.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_url" name = "deno_url"
version = "0.183.0" version = "0.184.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -908,8 +908,8 @@ const _original = Symbol("[[original]]");
* @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true. * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
* @returns {ReadableStream<Uint8Array>} * @returns {ReadableStream<Uint8Array>}
*/ */
function readableStreamForRid(rid, autoClose = true) { function readableStreamForRid(rid, autoClose = true, Super) {
const stream = new ReadableStream(_brand); const stream = new (Super ?? ReadableStream)(_brand);
stream[_resourceBacking] = { rid, autoClose }; stream[_resourceBacking] = { rid, autoClose };
const tryClose = () => { const tryClose = () => {
@ -1130,8 +1130,8 @@ async function readableStreamCollectIntoUint8Array(stream) {
* @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true. * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
* @returns {ReadableStream<Uint8Array>} * @returns {ReadableStream<Uint8Array>}
*/ */
function writableStreamForRid(rid, autoClose = true) { function writableStreamForRid(rid, autoClose = true, Super) {
const stream = new WritableStream(_brand); const stream = new (Super ?? WritableStream)(_brand);
stream[_resourceBacking] = { rid, autoClose }; stream[_resourceBacking] = { rid, autoClose };
const tryClose = () => { const tryClose = () => {

View file

@ -102,8 +102,8 @@ const nodeWorkerThreadCloseCb = Symbol("nodeWorkerThreadCloseCb");
const nodeWorkerThreadCloseCbInvoked = Symbol("nodeWorkerThreadCloseCbInvoked"); const nodeWorkerThreadCloseCbInvoked = Symbol("nodeWorkerThreadCloseCbInvoked");
export const refMessagePort = Symbol("refMessagePort"); export const refMessagePort = Symbol("refMessagePort");
/** It is used by 99_main.js and worker_threads to /** It is used by 99_main.js and worker_threads to
* unref/ref on the global pollForMessages promise. */ * unref/ref on the global message event handler count. */
export const unrefPollForMessages = Symbol("unrefPollForMessages"); export const unrefParentPort = Symbol("unrefParentPort");
/** /**
* @param {number} id * @param {number} id

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_web" name = "deno_web"
version = "0.214.0" version = "0.215.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_webgpu" name = "deno_webgpu"
version = "0.150.0" version = "0.151.0"
authors = ["the Deno authors"] authors = ["the Deno authors"]
edition.workspace = true edition.workspace = true
license = "MIT" license = "MIT"

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_webidl" name = "deno_webidl"
version = "0.183.0" version = "0.184.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_websocket" name = "deno_websocket"
version = "0.188.0" version = "0.189.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

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

View file

@ -9,6 +9,7 @@ use deno_package_json::PackageJsonDepValue;
use deno_package_json::PackageJsonRc; use deno_package_json::PackageJsonRc;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::Version; use deno_semver::Version;
use node_resolver::env::NodeResolverEnv; use node_resolver::env::NodeResolverEnv;
use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveError;
@ -30,7 +31,7 @@ use super::ResolvePkgFolderFromDenoReqError;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ByonmResolvePkgFolderFromDenoReqError { pub enum ByonmResolvePkgFolderFromDenoReqError {
#[error("Could not find \"{}\" in a node_modules folder. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", .0)] #[error("Could not find \"{}\" in a node_modules folder. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", .0)]
MissingAlias(String), MissingAlias(StackString),
#[error(transparent)] #[error(transparent)]
PackageJson(#[from] PackageJsonLoadError), PackageJson(#[from] PackageJsonLoadError),
#[error("Could not find a matching package for 'npm:{}' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", .0)] #[error("Could not find a matching package for 'npm:{}' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", .0)]
@ -177,16 +178,14 @@ impl<Fs: DenoResolverFs, TEnv: NodeResolverEnv> ByonmNpmResolver<Fs, TEnv> {
&self, &self,
req: &PackageReq, req: &PackageReq,
referrer: &Url, referrer: &Url,
) -> Result<Option<(PackageJsonRc, String)>, PackageJsonLoadError> { ) -> Result<Option<(PackageJsonRc, StackString)>, PackageJsonLoadError> {
fn resolve_alias_from_pkg_json( fn resolve_alias_from_pkg_json(
req: &PackageReq, req: &PackageReq,
pkg_json: &PackageJson, pkg_json: &PackageJson,
) -> Option<String> { ) -> Option<StackString> {
let deps = pkg_json.resolve_local_package_json_deps(); let deps = pkg_json.resolve_local_package_json_deps();
for (key, value) in deps for (key, value) in
.dependencies deps.dependencies.iter().chain(deps.dev_dependencies.iter())
.into_iter()
.chain(deps.dev_dependencies.into_iter())
{ {
if let Ok(value) = value { if let Ok(value) = value {
match value { match value {
@ -194,12 +193,14 @@ impl<Fs: DenoResolverFs, TEnv: NodeResolverEnv> ByonmNpmResolver<Fs, TEnv> {
if dep_req.name == req.name if dep_req.name == req.name
&& dep_req.version_req.intersects(&req.version_req) && dep_req.version_req.intersects(&req.version_req)
{ {
return Some(key); return Some(key.clone());
} }
} }
PackageJsonDepValue::Workspace(_workspace) => { PackageJsonDepValue::Workspace(_workspace) => {
if key == req.name && req.version_req.tag() == Some("workspace") { if key.as_str() == req.name
return Some(key); && req.version_req.tag() == Some("workspace")
{
return Some(key.clone());
} }
} }
} }
@ -246,7 +247,7 @@ impl<Fs: DenoResolverFs, TEnv: NodeResolverEnv> ByonmNpmResolver<Fs, TEnv> {
if let Ok(Some(dep_pkg_json)) = if let Ok(Some(dep_pkg_json)) =
self.load_pkg_json(&pkg_folder.join("package.json")) self.load_pkg_json(&pkg_folder.join("package.json"))
{ {
if dep_pkg_json.name.as_ref() == Some(&req.name) { if dep_pkg_json.name.as_deref() == Some(req.name.as_str()) {
let matches_req = dep_pkg_json let matches_req = dep_pkg_json
.version .version
.as_ref() .as_ref()

View file

@ -162,7 +162,7 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer, TNodeResolverEnv: NodeResolverEnv>
add_export( add_export(
&mut source, &mut source,
export, export,
&format!("mod[\"{}\"]", escape_for_double_quote_string(export)), &format!("mod[{}]", to_double_quote_string(export)),
&mut temp_var_count, &mut temp_var_count,
); );
} }
@ -561,8 +561,8 @@ fn add_export(
"const __deno_export_{temp_var_count}__ = {initializer};" "const __deno_export_{temp_var_count}__ = {initializer};"
)); ));
source.push(format!( source.push(format!(
"export {{ __deno_export_{temp_var_count}__ as \"{}\" }};", "export {{ __deno_export_{temp_var_count}__ as {} }};",
escape_for_double_quote_string(name) to_double_quote_string(name)
)); ));
} else { } else {
source.push(format!("export const {name} = {initializer};")); source.push(format!("export const {name} = {initializer};"));
@ -620,14 +620,9 @@ fn not_found(path: &str, referrer: &Path) -> AnyError {
std::io::Error::new(std::io::ErrorKind::NotFound, msg).into() std::io::Error::new(std::io::ErrorKind::NotFound, msg).into()
} }
fn escape_for_double_quote_string(text: &str) -> Cow<str> { fn to_double_quote_string(text: &str) -> String {
// this should be rare, so doing a scan first before allocating is ok // serde can handle this for us
if text.chars().any(|c| matches!(c, '"' | '\\')) { serde_json::to_string(text).unwrap()
// don't bother making this more complex for perf because it's rare
Cow::Owned(text.replace('\\', "\\\\").replace('"', "\\\""))
} else {
Cow::Borrowed(text)
}
} }
#[cfg(test)] #[cfg(test)]
@ -665,4 +660,13 @@ mod tests {
Some(("@some-package/core".to_string(), "./actions".to_string())) Some(("@some-package/core".to_string(), "./actions".to_string()))
); );
} }
#[test]
fn test_to_double_quote_string() {
assert_eq!(to_double_quote_string("test"), "\"test\"");
assert_eq!(
to_double_quote_string("\r\n\t\"test"),
"\"\\r\\n\\t\\\"test\""
);
}
} }

View file

@ -320,7 +320,6 @@ impl NodeJsErrorCoded for PackageJsonLoadError {
impl NodeJsErrorCoded for ClosestPkgJsonError { impl NodeJsErrorCoded for ClosestPkgJsonError {
fn code(&self) -> NodeJsErrorCode { fn code(&self) -> NodeJsErrorCode {
match self.as_kind() { match self.as_kind() {
ClosestPkgJsonErrorKind::CanonicalizingDir(e) => e.code(),
ClosestPkgJsonErrorKind::Load(e) => e.code(), ClosestPkgJsonErrorKind::Load(e) => e.code(),
} }
} }
@ -331,26 +330,10 @@ pub struct ClosestPkgJsonError(pub Box<ClosestPkgJsonErrorKind>);
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ClosestPkgJsonErrorKind { pub enum ClosestPkgJsonErrorKind {
#[error(transparent)]
CanonicalizingDir(#[from] CanonicalizingPkgJsonDirError),
#[error(transparent)] #[error(transparent)]
Load(#[from] PackageJsonLoadError), Load(#[from] PackageJsonLoadError),
} }
#[derive(Debug, Error)]
#[error("[{}] Failed canonicalizing package.json directory '{}'.", self.code(), dir_path.display())]
pub struct CanonicalizingPkgJsonDirError {
pub dir_path: PathBuf,
#[source]
pub source: std::io::Error,
}
impl NodeJsErrorCoded for CanonicalizingPkgJsonDirError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
}
}
// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError // todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error( #[error(

View file

@ -2,7 +2,6 @@
use deno_package_json::PackageJson; use deno_package_json::PackageJson;
use deno_package_json::PackageJsonRc; use deno_package_json::PackageJsonRc;
use deno_path_util::strip_unc_prefix;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::ErrorKind; use std::io::ErrorKind;
@ -11,7 +10,6 @@ use std::path::PathBuf;
use url::Url; use url::Url;
use crate::env::NodeResolverEnv; use crate::env::NodeResolverEnv;
use crate::errors::CanonicalizingPkgJsonDirError;
use crate::errors::ClosestPkgJsonError; use crate::errors::ClosestPkgJsonError;
use crate::errors::PackageJsonLoadError; use crate::errors::PackageJsonLoadError;
@ -67,37 +65,8 @@ impl<TEnv: NodeResolverEnv> PackageJsonResolver<TEnv> {
&self, &self,
file_path: &Path, file_path: &Path,
) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> { ) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> {
// we use this for deno compile using byonm because the script paths
// won't be in virtual file system, but the package.json paths will be
fn canonicalize_first_ancestor_exists<TEnv: NodeResolverEnv>(
dir_path: &Path,
env: &TEnv,
) -> Result<Option<PathBuf>, std::io::Error> {
for ancestor in dir_path.ancestors() {
match env.realpath_sync(ancestor) {
Ok(dir_path) => return Ok(Some(dir_path)),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
// keep searching
}
Err(err) => return Err(err),
}
}
Ok(None)
}
let parent_dir = file_path.parent().unwrap(); let parent_dir = file_path.parent().unwrap();
let Some(start_dir) = canonicalize_first_ancestor_exists( for current_dir in parent_dir.ancestors() {
parent_dir, &self.env,
)
.map_err(|source| CanonicalizingPkgJsonDirError {
dir_path: parent_dir.to_path_buf(),
source,
})?
else {
return Ok(None);
};
let start_dir = strip_unc_prefix(start_dir);
for current_dir in start_dir.ancestors() {
let package_json_path = current_dir.join("package.json"); let package_json_path = current_dir.join("package.json");
if let Some(pkg_json) = self.load_package_json(&package_json_path)? { if let Some(pkg_json) = self.load_package_json(&package_json_path)? {
return Ok(Some(pkg_json)); return Ok(Some(pkg_json));

View file

@ -318,6 +318,8 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageSubpathResolveError> { ) -> Result<Url, PackageSubpathResolveError> {
// todo(dsherret): don't allocate a string here (maybe use an
// enum that says the subpath is not prefixed with a ./)
let package_subpath = package_subpath let package_subpath = package_subpath
.map(|s| format!("./{s}")) .map(|s| format!("./{s}"))
.unwrap_or_else(|| ".".to_string()); .unwrap_or_else(|| ".".to_string());

View file

@ -23,6 +23,7 @@ async-trait.workspace = true
base64.workspace = true base64.workspace = true
boxed_error.workspace = true boxed_error.workspace = true
deno_cache_dir.workspace = true deno_cache_dir.workspace = true
deno_error.workspace = true
deno_npm.workspace = true deno_npm.workspace = true
deno_semver.workspace = true deno_semver.workspace = true
deno_unsync = { workspace = true, features = ["tokio"] } deno_unsync = { workspace = true, features = ["tokio"] }

View file

@ -15,6 +15,7 @@ use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo; use deno_npm::registry::NpmPackageInfo;
use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageCacheFolderId;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::StackString;
use deno_semver::Version; use deno_semver::Version;
use http::HeaderName; use http::HeaderName;
use http::HeaderValue; use http::HeaderValue;
@ -260,7 +261,7 @@ impl<TEnv: NpmCacheEnv> NpmCache<TEnv> {
.and_then(|cache_id| { .and_then(|cache_id| {
Some(NpmPackageCacheFolderId { Some(NpmPackageCacheFolderId {
nv: PackageNv { nv: PackageNv {
name: cache_id.name, name: StackString::from_string(cache_id.name),
version: Version::parse_from_npm(&cache_id.version).ok()?, version: Version::parse_from_npm(&cache_id.version).ok()?,
}, },
copy_index: cache_id.copy_index, copy_index: cache_id.copy_index,

View file

@ -18,6 +18,7 @@ use deno_unsync::sync::MultiRuntimeAsyncValueCreator;
use futures::future::LocalBoxFuture; use futures::future::LocalBoxFuture;
use futures::FutureExt; use futures::FutureExt;
use parking_lot::Mutex; use parking_lot::Mutex;
use thiserror::Error;
use url::Url; use url::Url;
use crate::remote::maybe_auth_header_for_npm_registry; use crate::remote::maybe_auth_header_for_npm_registry;
@ -28,6 +29,31 @@ use crate::NpmCacheSetting;
type LoadResult = Result<FutureResult, Arc<AnyError>>; type LoadResult = Result<FutureResult, Arc<AnyError>>;
type LoadFuture = LocalBoxFuture<'static, LoadResult>; type LoadFuture = LocalBoxFuture<'static, LoadResult>;
#[derive(Debug, Error)]
#[error(transparent)]
pub struct AnyhowJsError(pub AnyError);
impl deno_error::JsErrorClass for AnyhowJsError {
fn get_class(&self) -> &'static str {
"generic"
}
fn get_message(&self) -> std::borrow::Cow<'static, str> {
self.0.to_string().into()
}
fn get_additional_properties(
&self,
) -> Option<
Vec<(
std::borrow::Cow<'static, str>,
std::borrow::Cow<'static, str>,
)>,
> {
None
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum FutureResult { enum FutureResult {
PackageNotExists, PackageNotExists,
@ -157,9 +183,9 @@ impl<TEnv: NpmCacheEnv> RegistryInfoProvider<TEnv> {
Ok(None) => Err(NpmRegistryPackageInfoLoadError::PackageNotExists { Ok(None) => Err(NpmRegistryPackageInfoLoadError::PackageNotExists {
package_name: name.to_string(), package_name: name.to_string(),
}), }),
Err(err) => { Err(err) => Err(NpmRegistryPackageInfoLoadError::LoadError(Arc::new(
Err(NpmRegistryPackageInfoLoadError::LoadError(Arc::new(err))) AnyhowJsError(err),
} ))),
} }
} }

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