mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
Compare commits
9 commits
7a1b53bee8
...
ec4b7e5d92
Author | SHA1 | Date | |
---|---|---|---|
|
ec4b7e5d92 | ||
|
4f27d7cdc0 | ||
|
ca084b6bba | ||
|
eafec84357 | ||
|
e4a16e91fa | ||
|
9aa02769c8 | ||
|
b962b87cfe | ||
|
9404dfc8cb | ||
|
57dd66ec3d |
137 changed files with 7197 additions and 6560 deletions
326
Cargo.lock
generated
326
Cargo.lock
generated
|
@ -212,11 +212,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
version = "0.37.3+1.3.251"
|
||||
version = "0.38.0+1.3.281"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
|
||||
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
||||
dependencies = [
|
||||
"libloading 0.7.4",
|
||||
"libloading 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -231,7 +231,7 @@ dependencies = [
|
|||
"nom 7.1.3",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
]
|
||||
|
||||
|
@ -525,7 +525,16 @@ version = "0.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
"bit-vec 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||
dependencies = [
|
||||
"bit-vec 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -534,6 +543,12 @@ version = "0.6.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -646,9 +661,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.15.0"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
|
||||
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -838,18 +853,16 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
|||
name = "cli_tests"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"deno_ast",
|
||||
"deno_bench_util",
|
||||
"deno_cache_dir",
|
||||
"deno_core",
|
||||
"deno_fetch",
|
||||
"deno_lockfile",
|
||||
"deno_semver",
|
||||
"deno_terminal 0.2.0",
|
||||
"deno_tls",
|
||||
"deno_tower_lsp",
|
||||
"deno_unsync",
|
||||
"fastwebsockets",
|
||||
"file_test_runner",
|
||||
"flaky_test",
|
||||
|
@ -866,7 +879,11 @@ dependencies = [
|
|||
"pretty_assertions",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-tokio-stream",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sys_traits",
|
||||
"test_server",
|
||||
"tokio",
|
||||
|
@ -1155,17 +1172,6 @@ dependencies = [
|
|||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"libloading 0.8.5",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
|
@ -1280,6 +1286,7 @@ dependencies = [
|
|||
"deno_resolver",
|
||||
"deno_runtime",
|
||||
"deno_semver",
|
||||
"deno_snapshots",
|
||||
"deno_task_shell",
|
||||
"deno_telemetry",
|
||||
"deno_terminal 0.2.0",
|
||||
|
@ -1291,7 +1298,6 @@ dependencies = [
|
|||
"dprint-plugin-jupyter",
|
||||
"dprint-plugin-markdown",
|
||||
"dprint-plugin-typescript",
|
||||
"env_logger",
|
||||
"fancy-regex",
|
||||
"faster-hex",
|
||||
"flate2",
|
||||
|
@ -1480,7 +1486,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"sha2",
|
||||
"sys_traits",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"url",
|
||||
]
|
||||
|
||||
|
@ -1533,14 +1539,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "deno_core"
|
||||
version = "0.331.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce2d1779358cad2bc56d71176298767be628d707bb75585f6f8a4be2da8ccda1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"az",
|
||||
"bincode",
|
||||
"bit-set",
|
||||
"bit-vec",
|
||||
"bit-set 0.5.3",
|
||||
"bit-vec 0.6.3",
|
||||
"bytes",
|
||||
"capacity_builder 0.1.3",
|
||||
"cooked-waker",
|
||||
|
@ -1896,24 +1900,33 @@ dependencies = [
|
|||
name = "deno_lib"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"deno_cache_dir",
|
||||
"capacity_builder 0.5.0",
|
||||
"deno_config",
|
||||
"deno_error",
|
||||
"deno_fs",
|
||||
"deno_media_type",
|
||||
"deno_node",
|
||||
"deno_npm",
|
||||
"deno_path_util",
|
||||
"deno_resolver",
|
||||
"deno_runtime",
|
||||
"deno_semver",
|
||||
"deno_terminal 0.2.0",
|
||||
"env_logger",
|
||||
"faster-hex",
|
||||
"indexmap 2.3.0",
|
||||
"libsui",
|
||||
"log",
|
||||
"node_resolver",
|
||||
"parking_lot",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sys_traits",
|
||||
"test_server",
|
||||
"thiserror 2.0.3",
|
||||
"tokio",
|
||||
"twox-hash",
|
||||
"url",
|
||||
]
|
||||
|
||||
|
@ -1949,11 +1962,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_media_type"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a417f8bd3f1074185c4c8ccb6ea6261ae173781596cc358e68ad07aaac11009d"
|
||||
checksum = "577fe2bbe04f3e9b1b7c6fac6a75101a9fbd611c50a6b68789e69f4d63dcb2b4"
|
||||
dependencies = [
|
||||
"data-url",
|
||||
"encoding_rs",
|
||||
"serde",
|
||||
"url",
|
||||
]
|
||||
|
@ -2026,7 +2040,6 @@ dependencies = [
|
|||
"deno_fetch",
|
||||
"deno_fs",
|
||||
"deno_io",
|
||||
"deno_media_type",
|
||||
"deno_net",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
|
@ -2040,7 +2053,7 @@ dependencies = [
|
|||
"ecdsa",
|
||||
"ed25519-dalek",
|
||||
"elliptic-curve",
|
||||
"errno 0.2.8",
|
||||
"errno",
|
||||
"faster-hex",
|
||||
"h2 0.4.4",
|
||||
"hkdf",
|
||||
|
@ -2152,8 +2165,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "deno_ops"
|
||||
version = "0.207.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96f000a21f6969b4c945bc8e9e785aa439f11ca4fd3fbddcd5bebc102167eb37"
|
||||
dependencies = [
|
||||
"indexmap 2.3.0",
|
||||
"proc-macro-rules",
|
||||
|
@ -2331,7 +2342,6 @@ dependencies = [
|
|||
"dlopen2",
|
||||
"encoding_rs",
|
||||
"fastwebsockets",
|
||||
"flate2",
|
||||
"http 1.1.0",
|
||||
"http-body-util",
|
||||
"hyper 0.14.28",
|
||||
|
@ -2379,6 +2389,13 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_snapshots"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"deno_runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_task_shell"
|
||||
version = "0.20.2"
|
||||
|
@ -2392,7 +2409,7 @@ dependencies = [
|
|||
"nix",
|
||||
"os_pipe",
|
||||
"path-dedot",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
@ -2533,8 +2550,10 @@ version = "0.153.0"
|
|||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_error",
|
||||
"indexmap 2.3.0",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.3",
|
||||
"tokio",
|
||||
"wgpu-core",
|
||||
|
@ -2660,6 +2679,43 @@ dependencies = [
|
|||
"v8_valueserializer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "denort"
|
||||
version = "2.1.5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"deno_cache_dir",
|
||||
"deno_config",
|
||||
"deno_core",
|
||||
"deno_error",
|
||||
"deno_lib",
|
||||
"deno_media_type",
|
||||
"deno_npm",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_resolver",
|
||||
"deno_runtime",
|
||||
"deno_semver",
|
||||
"deno_snapshots",
|
||||
"deno_terminal 0.2.0",
|
||||
"import_map",
|
||||
"indexmap 2.3.0",
|
||||
"libsui",
|
||||
"log",
|
||||
"node_resolver",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sys_traits",
|
||||
"test_server",
|
||||
"thiserror 2.0.3",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"twox-hash",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
|
@ -2864,9 +2920,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
|
||||
checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
|
||||
dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
@ -3103,7 +3159,7 @@ dependencies = [
|
|||
"debug-ignore",
|
||||
"indexmap 2.3.0",
|
||||
"log",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
|
@ -3189,17 +3245,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
|
@ -3210,16 +3255,6 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-code"
|
||||
version = "3.2.0"
|
||||
|
@ -3250,7 +3285,7 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0678ab2d46fa5195aaf59ad034c083d351377d4af57f3e073c074d0da3e3c766"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bit-set 0.5.3",
|
||||
"regex",
|
||||
]
|
||||
|
||||
|
@ -3263,7 +3298,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-trait",
|
||||
"log",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
@ -3298,7 +3333,7 @@ dependencies = [
|
|||
"rand",
|
||||
"sha1",
|
||||
"simdutf8",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"utf-8",
|
||||
]
|
||||
|
@ -3356,7 +3391,7 @@ dependencies = [
|
|||
"deno_terminal 0.1.1",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3705,9 +3740,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.13.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
|
||||
checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
|
@ -3717,9 +3752,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glutin_wgl_sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
|
||||
checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
@ -3743,6 +3778,18 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-allocator"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd"
|
||||
dependencies = [
|
||||
"log",
|
||||
"presser",
|
||||
"thiserror 1.0.69",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-descriptor"
|
||||
version = "0.3.0"
|
||||
|
@ -3843,7 +3890,7 @@ dependencies = [
|
|||
"pest_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4614,10 +4661,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
@ -4649,7 +4697,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -5023,9 +5071,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb"
|
||||
checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
|
@ -5091,7 +5139,7 @@ dependencies = [
|
|||
"rustc_version 0.4.0",
|
||||
"smallvec",
|
||||
"tagptr",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -5109,23 +5157,23 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
|||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.20.0"
|
||||
version = "23.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231"
|
||||
checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
"bit-set 0.8.0",
|
||||
"bitflags 2.6.0",
|
||||
"cfg_aliases 0.1.1",
|
||||
"codespan-reporting",
|
||||
"hexf-parse",
|
||||
"indexmap 2.3.0",
|
||||
"log",
|
||||
"num-traits",
|
||||
"rustc-hash 1.1.0",
|
||||
"serde",
|
||||
"spirv",
|
||||
"termcolor",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
|
@ -5207,7 +5255,6 @@ dependencies = [
|
|||
"async-trait",
|
||||
"boxed_error",
|
||||
"deno_error",
|
||||
"deno_media_type",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"futures",
|
||||
|
@ -5215,6 +5262,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"path-clean",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sys_traits",
|
||||
"thiserror 2.0.3",
|
||||
|
@ -5424,7 +5472,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5454,7 +5502,7 @@ dependencies = [
|
|||
"opentelemetry_sdk",
|
||||
"prost",
|
||||
"serde_json",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
|
@ -5496,7 +5544,7 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
"rand",
|
||||
"serde_json",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
@ -5686,7 +5734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
|
@ -5905,6 +5953,12 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "presser"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
|
@ -6116,7 +6170,7 @@ dependencies = [
|
|||
"indexmap 2.3.0",
|
||||
"quick-xml",
|
||||
"strip-ansi-escapes",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -6312,7 +6366,7 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
|||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6612,7 +6666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno 0.3.8",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
|
@ -6861,9 +6915,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.205"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -6900,9 +6954,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.205"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -6948,8 +7002,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "serde_v8"
|
||||
version = "0.240.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0494d74c40ab94f53a19485de359ea6a55f05341b817b93440b673c1ce8ec6"
|
||||
dependencies = [
|
||||
"deno_error",
|
||||
"num-bigint",
|
||||
|
@ -7988,11 +8040,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.64"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.64",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -8006,9 +8058,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.64"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -8178,7 +8230,7 @@ checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0"
|
|||
dependencies = [
|
||||
"either",
|
||||
"futures-util",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
@ -8515,9 +8567,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_categories"
|
||||
|
@ -8634,7 +8686,7 @@ dependencies = [
|
|||
"indexmap 2.3.0",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"wtf8",
|
||||
]
|
||||
|
||||
|
@ -8729,23 +8781,24 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
|
@ -8766,9 +8819,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -8776,9 +8829,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -8789,9 +8842,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
|
@ -8818,9 +8874,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -8856,15 +8912,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.21.1"
|
||||
version = "23.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39"
|
||||
checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
"bit-vec 0.8.0",
|
||||
"bitflags 2.6.0",
|
||||
"cfg_aliases 0.1.1",
|
||||
"codespan-reporting",
|
||||
"document-features",
|
||||
"indexmap 2.3.0",
|
||||
"log",
|
||||
|
@ -8877,30 +8932,30 @@ dependencies = [
|
|||
"rustc-hash 1.1.0",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"thiserror 1.0.64",
|
||||
"web-sys",
|
||||
"thiserror 1.0.69",
|
||||
"wgpu-hal",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "0.21.1"
|
||||
version = "23.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222"
|
||||
checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
"ash",
|
||||
"bit-set",
|
||||
"bit-set 0.8.0",
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"bytemuck",
|
||||
"cfg_aliases 0.1.1",
|
||||
"core-graphics-types",
|
||||
"d3d12",
|
||||
"glow",
|
||||
"glutin_wgl_sys",
|
||||
"gpu-alloc",
|
||||
"gpu-allocator",
|
||||
"gpu-descriptor",
|
||||
"js-sys",
|
||||
"khronos-egl",
|
||||
|
@ -8918,18 +8973,19 @@ dependencies = [
|
|||
"raw-window-handle",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"wgpu-types",
|
||||
"winapi",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.20.0"
|
||||
version = "23.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef"
|
||||
checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"js-sys",
|
||||
|
@ -8972,7 +9028,7 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c"
|
||||
dependencies = [
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"windows 0.52.0",
|
||||
]
|
||||
|
||||
|
@ -9334,7 +9390,7 @@ dependencies = [
|
|||
"nom 7.1.3",
|
||||
"oid-registry",
|
||||
"rusticata-macros",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
]
|
||||
|
||||
|
@ -9478,7 +9534,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"rand",
|
||||
"regex",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"uuid",
|
||||
|
@ -9519,7 +9575,7 @@ dependencies = [
|
|||
"flate2",
|
||||
"indexmap 2.3.0",
|
||||
"memchr",
|
||||
"thiserror 1.0.64",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -6,6 +6,8 @@ members = [
|
|||
"bench_util",
|
||||
"cli",
|
||||
"cli/lib",
|
||||
"cli/rt",
|
||||
"cli/snapshot",
|
||||
"ext/broadcast_channel",
|
||||
"ext/cache",
|
||||
"ext/canvas",
|
||||
|
@ -54,7 +56,7 @@ deno_core = { version = "0.331.0" }
|
|||
deno_bench_util = { version = "0.180.0", path = "./bench_util" }
|
||||
deno_config = { version = "=0.45.0", features = ["workspace", "sync"] }
|
||||
deno_lockfile = "=0.24.0"
|
||||
deno_media_type = { version = "0.2.3", features = ["module_specifier"] }
|
||||
deno_media_type = { version = "0.2.4", features = ["module_specifier"] }
|
||||
deno_npm = "=0.27.2"
|
||||
deno_path_util = "=0.3.0"
|
||||
deno_permissions = { version = "0.45.0", path = "./runtime/permissions" }
|
||||
|
@ -100,6 +102,7 @@ deno_webstorage = { version = "0.181.0", path = "./ext/webstorage" }
|
|||
deno_lib = { version = "0.2.0", path = "./cli/lib" }
|
||||
deno_npm_cache = { version = "0.5.0", path = "./resolvers/npm_cache" }
|
||||
deno_resolver = { version = "0.17.0", path = "./resolvers/deno" }
|
||||
deno_snapshots = { version = "0.1.0", path = "./cli/snapshot" }
|
||||
node_resolver = { version = "0.24.0", path = "./resolvers/node" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
|
@ -154,6 +157,7 @@ ipnet = "2.3"
|
|||
jsonc-parser = { version = "=0.26.2", features = ["serde"] }
|
||||
lazy-regex = "3"
|
||||
libc = "0.2.168"
|
||||
libsui = "0.5.0"
|
||||
libz-sys = { version = "1.1.20", default-features = false }
|
||||
log = { version = "0.4.20", features = ["kv"] }
|
||||
lsp-types = "=0.97.0" # used by tower-lsp and "proposed" feature is unstable in patch releases
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
<img align="right" src="https://deno.land/logo.svg" height="150px" alt="the deno mascot dinosaur standing in the rain">
|
||||
|
||||
[Deno](https://www.deno.com)
|
||||
([/ˈdiːnoʊ/](http://ipa-reader.xyz/?text=%CB%88di%CB%90no%CA%8A), pronounced
|
||||
[Deno](https://deno.com)
|
||||
([/ˈdiːnoʊ/](https://ipa-reader.com/?text=%CB%88di%CB%90no%CA%8A), pronounced
|
||||
`dee-no`) is a JavaScript, TypeScript, and WebAssembly runtime with secure
|
||||
defaults and a great developer experience. It's built on [V8](https://v8.dev/),
|
||||
[Rust](https://www.rust-lang.org/), and [Tokio](https://tokio.rs/).
|
||||
|
|
|
@ -16,11 +16,6 @@ name = "deno"
|
|||
path = "main.rs"
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "denort"
|
||||
path = "mainrt.rs"
|
||||
doc = false
|
||||
|
||||
[[test]]
|
||||
name = "integration"
|
||||
path = "integration_tests_runner.rs"
|
||||
|
@ -49,7 +44,7 @@ dhat-heap = ["dhat"]
|
|||
upgrade = []
|
||||
# A dev feature to disable creations and loading of snapshots in favor of
|
||||
# loading JS sources at runtime.
|
||||
hmr = ["deno_runtime/hmr"]
|
||||
hmr = ["deno_runtime/hmr", "deno_snapshots/disable"]
|
||||
# Vendor zlib as zlib-ng
|
||||
__vendored_zlib_ng = ["flate2/zlib-ng-compat", "libz-sys/zlib-ng"]
|
||||
|
||||
|
@ -60,10 +55,12 @@ lazy-regex.workspace = true
|
|||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
zstd.workspace = true
|
||||
glibc_version = "0.1.2"
|
||||
flate2 = { workspace = true, features = ["default"] }
|
||||
deno_error.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.build-dependencies]
|
||||
glibc_version = "0.1.2"
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
winapi.workspace = true
|
||||
winres.workspace = true
|
||||
|
@ -86,10 +83,11 @@ deno_path_util.workspace = true
|
|||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_semver.workspace = true
|
||||
deno_snapshots = { workspace = true }
|
||||
deno_task_shell = "=0.20.2"
|
||||
deno_telemetry.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
libsui = "0.5.0"
|
||||
libsui.workspace = true
|
||||
node_resolver.workspace = true
|
||||
|
||||
anstream = "0.6.14"
|
||||
|
@ -115,7 +113,6 @@ dprint-plugin-json = "=0.19.4"
|
|||
dprint-plugin-jupyter = "=0.1.5"
|
||||
dprint-plugin-markdown = "=0.17.8"
|
||||
dprint-plugin-typescript = "=0.93.3"
|
||||
env_logger = "=0.10.0"
|
||||
fancy-regex = "=0.10.0"
|
||||
faster-hex.workspace = true
|
||||
# If you disable the default __vendored_zlib_ng feature above, you _must_ be able to link against `-lz`.
|
||||
|
@ -156,7 +153,6 @@ rustyline-derive = "=0.7.0"
|
|||
serde.workspace = true
|
||||
serde_repr.workspace = true
|
||||
sha2.workspace = true
|
||||
shell-escape = "=0.1.5"
|
||||
spki = { version = "0.7", features = ["pem"] }
|
||||
sqlformat = "=0.3.2"
|
||||
strsim = "0.11.1"
|
||||
|
@ -185,6 +181,7 @@ winapi = { workspace = true, features = ["knownfolders", "mswsock", "objbase", "
|
|||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix.workspace = true
|
||||
shell-escape = "=0.1.5"
|
||||
|
||||
[dev-dependencies]
|
||||
deno_bench_util.workspace = true
|
||||
|
|
|
@ -31,6 +31,9 @@ use deno_core::error::AnyError;
|
|||
use deno_core::resolve_url_or_path;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::UnstableConfig;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_permissions::SysDescriptor;
|
||||
|
@ -546,15 +549,6 @@ impl Default for TypeCheckMode {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum CaData {
|
||||
/// The string is a file path
|
||||
File(String),
|
||||
/// This variant is not exposed as an option in the CLI, it is used internally
|
||||
/// for standalone binaries.
|
||||
Bytes(Vec<u8>),
|
||||
}
|
||||
|
||||
// Info needed to run NPM lifecycle scripts
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct LifecycleScriptsConfig {
|
||||
|
@ -582,19 +576,6 @@ fn parse_packages_allowed_scripts(s: &str) -> Result<String, AnyError> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Default, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize,
|
||||
)]
|
||||
pub struct UnstableConfig {
|
||||
// TODO(bartlomieju): remove in Deno 2.5
|
||||
pub legacy_flag_enabled: bool, // --unstable
|
||||
pub bare_node_builtins: bool,
|
||||
pub detect_cjs: bool,
|
||||
pub sloppy_imports: bool,
|
||||
pub npm_lazy_caching: bool,
|
||||
pub features: Vec<String>, // --unstabe-kv --unstable-cron
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct InternalFlags {
|
||||
/// Used when the language server is configured with an
|
||||
|
@ -1484,14 +1465,15 @@ fn handle_repl_flags(flags: &mut Flags, repl_flags: ReplFlags) {
|
|||
}
|
||||
|
||||
pub fn clap_root() -> Command {
|
||||
debug_assert_eq!(DENO_VERSION_INFO.typescript, deno_snapshots::TS_VERSION);
|
||||
let long_version = format!(
|
||||
"{} ({}, {}, {})\nv8 {}\ntypescript {}",
|
||||
crate::version::DENO_VERSION_INFO.deno,
|
||||
crate::version::DENO_VERSION_INFO.release_channel.name(),
|
||||
DENO_VERSION_INFO.deno,
|
||||
DENO_VERSION_INFO.release_channel.name(),
|
||||
env!("PROFILE"),
|
||||
env!("TARGET"),
|
||||
deno_core::v8::VERSION_STRING,
|
||||
crate::version::DENO_VERSION_INFO.typescript
|
||||
DENO_VERSION_INFO.typescript
|
||||
);
|
||||
|
||||
run_args(Command::new("deno"), true)
|
||||
|
@ -1507,7 +1489,7 @@ pub fn clap_root() -> Command {
|
|||
)
|
||||
.color(ColorChoice::Auto)
|
||||
.term_width(800)
|
||||
.version(crate::version::DENO_VERSION_INFO.deno)
|
||||
.version(DENO_VERSION_INFO.deno)
|
||||
.long_version(long_version)
|
||||
.disable_version_flag(true)
|
||||
.disable_help_flag(true)
|
||||
|
|
185
cli/args/mod.rs
185
cli/args/mod.rs
|
@ -10,10 +10,6 @@ mod package_json;
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::io::BufReader;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
use std::io::Seek;
|
||||
use std::net::SocketAddr;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
|
@ -58,8 +54,12 @@ use deno_core::serde_json;
|
|||
use deno_core::url::Url;
|
||||
use deno_graph::GraphKind;
|
||||
pub use deno_json::check_warn_tsconfig;
|
||||
use deno_lib::cache::DenoDirProvider;
|
||||
use deno_lib::env::has_flag_env_var;
|
||||
use deno_lib::args::has_flag_env_var;
|
||||
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::NpmProcessStateKind;
|
||||
use deno_lib::args::NPM_PROCESS_STATE;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_lib::worker::StorageKeyResolver;
|
||||
use deno_lint::linter::LintConfig as DenoLintConfig;
|
||||
use deno_npm::npm_rc::NpmRc;
|
||||
|
@ -68,16 +68,10 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
|||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
|
||||
use deno_runtime::deno_tls::rustls;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::rustls_pemfile;
|
||||
use deno_runtime::deno_tls::webpki_roots;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::StackString;
|
||||
use deno_telemetry::OtelConfig;
|
||||
use deno_telemetry::OtelRuntimeConfig;
|
||||
use deno_terminal::colors;
|
||||
use dotenvy::from_filename;
|
||||
pub use flags::*;
|
||||
|
@ -88,15 +82,13 @@ pub use lockfile::CliLockfileReadFromPathOptions;
|
|||
use once_cell::sync::Lazy;
|
||||
pub use package_json::NpmInstallDepsProvider;
|
||||
pub use package_json::PackageJsonDepValueParseWithLocationError;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sys_traits::EnvHomeDir;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::cache::DenoDirProvider;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::sys::CliSys;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
use crate::version;
|
||||
|
||||
pub fn npm_registry_url() -> &'static Url {
|
||||
static NPM_REGISTRY_DEFAULT_URL: Lazy<Url> = Lazy::new(|| {
|
||||
|
@ -608,147 +600,6 @@ pub fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
|
|||
})
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, deno_error::JsError)]
|
||||
#[class(generic)]
|
||||
pub enum RootCertStoreLoadError {
|
||||
#[error(
|
||||
"Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")"
|
||||
)]
|
||||
UnknownStore(String),
|
||||
#[error("Unable to add pem file to certificate store: {0}")]
|
||||
FailedAddPemFile(String),
|
||||
#[error("Failed opening CA file: {0}")]
|
||||
CaFileOpenError(String),
|
||||
}
|
||||
|
||||
/// Create and populate a root cert store based on the passed options and
|
||||
/// environment.
|
||||
pub fn get_root_cert_store(
|
||||
maybe_root_path: Option<PathBuf>,
|
||||
maybe_ca_stores: Option<Vec<String>>,
|
||||
maybe_ca_data: Option<CaData>,
|
||||
) -> Result<RootCertStore, RootCertStoreLoadError> {
|
||||
let mut root_cert_store = RootCertStore::empty();
|
||||
let ca_stores: Vec<String> = maybe_ca_stores
|
||||
.or_else(|| {
|
||||
let env_ca_store = env::var("DENO_TLS_CA_STORE").ok()?;
|
||||
Some(
|
||||
env_ca_store
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| vec!["mozilla".to_string()]);
|
||||
|
||||
for store in ca_stores.iter() {
|
||||
match store.as_str() {
|
||||
"mozilla" => {
|
||||
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.to_vec());
|
||||
}
|
||||
"system" => {
|
||||
let roots = load_native_certs().expect("could not load platform certs");
|
||||
for root in roots {
|
||||
if let Err(err) = root_cert_store
|
||||
.add(rustls::pki_types::CertificateDer::from(root.0.clone()))
|
||||
{
|
||||
log::error!(
|
||||
"{}",
|
||||
colors::yellow(&format!(
|
||||
"Unable to add system certificate to certificate store: {:?}",
|
||||
err
|
||||
))
|
||||
);
|
||||
let hex_encoded_root = faster_hex::hex_string(&root.0);
|
||||
log::error!("{}", colors::gray(&hex_encoded_root));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(RootCertStoreLoadError::UnknownStore(store.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ca_data =
|
||||
maybe_ca_data.or_else(|| env::var("DENO_CERT").ok().map(CaData::File));
|
||||
if let Some(ca_data) = ca_data {
|
||||
let result = match ca_data {
|
||||
CaData::File(ca_file) => {
|
||||
let ca_file = if let Some(root) = &maybe_root_path {
|
||||
root.join(&ca_file)
|
||||
} else {
|
||||
PathBuf::from(ca_file)
|
||||
};
|
||||
let certfile = std::fs::File::open(ca_file).map_err(|err| {
|
||||
RootCertStoreLoadError::CaFileOpenError(err.to_string())
|
||||
})?;
|
||||
let mut reader = BufReader::new(certfile);
|
||||
rustls_pemfile::certs(&mut reader).collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
CaData::Bytes(data) => {
|
||||
let mut reader = BufReader::new(Cursor::new(data));
|
||||
rustls_pemfile::certs(&mut reader).collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(certs) => {
|
||||
root_cert_store.add_parsable_certificates(certs);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(RootCertStoreLoadError::FailedAddPemFile(e.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(root_cert_store)
|
||||
}
|
||||
|
||||
/// State provided to the process via an environment variable.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct NpmProcessState {
|
||||
pub kind: NpmProcessStateKind,
|
||||
pub local_node_modules_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum NpmProcessStateKind {
|
||||
Snapshot(deno_npm::resolution::SerializedNpmResolutionSnapshot),
|
||||
Byonm,
|
||||
}
|
||||
|
||||
static NPM_PROCESS_STATE: Lazy<Option<NpmProcessState>> = Lazy::new(|| {
|
||||
use deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
|
||||
let fd = std::env::var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME).ok()?;
|
||||
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME);
|
||||
let fd = fd.parse::<usize>().ok()?;
|
||||
let mut file = {
|
||||
use deno_runtime::deno_io::FromRawIoHandle;
|
||||
unsafe { std::fs::File::from_raw_io_handle(fd as _) }
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
// seek to beginning. after the file is written the position will be inherited by this subprocess,
|
||||
// and also this file might have been read before
|
||||
file.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||
file
|
||||
.read_to_end(&mut buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!("failed to read npm process state from fd {fd}: {e}");
|
||||
})
|
||||
.ok()?;
|
||||
let state: NpmProcessState = serde_json::from_slice(&buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!(
|
||||
"failed to deserialize npm process state: {e} {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
Some(state)
|
||||
});
|
||||
|
||||
/// Overrides for the options below that when set will
|
||||
/// use these values over the values derived from the
|
||||
/// CLI flags or config file.
|
||||
|
@ -771,7 +622,7 @@ pub struct CliOptions {
|
|||
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
||||
overrides: CliOptionOverrides,
|
||||
pub start_dir: Arc<WorkspaceDirectory>,
|
||||
pub deno_dir_provider: Arc<DenoDirProvider<CliSys>>,
|
||||
pub deno_dir_provider: Arc<DenoDirProvider>,
|
||||
}
|
||||
|
||||
impl CliOptions {
|
||||
|
@ -1294,7 +1145,7 @@ impl CliOptions {
|
|||
|
||||
Ok(Some(InspectorServer::new(
|
||||
host,
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
)?))
|
||||
}
|
||||
|
||||
|
@ -1884,7 +1735,7 @@ fn resolve_node_modules_folder(
|
|||
cwd: &Path,
|
||||
flags: &Flags,
|
||||
workspace: &Workspace,
|
||||
deno_dir_provider: &Arc<DenoDirProvider<CliSys>>,
|
||||
deno_dir_provider: &Arc<DenoDirProvider>,
|
||||
) -> Result<Option<PathBuf>, AnyError> {
|
||||
fn resolve_from_root(root_folder: &FolderConfigs, cwd: &Path) -> PathBuf {
|
||||
root_folder
|
||||
|
@ -1993,15 +1844,6 @@ pub fn resolve_no_prompt(flags: &PermissionFlags) -> bool {
|
|||
flags.no_prompt || has_flag_env_var("DENO_NO_PROMPT")
|
||||
}
|
||||
|
||||
pub fn npm_pkg_req_ref_to_binary_command(
|
||||
req_ref: &NpmPackageReqReference,
|
||||
) -> String {
|
||||
req_ref
|
||||
.sub_path()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| req_ref.req().name.to_string())
|
||||
}
|
||||
|
||||
pub fn config_to_deno_graph_workspace_member(
|
||||
config: &ConfigFile,
|
||||
) -> Result<deno_graph::WorkspaceMember, AnyError> {
|
||||
|
@ -2062,13 +1904,6 @@ pub enum NpmCachingStrategy {
|
|||
Manual,
|
||||
}
|
||||
|
||||
pub fn otel_runtime_config() -> OtelRuntimeConfig {
|
||||
OtelRuntimeConfig {
|
||||
runtime_name: Cow::Borrowed("deno"),
|
||||
runtime_version: Cow::Borrowed(crate::version::DENO_VERSION_INFO.deno),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
|
90
cli/build.rs
90
cli/build.rs
|
@ -5,7 +5,6 @@ use std::path::PathBuf;
|
|||
|
||||
use deno_core::snapshot::*;
|
||||
use deno_runtime::*;
|
||||
mod shared;
|
||||
|
||||
mod ts {
|
||||
use std::collections::HashMap;
|
||||
|
@ -310,57 +309,6 @@ mod ts {
|
|||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn version() -> String {
|
||||
let file_text = std::fs::read_to_string("tsc/00_typescript.js").unwrap();
|
||||
let version_text = " version = \"";
|
||||
for line in file_text.lines() {
|
||||
if let Some(index) = line.find(version_text) {
|
||||
let remaining_line = &line[index + version_text.len()..];
|
||||
return remaining_line[..remaining_line.find('"').unwrap()].to_string();
|
||||
}
|
||||
}
|
||||
panic!("Could not find ts version.")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "hmr"))]
|
||||
fn create_cli_snapshot(snapshot_path: PathBuf) {
|
||||
use deno_runtime::ops::bootstrap::SnapshotOptions;
|
||||
|
||||
let snapshot_options = SnapshotOptions {
|
||||
ts_version: ts::version(),
|
||||
v8_version: deno_core::v8::VERSION_STRING,
|
||||
target: std::env::var("TARGET").unwrap(),
|
||||
};
|
||||
|
||||
deno_runtime::snapshot::create_runtime_snapshot(
|
||||
snapshot_path,
|
||||
snapshot_options,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
||||
fn git_commit_hash() -> String {
|
||||
if let Ok(output) = std::process::Command::new("git")
|
||||
.arg("rev-list")
|
||||
.arg("-1")
|
||||
.arg("HEAD")
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
std::str::from_utf8(&output.stdout[..40])
|
||||
.unwrap()
|
||||
.to_string()
|
||||
} else {
|
||||
// When not in git repository
|
||||
// (e.g. when the user install by `cargo install deno`)
|
||||
"UNKNOWN".to_string()
|
||||
}
|
||||
} else {
|
||||
// When there is no git command for some reason
|
||||
"UNKNOWN".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -370,7 +318,7 @@ fn main() {
|
|||
}
|
||||
|
||||
deno_napi::print_linker_flags("deno");
|
||||
deno_napi::print_linker_flags("denort");
|
||||
deno_webgpu::print_linker_flags("deno");
|
||||
|
||||
// Host snapshots won't work when cross compiling.
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
@ -389,51 +337,15 @@ fn main() {
|
|||
}
|
||||
println!("cargo:rerun-if-env-changed=DENO_CANARY");
|
||||
|
||||
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", git_commit_hash());
|
||||
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_COMMIT_HASH_SHORT={}",
|
||||
&git_commit_hash()[..7]
|
||||
);
|
||||
|
||||
let ts_version = ts::version();
|
||||
debug_assert_eq!(ts_version, "5.6.2"); // bump this assertion when it changes
|
||||
println!("cargo:rustc-env=TS_VERSION={}", ts_version);
|
||||
println!("cargo:rerun-if-env-changed=TS_VERSION");
|
||||
|
||||
println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());
|
||||
println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
|
||||
|
||||
if cfg!(windows) {
|
||||
// these dls load slowly, so delay loading them
|
||||
let dlls = [
|
||||
// webgpu
|
||||
"d3dcompiler_47",
|
||||
"OPENGL32",
|
||||
// network related functions
|
||||
"iphlpapi",
|
||||
];
|
||||
for dll in dlls {
|
||||
println!("cargo:rustc-link-arg-bin=deno=/delayload:{dll}.dll");
|
||||
println!("cargo:rustc-link-arg-bin=denort=/delayload:{dll}.dll");
|
||||
}
|
||||
// enable delay loading
|
||||
println!("cargo:rustc-link-arg-bin=deno=delayimp.lib");
|
||||
println!("cargo:rustc-link-arg-bin=denort=delayimp.lib");
|
||||
}
|
||||
|
||||
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
||||
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
let compiler_snapshot_path = o.join("COMPILER_SNAPSHOT.bin");
|
||||
ts::create_compiler_snapshot(compiler_snapshot_path, &c);
|
||||
|
||||
#[cfg(not(feature = "hmr"))]
|
||||
{
|
||||
let cli_snapshot_path = o.join("CLI_SNAPSHOT.bin");
|
||||
create_cli_snapshot(cli_snapshot_path);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let mut res = winres::WindowsResource::new();
|
||||
|
|
3
cli/cache/cache_db.rs
vendored
3
cli/cache/cache_db.rs
vendored
|
@ -9,14 +9,13 @@ use deno_core::error::AnyError;
|
|||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::parking_lot::MutexGuard;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_runtime::deno_webstorage::rusqlite;
|
||||
use deno_runtime::deno_webstorage::rusqlite::Connection;
|
||||
use deno_runtime::deno_webstorage::rusqlite::OptionalExtension;
|
||||
use deno_runtime::deno_webstorage::rusqlite::Params;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use super::FastInsecureHasher;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CacheDBHash(u64);
|
||||
|
||||
|
|
16
cli/cache/caches.rs
vendored
16
cli/cache/caches.rs
vendored
|
@ -3,7 +3,7 @@
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_lib::cache::DenoDirProvider;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use super::cache_db::CacheDB;
|
||||
|
@ -14,10 +14,10 @@ use super::fast_check::FAST_CHECK_CACHE_DB;
|
|||
use super::incremental::INCREMENTAL_CACHE_DB;
|
||||
use super::module_info::MODULE_INFO_CACHE_DB;
|
||||
use super::node::NODE_ANALYSIS_CACHE_DB;
|
||||
use crate::sys::CliSys;
|
||||
use crate::cache::DenoDirProvider;
|
||||
|
||||
pub struct Caches {
|
||||
dir_provider: Arc<DenoDirProvider<CliSys>>,
|
||||
dir_provider: Arc<DenoDirProvider>,
|
||||
fmt_incremental_cache_db: OnceCell<CacheDB>,
|
||||
lint_incremental_cache_db: OnceCell<CacheDB>,
|
||||
dep_analysis_db: OnceCell<CacheDB>,
|
||||
|
@ -28,7 +28,7 @@ pub struct Caches {
|
|||
}
|
||||
|
||||
impl Caches {
|
||||
pub fn new(dir: Arc<DenoDirProvider<CliSys>>) -> Self {
|
||||
pub fn new(dir: Arc<DenoDirProvider>) -> Self {
|
||||
Self {
|
||||
dir_provider: dir,
|
||||
fmt_incremental_cache_db: Default::default(),
|
||||
|
@ -49,13 +49,9 @@ impl Caches {
|
|||
cell
|
||||
.get_or_init(|| {
|
||||
if let Some(path) = path {
|
||||
CacheDB::from_path(
|
||||
config,
|
||||
path,
|
||||
crate::version::DENO_VERSION_INFO.deno,
|
||||
)
|
||||
CacheDB::from_path(config, path, DENO_VERSION_INFO.deno)
|
||||
} else {
|
||||
CacheDB::in_memory(config, crate::version::DENO_VERSION_INFO.deno)
|
||||
CacheDB::in_memory(config, DENO_VERSION_INFO.deno)
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
|
|
9
cli/cache/code_cache.rs
vendored
9
cli/cache/code_cache.rs
vendored
|
@ -1,7 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_runtime::code_cache;
|
||||
|
@ -11,7 +9,6 @@ use super::cache_db::CacheDB;
|
|||
use super::cache_db::CacheDBConfiguration;
|
||||
use super::cache_db::CacheDBHash;
|
||||
use super::cache_db::CacheFailure;
|
||||
use crate::worker::CliCodeCache;
|
||||
|
||||
pub static CODE_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration {
|
||||
table_initializer: concat!(
|
||||
|
@ -85,12 +82,6 @@ impl CodeCache {
|
|||
}
|
||||
}
|
||||
|
||||
impl CliCodeCache for CodeCache {
|
||||
fn as_code_cache(self: Arc<Self>) -> Arc<dyn code_cache::CodeCache> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl code_cache::CodeCache for CodeCache {
|
||||
fn get_sync(
|
||||
&self,
|
||||
|
|
|
@ -6,18 +6,18 @@ use std::path::PathBuf;
|
|||
use deno_cache_dir::DenoDirResolutionError;
|
||||
|
||||
use super::DiskCache;
|
||||
use crate::sys::DenoLibSys;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
/// Lazily creates the deno dir which might be useful in scenarios
|
||||
/// where functionality wants to continue if the DENO_DIR can't be created.
|
||||
pub struct DenoDirProvider<TSys: DenoLibSys> {
|
||||
sys: TSys,
|
||||
pub struct DenoDirProvider {
|
||||
sys: CliSys,
|
||||
maybe_custom_root: Option<PathBuf>,
|
||||
deno_dir: std::sync::OnceLock<Result<DenoDir<TSys>, DenoDirResolutionError>>,
|
||||
deno_dir: std::sync::OnceLock<Result<DenoDir, DenoDirResolutionError>>,
|
||||
}
|
||||
|
||||
impl<TSys: DenoLibSys> DenoDirProvider<TSys> {
|
||||
pub fn new(sys: TSys, maybe_custom_root: Option<PathBuf>) -> Self {
|
||||
impl DenoDirProvider {
|
||||
pub fn new(sys: CliSys, maybe_custom_root: Option<PathBuf>) -> Self {
|
||||
Self {
|
||||
sys,
|
||||
maybe_custom_root,
|
||||
|
@ -25,9 +25,7 @@ impl<TSys: DenoLibSys> DenoDirProvider<TSys> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create(
|
||||
&self,
|
||||
) -> Result<&DenoDir<TSys>, DenoDirResolutionError> {
|
||||
pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> {
|
||||
self
|
||||
.deno_dir
|
||||
.get_or_init(|| {
|
||||
|
@ -50,16 +48,16 @@ impl<TSys: DenoLibSys> DenoDirProvider<TSys> {
|
|||
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
|
||||
/// in single directory that can be controlled with `$DENO_DIR` env variable.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DenoDir<TSys: DenoLibSys> {
|
||||
pub struct DenoDir {
|
||||
/// Example: /Users/rld/.deno/
|
||||
pub root: PathBuf,
|
||||
/// Used by TsCompiler to cache compiler output.
|
||||
pub gen_cache: DiskCache<TSys>,
|
||||
pub gen_cache: DiskCache,
|
||||
}
|
||||
|
||||
impl<TSys: DenoLibSys> DenoDir<TSys> {
|
||||
impl DenoDir {
|
||||
pub fn new(
|
||||
sys: TSys,
|
||||
sys: CliSys,
|
||||
maybe_custom_root: Option<PathBuf>,
|
||||
) -> Result<Self, deno_cache_dir::DenoDirResolutionError> {
|
||||
let root = deno_cache_dir::resolve_deno_dir(
|
|
@ -10,21 +10,21 @@ use std::str;
|
|||
|
||||
use deno_cache_dir::url_to_filename;
|
||||
use deno_cache_dir::CACHE_PERM;
|
||||
use deno_core::url::Host;
|
||||
use deno_core::url::Url;
|
||||
use deno_path_util::fs::atomic_write_file_with_retries;
|
||||
use url::Host;
|
||||
use url::Url;
|
||||
|
||||
use crate::sys::DenoLibSys;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DiskCache<TSys: DenoLibSys> {
|
||||
sys: TSys,
|
||||
pub struct DiskCache {
|
||||
sys: CliSys,
|
||||
pub location: PathBuf,
|
||||
}
|
||||
|
||||
impl<TSys: DenoLibSys> DiskCache<TSys> {
|
||||
impl DiskCache {
|
||||
/// `location` must be an absolute path.
|
||||
pub fn new(sys: TSys, location: &Path) -> Self {
|
||||
pub fn new(sys: CliSys, location: &Path) -> Self {
|
||||
assert!(location.is_absolute());
|
||||
Self {
|
||||
sys,
|
12
cli/cache/emit.rs
vendored
12
cli/cache/emit.rs
vendored
|
@ -6,25 +6,25 @@ use deno_ast::ModuleSpecifier;
|
|||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::unsync::sync::AtomicFlag;
|
||||
use deno_lib::cache::DiskCache;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
|
||||
use crate::sys::CliSys;
|
||||
use super::DiskCache;
|
||||
|
||||
/// The cache that stores previously emitted files.
|
||||
#[derive(Debug)]
|
||||
pub struct EmitCache {
|
||||
disk_cache: DiskCache<CliSys>,
|
||||
disk_cache: DiskCache,
|
||||
emit_failed_flag: AtomicFlag,
|
||||
file_serializer: EmitFileSerializer,
|
||||
}
|
||||
|
||||
impl EmitCache {
|
||||
pub fn new(disk_cache: DiskCache<CliSys>) -> Self {
|
||||
pub fn new(disk_cache: DiskCache) -> Self {
|
||||
Self {
|
||||
disk_cache,
|
||||
emit_failed_flag: Default::default(),
|
||||
file_serializer: EmitFileSerializer {
|
||||
cli_version: crate::version::DENO_VERSION_INFO.deno,
|
||||
cli_version: DENO_VERSION_INFO.deno,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ impl EmitFileSerializer {
|
|||
// it's ok to use an insecure hash here because
|
||||
// if someone can change the emit source then they
|
||||
// can also change the version hash
|
||||
crate::cache::FastInsecureHasher::new_without_deno_version() // use cli_version property instead
|
||||
deno_lib::util::hash::FastInsecureHasher::new_without_deno_version() // use cli_version property instead
|
||||
.write(bytes)
|
||||
// emit should not be re-used between cli versions
|
||||
.write_str(self.cli_version)
|
||||
|
|
7
cli/cache/mod.rs
vendored
7
cli/cache/mod.rs
vendored
|
@ -30,7 +30,8 @@ mod cache_db;
|
|||
mod caches;
|
||||
mod check;
|
||||
mod code_cache;
|
||||
mod common;
|
||||
mod deno_dir;
|
||||
mod disk_cache;
|
||||
mod emit;
|
||||
mod fast_check;
|
||||
mod incremental;
|
||||
|
@ -42,9 +43,11 @@ pub use cache_db::CacheDBHash;
|
|||
pub use caches::Caches;
|
||||
pub use check::TypeCheckCache;
|
||||
pub use code_cache::CodeCache;
|
||||
pub use common::FastInsecureHasher;
|
||||
/// Permissions used to save a file in the disk caches.
|
||||
pub use deno_cache_dir::CACHE_PERM;
|
||||
pub use deno_dir::DenoDir;
|
||||
pub use deno_dir::DenoDirProvider;
|
||||
pub use disk_cache::DiskCache;
|
||||
pub use emit::EmitCache;
|
||||
pub use fast_check::FastCheckCache;
|
||||
pub use incremental::IncrementalCache;
|
||||
|
|
|
@ -20,9 +20,9 @@ use deno_error::JsErrorBox;
|
|||
use deno_graph::MediaType;
|
||||
use deno_graph::Module;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
|
||||
use crate::cache::EmitCache;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::resolver::CliCjsTracker;
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ use deno_core::error::AnyError;
|
|||
use deno_core::futures::FutureExt;
|
||||
use deno_core::FeatureChecker;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::cache::DenoDir;
|
||||
use deno_lib::cache::DenoDirProvider;
|
||||
use deno_lib::args::get_root_cert_store;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::loader::NpmModuleLoader;
|
||||
use deno_lib::npm::create_npm_process_state_provider;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionChecker;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
|
||||
use deno_lib::worker::LibMainWorkerFactory;
|
||||
|
@ -42,8 +44,6 @@ use node_resolver::analyze::NodeCodeTranslator;
|
|||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::args::check_warn_tsconfig;
|
||||
use crate::args::get_root_cert_store;
|
||||
use crate::args::CaData;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::Flags;
|
||||
|
@ -51,6 +51,8 @@ use crate::args::NpmInstallDepsProvider;
|
|||
use crate::args::TsConfigType;
|
||||
use crate::cache::Caches;
|
||||
use crate::cache::CodeCache;
|
||||
use crate::cache::DenoDir;
|
||||
use crate::cache::DenoDirProvider;
|
||||
use crate::cache::EmitCache;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
|
@ -71,7 +73,6 @@ use crate::node::CliCjsCodeAnalyzer;
|
|||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::node::CliNodeResolver;
|
||||
use crate::node::CliPackageJsonResolver;
|
||||
use crate::npm::create_npm_process_state_provider;
|
||||
use crate::npm::installer::NpmInstaller;
|
||||
use crate::npm::installer::NpmResolutionInstaller;
|
||||
use crate::npm::CliByonmNpmResolverCreateOptions;
|
||||
|
@ -91,7 +92,6 @@ use crate::resolver::CliNpmReqResolver;
|
|||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::FoundPackageJsonDepFlag;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::standalone::binary::DenoCompileBinaryWriter;
|
||||
use crate::sys::CliSys;
|
||||
use crate::tools::check::TypeChecker;
|
||||
|
@ -283,13 +283,11 @@ impl CliFactory {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn deno_dir_provider(
|
||||
&self,
|
||||
) -> Result<&Arc<DenoDirProvider<CliSys>>, AnyError> {
|
||||
pub fn deno_dir_provider(&self) -> Result<&Arc<DenoDirProvider>, AnyError> {
|
||||
Ok(&self.cli_options()?.deno_dir_provider)
|
||||
}
|
||||
|
||||
pub fn deno_dir(&self) -> Result<&DenoDir<CliSys>, AnyError> {
|
||||
pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> {
|
||||
Ok(self.deno_dir_provider()?.get_or_create()?)
|
||||
}
|
||||
|
||||
|
@ -815,19 +813,11 @@ impl CliFactory {
|
|||
.services
|
||||
.node_code_translator
|
||||
.get_or_try_init_async(async {
|
||||
let caches = self.caches()?;
|
||||
let node_analysis_cache =
|
||||
NodeAnalysisCache::new(caches.node_analysis_db());
|
||||
let node_resolver = self.node_resolver().await?.clone();
|
||||
let cjs_esm_analyzer = CliCjsCodeAnalyzer::new(
|
||||
node_analysis_cache,
|
||||
self.cjs_tracker()?.clone(),
|
||||
self.fs().clone(),
|
||||
Some(self.parsed_source_cache().clone()),
|
||||
);
|
||||
let cjs_code_analyzer = self.create_cjs_code_analyzer()?;
|
||||
|
||||
Ok(Arc::new(NodeCodeTranslator::new(
|
||||
cjs_esm_analyzer,
|
||||
cjs_code_analyzer,
|
||||
self.in_npm_pkg_checker()?.clone(),
|
||||
node_resolver,
|
||||
self.npm_resolver().await?.clone(),
|
||||
|
@ -838,6 +828,17 @@ impl CliFactory {
|
|||
.await
|
||||
}
|
||||
|
||||
fn create_cjs_code_analyzer(&self) -> Result<CliCjsCodeAnalyzer, AnyError> {
|
||||
let caches = self.caches()?;
|
||||
let node_analysis_cache = NodeAnalysisCache::new(caches.node_analysis_db());
|
||||
Ok(CliCjsCodeAnalyzer::new(
|
||||
node_analysis_cache,
|
||||
self.cjs_tracker()?.clone(),
|
||||
self.fs().clone(),
|
||||
Some(self.parsed_source_cache().clone()),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn npm_req_resolver(
|
||||
&self,
|
||||
) -> Result<&Arc<CliNpmReqResolver>, AnyError> {
|
||||
|
@ -1027,11 +1028,11 @@ impl CliFactory {
|
|||
) -> Result<DenoCompileBinaryWriter, AnyError> {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(DenoCompileBinaryWriter::new(
|
||||
self.create_cjs_code_analyzer()?,
|
||||
self.cjs_tracker()?,
|
||||
self.cli_options()?,
|
||||
self.deno_dir()?,
|
||||
self.emitter()?,
|
||||
self.file_fetcher()?,
|
||||
self.http_client_provider(),
|
||||
self.npm_resolver().await?,
|
||||
self.workspace_resolver().await?.as_ref(),
|
||||
|
@ -1103,8 +1104,8 @@ impl CliFactory {
|
|||
node_resolver.clone(),
|
||||
NpmModuleLoader::new(
|
||||
self.cjs_tracker()?.clone(),
|
||||
fs.clone(),
|
||||
node_code_translator.clone(),
|
||||
self.sys(),
|
||||
),
|
||||
npm_registry_permission_checker,
|
||||
npm_req_resolver.clone(),
|
||||
|
@ -1138,7 +1139,6 @@ impl CliFactory {
|
|||
lib_main_worker_factory,
|
||||
maybe_file_watcher_communicator,
|
||||
cli_options.maybe_lockfile().cloned(),
|
||||
node_resolver.clone(),
|
||||
self.npm_installer_if_managed()?.cloned(),
|
||||
npm_resolver.clone(),
|
||||
self.sys(),
|
||||
|
@ -1180,8 +1180,6 @@ impl CliFactory {
|
|||
node_ipc: cli_options.node_ipc_fd(),
|
||||
serve_port: cli_options.serve_port(),
|
||||
serve_host: cli_options.serve_host(),
|
||||
deno_version: crate::version::DENO_VERSION_INFO.deno,
|
||||
deno_user_agent: crate::version::DENO_VERSION_INFO.user_agent,
|
||||
otel_config: self.cli_options()?.otel_config(),
|
||||
startup_snapshot: crate::js::deno_isolate_init(),
|
||||
})
|
||||
|
|
|
@ -14,6 +14,7 @@ use deno_core::serde_json;
|
|||
use deno_core::url::Url;
|
||||
use deno_error::JsError;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_runtime::deno_fetch;
|
||||
use deno_runtime::deno_fetch::create_http_client;
|
||||
use deno_runtime::deno_fetch::CreateHttpClientOptions;
|
||||
|
@ -28,7 +29,6 @@ use http_body_util::BodyExt;
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::util::progress_bar::UpdateGuard;
|
||||
use crate::version;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SendError {
|
||||
|
@ -79,7 +79,7 @@ impl HttpClientProvider {
|
|||
Entry::Occupied(entry) => Ok(HttpClient::new(entry.get().clone())),
|
||||
Entry::Vacant(entry) => {
|
||||
let client = create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
root_cert_store: match &self.root_cert_store_provider {
|
||||
Some(provider) => Some(provider.get_or_try_init()?.clone()),
|
||||
|
@ -481,7 +481,7 @@ mod test {
|
|||
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
ca_certs: vec![std::fs::read(
|
||||
test_util::testdata_path().join("tls/RootCA.pem"),
|
||||
|
@ -525,7 +525,7 @@ mod test {
|
|||
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions::default(),
|
||||
)
|
||||
.unwrap(),
|
||||
|
@ -566,7 +566,7 @@ mod test {
|
|||
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
root_cert_store: Some(root_cert_store),
|
||||
..Default::default()
|
||||
|
@ -587,7 +587,7 @@ mod test {
|
|||
.unwrap();
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
ca_certs: vec![std::fs::read(
|
||||
test_util::testdata_path()
|
||||
|
@ -620,7 +620,7 @@ mod test {
|
|||
let url = Url::parse("https://localhost:5545/etag_script.ts").unwrap();
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
ca_certs: vec![std::fs::read(
|
||||
test_util::testdata_path()
|
||||
|
@ -661,7 +661,7 @@ mod test {
|
|||
.unwrap();
|
||||
let client = HttpClient::new(
|
||||
create_http_client(
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
DENO_VERSION_INFO.user_agent,
|
||||
CreateHttpClientOptions {
|
||||
ca_certs: vec![std::fs::read(
|
||||
test_util::testdata_path()
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub fn main() {
|
||||
let mut args = vec!["cargo", "test", "-p", "cli_tests", "--features", "run"];
|
||||
|
||||
if !cfg!(debug_assertions) {
|
||||
args.push("--release");
|
||||
}
|
||||
|
||||
args.push("--");
|
||||
|
||||
// If any args were passed to this process, pass them through to the child
|
||||
let orig_args = std::env::args().skip(1).collect::<Vec<_>>();
|
||||
let orig_args: Vec<&str> =
|
||||
orig_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>();
|
||||
args.extend(orig_args);
|
||||
|
||||
test_util::spawn::exec_replace("cargo", &args).unwrap();
|
||||
// this file exists to cause the executable to be built when running cargo test
|
||||
}
|
||||
|
|
13
cli/js.rs
13
cli/js.rs
|
@ -2,18 +2,7 @@
|
|||
|
||||
use log::debug;
|
||||
|
||||
#[cfg(not(feature = "hmr"))]
|
||||
static CLI_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
|
||||
|
||||
pub fn deno_isolate_init() -> Option<&'static [u8]> {
|
||||
debug!("Deno isolate init with snapshots.");
|
||||
#[cfg(not(feature = "hmr"))]
|
||||
{
|
||||
Some(CLI_SNAPSHOT)
|
||||
}
|
||||
#[cfg(feature = "hmr")]
|
||||
{
|
||||
None
|
||||
}
|
||||
deno_snapshots::CLI_SNAPSHOT
|
||||
}
|
||||
|
|
|
@ -14,23 +14,32 @@ description = "Shared code between the Deno CLI and denort"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_cache_dir.workspace = true
|
||||
capacity_builder.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_error.workspace = true
|
||||
deno_fs = { workspace = true, features = ["sync_fs"] }
|
||||
deno_media_type.workspace = true
|
||||
deno_node = { workspace = true, features = ["sync_fs"] }
|
||||
deno_npm.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_runtime.workspace = true
|
||||
deno_semver.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
env_logger = "=0.10.0"
|
||||
faster-hex.workspace = true
|
||||
indexmap.workspace = true
|
||||
libsui.workspace = true
|
||||
log.workspace = true
|
||||
node_resolver = { workspace = true, features = ["sync"] }
|
||||
parking_lot.workspace = true
|
||||
ring.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
sys_traits = { workspace = true, features = ["getrandom"] }
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
twox-hash.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
199
cli/lib/args.rs
Normal file
199
cli/lib/args.rs
Normal file
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::io::BufReader;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
use std::io::Seek;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
|
||||
use deno_runtime::deno_tls::rustls;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::rustls_pemfile;
|
||||
use deno_runtime::deno_tls::webpki_roots;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
pub fn npm_pkg_req_ref_to_binary_command(
|
||||
req_ref: &NpmPackageReqReference,
|
||||
) -> String {
|
||||
req_ref
|
||||
.sub_path()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| req_ref.req().name.to_string())
|
||||
}
|
||||
|
||||
pub fn has_trace_permissions_enabled() -> bool {
|
||||
has_flag_env_var("DENO_TRACE_PERMISSIONS")
|
||||
}
|
||||
|
||||
pub fn has_flag_env_var(name: &str) -> bool {
|
||||
let value = std::env::var(name);
|
||||
matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum CaData {
|
||||
/// The string is a file path
|
||||
File(String),
|
||||
/// This variant is not exposed as an option in the CLI, it is used internally
|
||||
/// for standalone binaries.
|
||||
Bytes(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, deno_error::JsError)]
|
||||
#[class(generic)]
|
||||
pub enum RootCertStoreLoadError {
|
||||
#[error(
|
||||
"Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")"
|
||||
)]
|
||||
UnknownStore(String),
|
||||
#[error("Unable to add pem file to certificate store: {0}")]
|
||||
FailedAddPemFile(String),
|
||||
#[error("Failed opening CA file: {0}")]
|
||||
CaFileOpenError(String),
|
||||
}
|
||||
|
||||
/// Create and populate a root cert store based on the passed options and
|
||||
/// environment.
|
||||
pub fn get_root_cert_store(
|
||||
maybe_root_path: Option<PathBuf>,
|
||||
maybe_ca_stores: Option<Vec<String>>,
|
||||
maybe_ca_data: Option<CaData>,
|
||||
) -> Result<RootCertStore, RootCertStoreLoadError> {
|
||||
let mut root_cert_store = RootCertStore::empty();
|
||||
let ca_stores: Vec<String> = maybe_ca_stores
|
||||
.or_else(|| {
|
||||
let env_ca_store = std::env::var("DENO_TLS_CA_STORE").ok()?;
|
||||
Some(
|
||||
env_ca_store
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| vec!["mozilla".to_string()]);
|
||||
|
||||
for store in ca_stores.iter() {
|
||||
match store.as_str() {
|
||||
"mozilla" => {
|
||||
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.to_vec());
|
||||
}
|
||||
"system" => {
|
||||
let roots = load_native_certs().expect("could not load platform certs");
|
||||
for root in roots {
|
||||
if let Err(err) = root_cert_store
|
||||
.add(rustls::pki_types::CertificateDer::from(root.0.clone()))
|
||||
{
|
||||
log::error!(
|
||||
"{}",
|
||||
colors::yellow(&format!(
|
||||
"Unable to add system certificate to certificate store: {:?}",
|
||||
err
|
||||
))
|
||||
);
|
||||
let hex_encoded_root = faster_hex::hex_string(&root.0);
|
||||
log::error!("{}", colors::gray(&hex_encoded_root));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(RootCertStoreLoadError::UnknownStore(store.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ca_data =
|
||||
maybe_ca_data.or_else(|| std::env::var("DENO_CERT").ok().map(CaData::File));
|
||||
if let Some(ca_data) = ca_data {
|
||||
let result = match ca_data {
|
||||
CaData::File(ca_file) => {
|
||||
let ca_file = if let Some(root) = &maybe_root_path {
|
||||
root.join(&ca_file)
|
||||
} else {
|
||||
PathBuf::from(ca_file)
|
||||
};
|
||||
let certfile = std::fs::File::open(ca_file).map_err(|err| {
|
||||
RootCertStoreLoadError::CaFileOpenError(err.to_string())
|
||||
})?;
|
||||
let mut reader = BufReader::new(certfile);
|
||||
rustls_pemfile::certs(&mut reader).collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
CaData::Bytes(data) => {
|
||||
let mut reader = BufReader::new(Cursor::new(data));
|
||||
rustls_pemfile::certs(&mut reader).collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(certs) => {
|
||||
root_cert_store.add_parsable_certificates(certs);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(RootCertStoreLoadError::FailedAddPemFile(e.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(root_cert_store)
|
||||
}
|
||||
|
||||
/// State provided to the process via an environment variable.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct NpmProcessState {
|
||||
pub kind: NpmProcessStateKind,
|
||||
pub local_node_modules_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum NpmProcessStateKind {
|
||||
Snapshot(deno_npm::resolution::SerializedNpmResolutionSnapshot),
|
||||
Byonm,
|
||||
}
|
||||
|
||||
pub static NPM_PROCESS_STATE: LazyLock<Option<NpmProcessState>> =
|
||||
LazyLock::new(|| {
|
||||
use deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
|
||||
let fd = std::env::var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME).ok()?;
|
||||
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME);
|
||||
let fd = fd.parse::<usize>().ok()?;
|
||||
let mut file = {
|
||||
use deno_runtime::deno_io::FromRawIoHandle;
|
||||
unsafe { std::fs::File::from_raw_io_handle(fd as _) }
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
// seek to beginning. after the file is written the position will be inherited by this subprocess,
|
||||
// and also this file might have been read before
|
||||
file.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||
file
|
||||
.read_to_end(&mut buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!("failed to read npm process state from fd {fd}: {e}");
|
||||
})
|
||||
.ok()?;
|
||||
let state: NpmProcessState = serde_json::from_slice(&buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!(
|
||||
"failed to deserialize npm process state: {e} {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
Some(state)
|
||||
});
|
||||
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UnstableConfig {
|
||||
// TODO(bartlomieju): remove in Deno 2.5
|
||||
pub legacy_flag_enabled: bool, // --unstable
|
||||
pub bare_node_builtins: bool,
|
||||
pub detect_cjs: bool,
|
||||
pub sloppy_imports: bool,
|
||||
pub npm_lazy_caching: bool,
|
||||
pub features: Vec<String>, // --unstabe-kv --unstable-cron
|
||||
}
|
42
cli/lib/build.rs
Normal file
42
cli/lib/build.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
fn main() {
|
||||
// todo(dsherret): remove this after Deno 2.2.0 is published and then
|
||||
// align the version of this crate with Deno then. We need to wait because
|
||||
// there was previously a deno_lib 2.2.0 published (https://crates.io/crates/deno_lib/versions)
|
||||
let version_path = std::path::Path::new(".").join("version.txt");
|
||||
println!("cargo:rerun-if-changed={}", version_path.display());
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let text = std::fs::read_to_string(version_path).unwrap();
|
||||
println!("cargo:rustc-env=DENO_VERSION={}", text);
|
||||
|
||||
let commit_hash = git_commit_hash();
|
||||
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", commit_hash);
|
||||
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_COMMIT_HASH_SHORT={}",
|
||||
&commit_hash[..7]
|
||||
);
|
||||
}
|
||||
|
||||
fn git_commit_hash() -> String {
|
||||
if let Ok(output) = std::process::Command::new("git")
|
||||
.arg("rev-list")
|
||||
.arg("-1")
|
||||
.arg("HEAD")
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
std::str::from_utf8(&output.stdout[..40])
|
||||
.unwrap()
|
||||
.to_string()
|
||||
} else {
|
||||
// When not in git repository
|
||||
// (e.g. when the user install by `cargo install deno`)
|
||||
"UNKNOWN".to_string()
|
||||
}
|
||||
} else {
|
||||
// When there is no git command for some reason
|
||||
"UNKNOWN".to_string()
|
||||
}
|
||||
}
|
8
cli/lib/cache/mod.rs
vendored
8
cli/lib/cache/mod.rs
vendored
|
@ -1,8 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub use deno_dir::DenoDir;
|
||||
pub use deno_dir::DenoDirProvider;
|
||||
pub use disk_cache::DiskCache;
|
||||
|
||||
mod deno_dir;
|
||||
mod disk_cache;
|
48
cli/lib/clippy.toml
Normal file
48
cli/lib/clippy.toml
Normal file
|
@ -0,0 +1,48 @@
|
|||
disallowed-methods = [
|
||||
{ path = "std::env::current_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::is_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::is_file", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::is_symlink", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::read_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::read_link", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::symlink_metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::try_exists", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::exists", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::canonicalize", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::is_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::is_file", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::is_symlink", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::read_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::read_link", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::symlink_metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::PathBuf::try_exists", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::env::set_current_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::env::temp_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::canonicalize", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::copy", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::create_dir_all", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::create_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::DirBuilder::new", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::hard_link", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::OpenOptions::new", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::read_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::read_link", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::read_to_string", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::read", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::remove_dir_all", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::remove_dir", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::remove_file", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::rename", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::set_permissions", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::symlink_metadata", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::fs::write", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "std::path::Path::exists", reason = "File system operations should be done using DenoLibSys" },
|
||||
{ path = "url::Url::to_file_path", reason = "Use deno_path_util instead" },
|
||||
{ path = "url::Url::from_file_path", reason = "Use deno_path_util instead" },
|
||||
{ path = "url::Url::from_directory_path", reason = "Use deno_path_util instead" },
|
||||
]
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub fn has_trace_permissions_enabled() -> bool {
|
||||
has_flag_env_var("DENO_TRACE_PERMISSIONS")
|
||||
}
|
||||
|
||||
pub fn has_flag_env_var(name: &str) -> bool {
|
||||
let value = std::env::var(name);
|
||||
matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub mod cache;
|
||||
pub mod env;
|
||||
pub mod args;
|
||||
pub mod loader;
|
||||
pub mod npm;
|
||||
pub mod shared;
|
||||
pub mod standalone;
|
||||
pub mod sys;
|
||||
pub mod util;
|
||||
pub mod version;
|
||||
pub mod worker;
|
||||
|
|
213
cli/lib/loader.rs
Normal file
213
cli/lib/loader.rs
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_media_type::MediaType;
|
||||
use deno_resolver::cjs::CjsTracker;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_runtime::deno_core::ModuleSourceCode;
|
||||
use node_resolver::analyze::CjsCodeAnalyzer;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::IsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NpmPackageFolderResolver;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
use crate::sys::DenoLibSys;
|
||||
use crate::util::text_encoding::from_utf8_lossy_cow;
|
||||
|
||||
pub struct ModuleCodeStringSource {
|
||||
pub code: ModuleSourceCode,
|
||||
pub found_url: Url,
|
||||
pub media_type: MediaType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, deno_error::JsError)]
|
||||
#[class(type)]
|
||||
#[error("{media_type} files are not supported in npm packages: {specifier}")]
|
||||
pub struct NotSupportedKindInNpmError {
|
||||
pub media_type: MediaType,
|
||||
pub specifier: Url,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, deno_error::JsError)]
|
||||
pub enum NpmModuleLoadError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
NotSupportedKindInNpm(#[from] NotSupportedKindInNpmError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
|
||||
#[class(inherit)]
|
||||
#[error("Unable to load {}{}", file_path.display(), maybe_referrer.as_ref().map(|r| format!(" imported from {}", r)).unwrap_or_default())]
|
||||
UnableToLoad {
|
||||
file_path: PathBuf,
|
||||
maybe_referrer: Option<Url>,
|
||||
#[source]
|
||||
#[inherit]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[class(inherit)]
|
||||
#[error(
|
||||
"{}",
|
||||
format_dir_import_message(file_path, maybe_referrer, suggestion)
|
||||
)]
|
||||
DirImport {
|
||||
file_path: PathBuf,
|
||||
maybe_referrer: Option<Url>,
|
||||
suggestion: Option<&'static str>,
|
||||
#[source]
|
||||
#[inherit]
|
||||
source: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
fn format_dir_import_message(
|
||||
file_path: &std::path::Path,
|
||||
maybe_referrer: &Option<Url>,
|
||||
suggestion: &Option<&'static str>,
|
||||
) -> String {
|
||||
// directory imports are not allowed when importing from an
|
||||
// ES module, so provide the user with a helpful error message
|
||||
let dir_path = file_path;
|
||||
let mut msg = "Directory import ".to_string();
|
||||
msg.push_str(&dir_path.to_string_lossy());
|
||||
if let Some(referrer) = maybe_referrer {
|
||||
msg.push_str(" is not supported resolving import from ");
|
||||
msg.push_str(referrer.as_str());
|
||||
if let Some(entrypoint_name) = suggestion {
|
||||
msg.push_str("\nDid you mean to import ");
|
||||
msg.push_str(entrypoint_name);
|
||||
msg.push_str(" within the directory?");
|
||||
}
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NpmModuleLoader<
|
||||
TCjsCodeAnalyzer: CjsCodeAnalyzer,
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoLibSys,
|
||||
> {
|
||||
cjs_tracker: Arc<CjsTracker<DenoInNpmPackageChecker, TSys>>,
|
||||
sys: TSys,
|
||||
node_code_translator: Arc<
|
||||
NodeCodeTranslator<
|
||||
TCjsCodeAnalyzer,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<
|
||||
TCjsCodeAnalyzer: CjsCodeAnalyzer,
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoLibSys,
|
||||
>
|
||||
NpmModuleLoader<
|
||||
TCjsCodeAnalyzer,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>
|
||||
{
|
||||
pub fn new(
|
||||
cjs_tracker: Arc<CjsTracker<DenoInNpmPackageChecker, TSys>>,
|
||||
node_code_translator: Arc<
|
||||
NodeCodeTranslator<
|
||||
TCjsCodeAnalyzer,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
>,
|
||||
sys: TSys,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_tracker,
|
||||
node_code_translator,
|
||||
sys,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
maybe_referrer: Option<&Url>,
|
||||
) -> Result<ModuleCodeStringSource, NpmModuleLoadError> {
|
||||
let file_path = deno_path_util::url_to_file_path(specifier)?;
|
||||
let code = self.sys.fs_read(&file_path).map_err(|source| {
|
||||
if self.sys.fs_is_dir_no_err(&file_path) {
|
||||
let suggestion = ["index.mjs", "index.js", "index.cjs"]
|
||||
.into_iter()
|
||||
.find(|e| self.sys.fs_is_file_no_err(file_path.join(e)));
|
||||
NpmModuleLoadError::DirImport {
|
||||
file_path,
|
||||
maybe_referrer: maybe_referrer.cloned(),
|
||||
suggestion,
|
||||
source,
|
||||
}
|
||||
} else {
|
||||
NpmModuleLoadError::UnableToLoad {
|
||||
file_path,
|
||||
maybe_referrer: maybe_referrer.cloned(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
if media_type.is_emittable() {
|
||||
return Err(NpmModuleLoadError::NotSupportedKindInNpm(
|
||||
NotSupportedKindInNpmError {
|
||||
media_type,
|
||||
specifier: specifier.clone(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let code = if self.cjs_tracker.is_maybe_cjs(specifier, media_type)? {
|
||||
// translate cjs to esm if it's cjs and inject node globals
|
||||
let code = from_utf8_lossy_cow(code);
|
||||
ModuleSourceCode::String(
|
||||
self
|
||||
.node_code_translator
|
||||
.translate_cjs_to_esm(specifier, Some(code))
|
||||
.await?
|
||||
.into_owned()
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
// esm and json code is untouched
|
||||
ModuleSourceCode::Bytes(match code {
|
||||
Cow::Owned(bytes) => bytes.into_boxed_slice().into(),
|
||||
Cow::Borrowed(bytes) => bytes.into(),
|
||||
})
|
||||
};
|
||||
|
||||
Ok(ModuleCodeStringSource {
|
||||
code,
|
||||
found_url: specifier.clone(),
|
||||
media_type: MediaType::from_specifier(specifier),
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,5 +2,79 @@
|
|||
|
||||
mod permission_checker;
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_resolver::npm::ByonmNpmResolver;
|
||||
use deno_resolver::npm::ManagedNpmResolverRc;
|
||||
use deno_resolver::npm::NpmResolver;
|
||||
use deno_runtime::deno_process::NpmProcessStateProvider;
|
||||
use deno_runtime::deno_process::NpmProcessStateProviderRc;
|
||||
pub use permission_checker::NpmRegistryReadPermissionChecker;
|
||||
pub use permission_checker::NpmRegistryReadPermissionCheckerMode;
|
||||
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::sys::DenoLibSys;
|
||||
|
||||
pub fn create_npm_process_state_provider<TSys: DenoLibSys>(
|
||||
npm_resolver: &NpmResolver<TSys>,
|
||||
) -> NpmProcessStateProviderRc {
|
||||
match npm_resolver {
|
||||
NpmResolver::Byonm(byonm_npm_resolver) => {
|
||||
Arc::new(ByonmNpmProcessStateProvider(byonm_npm_resolver.clone()))
|
||||
}
|
||||
NpmResolver::Managed(managed_npm_resolver) => {
|
||||
Arc::new(ManagedNpmProcessStateProvider(managed_npm_resolver.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn npm_process_state(
|
||||
snapshot: ValidSerializedNpmResolutionSnapshot,
|
||||
node_modules_path: Option<&Path>,
|
||||
) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Snapshot(snapshot.into_serialized()),
|
||||
local_node_modules_path: node_modules_path
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ManagedNpmProcessStateProvider<TSys: DenoLibSys>(
|
||||
pub ManagedNpmResolverRc<TSys>,
|
||||
);
|
||||
|
||||
impl<TSys: DenoLibSys> NpmProcessStateProvider
|
||||
for ManagedNpmProcessStateProvider<TSys>
|
||||
{
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
npm_process_state(
|
||||
self.0.resolution().serialized_valid_snapshot(),
|
||||
self.0.root_node_modules_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ByonmNpmProcessStateProvider<TSys: DenoLibSys>(
|
||||
pub Arc<ByonmNpmResolver<TSys>>,
|
||||
);
|
||||
|
||||
impl<TSys: DenoLibSys> NpmProcessStateProvider
|
||||
for ByonmNpmProcessStateProvider<TSys>
|
||||
{
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Byonm,
|
||||
local_node_modules_path: self
|
||||
.0
|
||||
.root_node_modules_path()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
/// This module is shared between build script and the binaries. Use it sparsely.
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::error::AnyError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Unrecognized release channel: {0}")]
|
||||
pub struct UnrecognizedReleaseChannelError(pub String);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ReleaseChannel {
|
||||
|
@ -50,13 +53,17 @@ impl ReleaseChannel {
|
|||
// NOTE(bartlomieju): do not ever change these values, tools like `patchver`
|
||||
// rely on them.
|
||||
#[allow(unused)]
|
||||
pub fn deserialize(str_: &str) -> Result<Self, AnyError> {
|
||||
pub fn deserialize(
|
||||
str_: &str,
|
||||
) -> Result<Self, UnrecognizedReleaseChannelError> {
|
||||
Ok(match str_ {
|
||||
"stable" => Self::Stable,
|
||||
"canary" => Self::Canary,
|
||||
"rc" => Self::Rc,
|
||||
"lts" => Self::Lts,
|
||||
unknown => bail!("Unrecognized release channel: {}", unknown),
|
||||
unknown => {
|
||||
return Err(UnrecognizedReleaseChannelError(unknown.to_string()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
389
cli/lib/standalone/binary.rs
Normal file
389
cli/lib/standalone/binary.rs
Normal file
|
@ -0,0 +1,389 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use deno_runtime::deno_telemetry::OtelConfig;
|
||||
use deno_semver::Version;
|
||||
use indexmap::IndexMap;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use url::Url;
|
||||
|
||||
use super::virtual_fs::FileSystemCaseSensitivity;
|
||||
use crate::args::UnstableConfig;
|
||||
|
||||
pub const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd";
|
||||
|
||||
pub trait DenoRtDeserializable<'a>: Sized {
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)>;
|
||||
}
|
||||
|
||||
impl<'a> DenoRtDeserializable<'a> for Cow<'a, [u8]> {
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)> {
|
||||
let (input, data) = read_bytes_with_u32_len(input)?;
|
||||
Ok((input, Cow::Borrowed(data)))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DenoRtSerializable<'a> {
|
||||
fn serialize(
|
||||
&'a self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, Vec<u8>>,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum NodeModules {
|
||||
Managed {
|
||||
/// Relative path for the node_modules directory in the vfs.
|
||||
node_modules_dir: Option<String>,
|
||||
},
|
||||
Byonm {
|
||||
root_node_modules_dir: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct SerializedWorkspaceResolverImportMap {
|
||||
pub specifier: String,
|
||||
pub json: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SerializedResolverWorkspaceJsrPackage {
|
||||
pub relative_base: String,
|
||||
pub name: String,
|
||||
pub version: Option<Version>,
|
||||
pub exports: IndexMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct SerializedWorkspaceResolver {
|
||||
pub import_map: Option<SerializedWorkspaceResolverImportMap>,
|
||||
pub jsr_pkgs: Vec<SerializedResolverWorkspaceJsrPackage>,
|
||||
pub package_jsons: BTreeMap<String, serde_json::Value>,
|
||||
pub pkg_json_resolution: PackageJsonDepResolution,
|
||||
}
|
||||
|
||||
// Note: Don't use hashmaps/hashsets. Ensure the serialization
|
||||
// is deterministic.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Metadata {
|
||||
pub argv: Vec<String>,
|
||||
pub seed: Option<u64>,
|
||||
pub code_cache_key: Option<u64>,
|
||||
pub permissions: PermissionsOptions,
|
||||
pub location: Option<Url>,
|
||||
pub v8_flags: Vec<String>,
|
||||
pub log_level: Option<log::Level>,
|
||||
pub ca_stores: Option<Vec<String>>,
|
||||
pub ca_data: Option<Vec<u8>>,
|
||||
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
||||
pub env_vars_from_env_file: IndexMap<String, String>,
|
||||
pub workspace_resolver: SerializedWorkspaceResolver,
|
||||
pub entrypoint_key: String,
|
||||
pub node_modules: Option<NodeModules>,
|
||||
pub unstable_config: UnstableConfig,
|
||||
pub otel_config: OtelConfig,
|
||||
pub vfs_case_sensitivity: FileSystemCaseSensitivity,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SpecifierId(u32);
|
||||
|
||||
impl SpecifierId {
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> capacity_builder::BytesAppendable<'a> for SpecifierId {
|
||||
fn append_to_builder<TBytes: capacity_builder::BytesType>(
|
||||
self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, TBytes>,
|
||||
) {
|
||||
builder.append_le(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DenoRtSerializable<'a> for SpecifierId {
|
||||
fn serialize(
|
||||
&'a self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, Vec<u8>>,
|
||||
) {
|
||||
builder.append_le(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DenoRtDeserializable<'a> for SpecifierId {
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)> {
|
||||
let (input, id) = read_u32(input)?;
|
||||
Ok((input, Self(id)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum CjsExportAnalysisEntry {
|
||||
Esm,
|
||||
Cjs(CjsAnalysisExports),
|
||||
}
|
||||
|
||||
const HAS_TRANSPILED_FLAG: u8 = 1 << 0;
|
||||
const HAS_SOURCE_MAP_FLAG: u8 = 1 << 1;
|
||||
const HAS_CJS_EXPORT_ANALYSIS_FLAG: u8 = 1 << 2;
|
||||
|
||||
pub struct RemoteModuleEntry<'a> {
|
||||
pub media_type: MediaType,
|
||||
pub data: Cow<'a, [u8]>,
|
||||
pub maybe_transpiled: Option<Cow<'a, [u8]>>,
|
||||
pub maybe_source_map: Option<Cow<'a, [u8]>>,
|
||||
pub maybe_cjs_export_analysis: Option<Cow<'a, [u8]>>,
|
||||
}
|
||||
|
||||
impl<'a> DenoRtSerializable<'a> for RemoteModuleEntry<'a> {
|
||||
fn serialize(
|
||||
&'a self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, Vec<u8>>,
|
||||
) {
|
||||
fn append_maybe_data<'a>(
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, Vec<u8>>,
|
||||
maybe_data: Option<&'a [u8]>,
|
||||
) {
|
||||
if let Some(data) = maybe_data {
|
||||
builder.append_le(data.len() as u32);
|
||||
builder.append(data);
|
||||
}
|
||||
}
|
||||
|
||||
let mut has_data_flags = 0;
|
||||
if self.maybe_transpiled.is_some() {
|
||||
has_data_flags |= HAS_TRANSPILED_FLAG;
|
||||
}
|
||||
if self.maybe_source_map.is_some() {
|
||||
has_data_flags |= HAS_SOURCE_MAP_FLAG;
|
||||
}
|
||||
if self.maybe_cjs_export_analysis.is_some() {
|
||||
has_data_flags |= HAS_CJS_EXPORT_ANALYSIS_FLAG;
|
||||
}
|
||||
builder.append(serialize_media_type(self.media_type));
|
||||
builder.append_le(self.data.len() as u32);
|
||||
builder.append(self.data.as_ref());
|
||||
builder.append(has_data_flags);
|
||||
append_maybe_data(builder, self.maybe_transpiled.as_deref());
|
||||
append_maybe_data(builder, self.maybe_source_map.as_deref());
|
||||
append_maybe_data(builder, self.maybe_cjs_export_analysis.as_deref());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DenoRtDeserializable<'a> for RemoteModuleEntry<'a> {
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn deserialize_data_if_has_flag(
|
||||
input: &[u8],
|
||||
has_data_flags: u8,
|
||||
flag: u8,
|
||||
) -> std::io::Result<(&[u8], Option<Cow<[u8]>>)> {
|
||||
if has_data_flags & flag != 0 {
|
||||
let (input, bytes) = read_bytes_with_u32_len(input)?;
|
||||
Ok((input, Some(Cow::Borrowed(bytes))))
|
||||
} else {
|
||||
Ok((input, None))
|
||||
}
|
||||
}
|
||||
|
||||
let (input, media_type) = MediaType::deserialize(input)?;
|
||||
let (input, data) = read_bytes_with_u32_len(input)?;
|
||||
let (input, has_data_flags) = read_u8(input)?;
|
||||
let (input, maybe_transpiled) =
|
||||
deserialize_data_if_has_flag(input, has_data_flags, HAS_TRANSPILED_FLAG)?;
|
||||
let (input, maybe_source_map) =
|
||||
deserialize_data_if_has_flag(input, has_data_flags, HAS_SOURCE_MAP_FLAG)?;
|
||||
let (input, maybe_cjs_export_analysis) = deserialize_data_if_has_flag(
|
||||
input,
|
||||
has_data_flags,
|
||||
HAS_CJS_EXPORT_ANALYSIS_FLAG,
|
||||
)?;
|
||||
Ok((
|
||||
input,
|
||||
Self {
|
||||
media_type,
|
||||
data: Cow::Borrowed(data),
|
||||
maybe_transpiled,
|
||||
maybe_source_map,
|
||||
maybe_cjs_export_analysis,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_media_type(media_type: MediaType) -> u8 {
|
||||
match media_type {
|
||||
MediaType::JavaScript => 0,
|
||||
MediaType::Jsx => 1,
|
||||
MediaType::Mjs => 2,
|
||||
MediaType::Cjs => 3,
|
||||
MediaType::TypeScript => 4,
|
||||
MediaType::Mts => 5,
|
||||
MediaType::Cts => 6,
|
||||
MediaType::Dts => 7,
|
||||
MediaType::Dmts => 8,
|
||||
MediaType::Dcts => 9,
|
||||
MediaType::Tsx => 10,
|
||||
MediaType::Json => 11,
|
||||
MediaType::Wasm => 12,
|
||||
MediaType::Css => 13,
|
||||
MediaType::SourceMap => 14,
|
||||
MediaType::Unknown => 15,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DenoRtDeserializable<'a> for MediaType {
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)> {
|
||||
let (input, value) = read_u8(input)?;
|
||||
let value = match value {
|
||||
0 => MediaType::JavaScript,
|
||||
1 => MediaType::Jsx,
|
||||
2 => MediaType::Mjs,
|
||||
3 => MediaType::Cjs,
|
||||
4 => MediaType::TypeScript,
|
||||
5 => MediaType::Mts,
|
||||
6 => MediaType::Cts,
|
||||
7 => MediaType::Dts,
|
||||
8 => MediaType::Dmts,
|
||||
9 => MediaType::Dcts,
|
||||
10 => MediaType::Tsx,
|
||||
11 => MediaType::Json,
|
||||
12 => MediaType::Wasm,
|
||||
13 => MediaType::Css,
|
||||
14 => MediaType::SourceMap,
|
||||
15 => MediaType::Unknown,
|
||||
value => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!("Unknown media type value: {value}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok((input, value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Data stored keyed by specifier.
|
||||
pub struct SpecifierDataStore<TData> {
|
||||
data: IndexMap<SpecifierId, TData>,
|
||||
}
|
||||
|
||||
impl<TData> Default for SpecifierDataStore<TData> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
data: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData> SpecifierDataStore<TData> {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
data: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (SpecifierId, &TData)> {
|
||||
self.data.iter().map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn contains(&self, specifier: SpecifierId) -> bool {
|
||||
self.data.contains_key(&specifier)
|
||||
}
|
||||
|
||||
pub fn add(&mut self, specifier: SpecifierId, value: TData) {
|
||||
self.data.insert(specifier, value);
|
||||
}
|
||||
|
||||
pub fn get(&self, specifier: SpecifierId) -> Option<&TData> {
|
||||
self.data.get(&specifier)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, TData> SpecifierDataStore<TData>
|
||||
where
|
||||
TData: DenoRtSerializable<'a> + 'a,
|
||||
{
|
||||
pub fn serialize(
|
||||
&'a self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, Vec<u8>>,
|
||||
) {
|
||||
builder.append_le(self.len() as u32);
|
||||
for (specifier, value) in self.iter() {
|
||||
builder.append(specifier);
|
||||
value.serialize(builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, TData> DenoRtDeserializable<'a> for SpecifierDataStore<TData>
|
||||
where
|
||||
TData: DenoRtDeserializable<'a>,
|
||||
{
|
||||
fn deserialize(input: &'a [u8]) -> std::io::Result<(&'a [u8], Self)> {
|
||||
let (input, len) = read_u32_as_usize(input)?;
|
||||
let mut data = IndexMap::with_capacity(len);
|
||||
let mut input = input;
|
||||
for _ in 0..len {
|
||||
let (new_input, specifier) = SpecifierId::deserialize(input)?;
|
||||
let (new_input, value) = TData::deserialize(new_input)?;
|
||||
data.insert(specifier, value);
|
||||
input = new_input;
|
||||
}
|
||||
Ok((input, Self { data }))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_bytes_with_u32_len(input: &[u8]) -> std::io::Result<(&[u8], &[u8])> {
|
||||
let (input, len) = read_u32_as_usize(input)?;
|
||||
let (input, data) = read_bytes(input, len)?;
|
||||
Ok((input, data))
|
||||
}
|
||||
|
||||
fn read_u32_as_usize(input: &[u8]) -> std::io::Result<(&[u8], usize)> {
|
||||
read_u32(input).map(|(input, len)| (input, len as usize))
|
||||
}
|
||||
|
||||
fn read_u32(input: &[u8]) -> std::io::Result<(&[u8], u32)> {
|
||||
let (input, len_bytes) = read_bytes(input, 4)?;
|
||||
let len = u32::from_le_bytes(len_bytes.try_into().unwrap());
|
||||
Ok((input, len))
|
||||
}
|
||||
|
||||
fn read_u8(input: &[u8]) -> std::io::Result<(&[u8], u8)> {
|
||||
check_has_len(input, 1)?;
|
||||
Ok((&input[1..], input[0]))
|
||||
}
|
||||
|
||||
fn read_bytes(input: &[u8], len: usize) -> std::io::Result<(&[u8], &[u8])> {
|
||||
check_has_len(input, len)?;
|
||||
let (len_bytes, input) = input.split_at(len);
|
||||
Ok((input, len_bytes))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_has_len(input: &[u8], len: usize) -> std::io::Result<()> {
|
||||
if input.len() < len {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"Unexpected end of data",
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub mod binary;
|
||||
pub mod virtual_fs;
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::strip_unc_prefix;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_core::anyhow::bail;
|
||||
use deno_runtime::deno_core::anyhow::Context;
|
||||
use deno_runtime::deno_core::error::AnyError;
|
||||
use indexmap::IndexSet;
|
||||
use serde::de;
|
||||
use serde::de::SeqAccess;
|
||||
use serde::de::Visitor;
|
||||
use serde::Deserialize;
|
||||
use serde::Deserializer;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum VfsFileSubDataKind {
|
||||
/// Raw bytes of the file.
|
||||
Raw,
|
||||
/// Bytes to use for module loading. For example, for TypeScript
|
||||
/// files this will be the transpiled JavaScript source.
|
||||
ModuleGraph,
|
||||
}
|
||||
use serde::Serializer;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum WindowsSystemRootablePath {
|
||||
|
@ -24,6 +31,14 @@ pub enum WindowsSystemRootablePath {
|
|||
}
|
||||
|
||||
impl WindowsSystemRootablePath {
|
||||
pub fn root_for_current_os() -> Self {
|
||||
if cfg!(windows) {
|
||||
WindowsSystemRootablePath::WindowSystemRoot
|
||||
} else {
|
||||
WindowsSystemRootablePath::Path(PathBuf::from("/"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(&self, name_component: &str) -> PathBuf {
|
||||
// this method doesn't handle multiple components
|
||||
debug_assert!(
|
||||
|
@ -110,6 +125,10 @@ impl VirtualDirectoryEntries {
|
|||
self.0.get_mut(index)
|
||||
}
|
||||
|
||||
pub fn get_by_index(&self, index: usize) -> Option<&VfsEntry> {
|
||||
self.0.get(index)
|
||||
}
|
||||
|
||||
pub fn binary_search(
|
||||
&self,
|
||||
name: &str,
|
||||
|
@ -180,27 +199,67 @@ pub struct VirtualDirectory {
|
|||
pub entries: VirtualDirectoryEntries,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OffsetWithLength {
|
||||
#[serde(rename = "o")]
|
||||
pub offset: u64,
|
||||
#[serde(rename = "l")]
|
||||
pub len: u64,
|
||||
}
|
||||
|
||||
// serialize as an array in order to save space
|
||||
impl Serialize for OffsetWithLength {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let array = [self.offset, self.len];
|
||||
array.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for OffsetWithLength {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct OffsetWithLengthVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for OffsetWithLengthVisitor {
|
||||
type Value = OffsetWithLength;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("an array with two elements: [offset, len]")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let offset = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||
let len = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||
Ok(OffsetWithLength { offset, len })
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(OffsetWithLengthVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VirtualFile {
|
||||
#[serde(rename = "n")]
|
||||
pub name: String,
|
||||
#[serde(rename = "o")]
|
||||
pub offset: OffsetWithLength,
|
||||
/// Offset file to use for module loading when it differs from the
|
||||
/// raw file. Often this will be the same offset as above for data
|
||||
/// such as JavaScript files, but for TypeScript files the `offset`
|
||||
/// will be the original raw bytes when included as an asset and this
|
||||
/// offset will be to the transpiled JavaScript source.
|
||||
#[serde(rename = "m")]
|
||||
pub module_graph_offset: OffsetWithLength,
|
||||
#[serde(rename = "m", skip_serializing_if = "Option::is_none")]
|
||||
pub transpiled_offset: Option<OffsetWithLength>,
|
||||
#[serde(rename = "c", skip_serializing_if = "Option::is_none")]
|
||||
pub cjs_export_analysis_offset: Option<OffsetWithLength>,
|
||||
#[serde(rename = "s", skip_serializing_if = "Option::is_none")]
|
||||
pub source_map_offset: Option<OffsetWithLength>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
@ -294,3 +353,647 @@ impl VfsEntry {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME: &str =
|
||||
".deno_compile_node_modules";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BuiltVfs {
|
||||
pub root_path: WindowsSystemRootablePath,
|
||||
pub case_sensitivity: FileSystemCaseSensitivity,
|
||||
pub entries: VirtualDirectoryEntries,
|
||||
pub files: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FilesData {
|
||||
files: Vec<Vec<u8>>,
|
||||
current_offset: u64,
|
||||
file_offsets: HashMap<(String, usize), OffsetWithLength>,
|
||||
}
|
||||
|
||||
impl FilesData {
|
||||
pub fn file_bytes(&self, offset: OffsetWithLength) -> Option<&[u8]> {
|
||||
if offset.len == 0 {
|
||||
return Some(&[]);
|
||||
}
|
||||
|
||||
// the debug assertions in this method should never happen
|
||||
// because it would indicate providing an offset not in the vfs
|
||||
let mut count: u64 = 0;
|
||||
for file in &self.files {
|
||||
// clippy wanted a match
|
||||
match count.cmp(&offset.offset) {
|
||||
Ordering::Equal => {
|
||||
debug_assert_eq!(offset.len, file.len() as u64);
|
||||
if offset.len == file.len() as u64 {
|
||||
return Some(file);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Ordering::Less => {
|
||||
count += file.len() as u64;
|
||||
}
|
||||
Ordering::Greater => {
|
||||
debug_assert!(false);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug_assert!(false);
|
||||
None
|
||||
}
|
||||
|
||||
pub fn add_data(&mut self, data: Vec<u8>) -> OffsetWithLength {
|
||||
if data.is_empty() {
|
||||
return OffsetWithLength { offset: 0, len: 0 };
|
||||
}
|
||||
let checksum = crate::util::checksum::gen(&[&data]);
|
||||
match self.file_offsets.entry((checksum, data.len())) {
|
||||
Entry::Occupied(occupied_entry) => {
|
||||
let offset_and_len = *occupied_entry.get();
|
||||
debug_assert_eq!(data.len() as u64, offset_and_len.len);
|
||||
offset_and_len
|
||||
}
|
||||
Entry::Vacant(vacant_entry) => {
|
||||
let offset_and_len = OffsetWithLength {
|
||||
offset: self.current_offset,
|
||||
len: data.len() as u64,
|
||||
};
|
||||
vacant_entry.insert(offset_and_len);
|
||||
self.current_offset += offset_and_len.len;
|
||||
self.files.push(data);
|
||||
offset_and_len
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddFileDataOptions {
|
||||
pub data: Vec<u8>,
|
||||
pub maybe_transpiled: Option<Vec<u8>>,
|
||||
pub maybe_source_map: Option<Vec<u8>>,
|
||||
pub maybe_cjs_export_analysis: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VfsBuilder {
|
||||
executable_root: VirtualDirectory,
|
||||
files: FilesData,
|
||||
/// The minimum root directory that should be included in the VFS.
|
||||
min_root_dir: Option<WindowsSystemRootablePath>,
|
||||
case_sensitivity: FileSystemCaseSensitivity,
|
||||
}
|
||||
|
||||
impl Default for VfsBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl VfsBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
executable_root: VirtualDirectory {
|
||||
name: "/".to_string(),
|
||||
entries: Default::default(),
|
||||
},
|
||||
files: Default::default(),
|
||||
min_root_dir: Default::default(),
|
||||
// This is not exactly correct because file systems on these OSes
|
||||
// may be case-sensitive or not based on the directory, but this
|
||||
// is a good enough approximation and limitation. In the future,
|
||||
// we may want to store this information per directory instead
|
||||
// depending on the feedback we get.
|
||||
case_sensitivity: if cfg!(windows) || cfg!(target_os = "macos") {
|
||||
FileSystemCaseSensitivity::Insensitive
|
||||
} else {
|
||||
FileSystemCaseSensitivity::Sensitive
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn case_sensitivity(&self) -> FileSystemCaseSensitivity {
|
||||
self.case_sensitivity
|
||||
}
|
||||
|
||||
pub fn files_len(&self) -> usize {
|
||||
self.files.files.len()
|
||||
}
|
||||
|
||||
pub fn file_bytes(&self, offset: OffsetWithLength) -> Option<&[u8]> {
|
||||
self.files.file_bytes(offset)
|
||||
}
|
||||
|
||||
/// Add a directory that might be the minimum root directory
|
||||
/// of the VFS.
|
||||
///
|
||||
/// For example, say the user has a deno.json and specifies an
|
||||
/// import map in a parent directory. The import map won't be
|
||||
/// included in the VFS, but its base will meaning we need to
|
||||
/// tell the VFS builder to include the base of the import map
|
||||
/// by calling this method.
|
||||
pub fn add_possible_min_root_dir(&mut self, path: &Path) {
|
||||
self.add_dir_raw(path);
|
||||
|
||||
match &self.min_root_dir {
|
||||
Some(WindowsSystemRootablePath::WindowSystemRoot) => {
|
||||
// already the root dir
|
||||
}
|
||||
Some(WindowsSystemRootablePath::Path(current_path)) => {
|
||||
let mut common_components = Vec::new();
|
||||
for (a, b) in current_path.components().zip(path.components()) {
|
||||
if a != b {
|
||||
break;
|
||||
}
|
||||
common_components.push(a);
|
||||
}
|
||||
if common_components.is_empty() {
|
||||
self.min_root_dir =
|
||||
Some(WindowsSystemRootablePath::root_for_current_os());
|
||||
} else {
|
||||
self.min_root_dir = Some(WindowsSystemRootablePath::Path(
|
||||
common_components.iter().collect(),
|
||||
));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.min_root_dir =
|
||||
Some(WindowsSystemRootablePath::Path(path.to_path_buf()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_dir_recursive(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
let target_path = self.resolve_target_path(path)?;
|
||||
self.add_dir_recursive_not_symlink(&target_path)
|
||||
}
|
||||
|
||||
fn add_dir_recursive_not_symlink(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
self.add_dir_raw(path);
|
||||
// ok, building fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let read_dir = std::fs::read_dir(path)
|
||||
.with_context(|| format!("Reading {}", path.display()))?;
|
||||
|
||||
let mut dir_entries =
|
||||
read_dir.into_iter().collect::<Result<Vec<_>, _>>()?;
|
||||
dir_entries.sort_by_cached_key(|entry| entry.file_name()); // determinism
|
||||
|
||||
for entry in dir_entries {
|
||||
let file_type = entry.file_type()?;
|
||||
let path = entry.path();
|
||||
|
||||
if file_type.is_dir() {
|
||||
self.add_dir_recursive_not_symlink(&path)?;
|
||||
} else if file_type.is_file() {
|
||||
self.add_file_at_path_not_symlink(&path)?;
|
||||
} else if file_type.is_symlink() {
|
||||
match self.add_symlink(&path) {
|
||||
Ok(target) => match target {
|
||||
SymlinkTarget::File(target) => {
|
||||
self.add_file_at_path_not_symlink(&target)?
|
||||
}
|
||||
SymlinkTarget::Dir(target) => {
|
||||
self.add_dir_recursive_not_symlink(&target)?;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
"{} Failed resolving symlink. Ignoring.\n Path: {}\n Message: {:#}",
|
||||
colors::yellow("Warning"),
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_dir_raw(&mut self, path: &Path) -> &mut VirtualDirectory {
|
||||
log::debug!("Ensuring directory '{}'", path.display());
|
||||
debug_assert!(path.is_absolute());
|
||||
let mut current_dir = &mut self.executable_root;
|
||||
|
||||
for component in path.components() {
|
||||
if matches!(component, std::path::Component::RootDir) {
|
||||
continue;
|
||||
}
|
||||
let name = component.as_os_str().to_string_lossy();
|
||||
let index = current_dir.entries.insert_or_modify(
|
||||
&name,
|
||||
self.case_sensitivity,
|
||||
|| {
|
||||
VfsEntry::Dir(VirtualDirectory {
|
||||
name: name.to_string(),
|
||||
entries: Default::default(),
|
||||
})
|
||||
},
|
||||
|_| {
|
||||
// ignore
|
||||
},
|
||||
);
|
||||
match current_dir.entries.get_mut_by_index(index) {
|
||||
Some(VfsEntry::Dir(dir)) => {
|
||||
current_dir = dir;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
current_dir
|
||||
}
|
||||
|
||||
pub fn get_system_root_dir_mut(&mut self) -> &mut VirtualDirectory {
|
||||
&mut self.executable_root
|
||||
}
|
||||
|
||||
pub fn get_dir_mut(&mut self, path: &Path) -> Option<&mut VirtualDirectory> {
|
||||
debug_assert!(path.is_absolute());
|
||||
let mut current_dir = &mut self.executable_root;
|
||||
|
||||
for component in path.components() {
|
||||
if matches!(component, std::path::Component::RootDir) {
|
||||
continue;
|
||||
}
|
||||
let name = component.as_os_str().to_string_lossy();
|
||||
let entry = current_dir
|
||||
.entries
|
||||
.get_mut_by_name(&name, self.case_sensitivity)?;
|
||||
match entry {
|
||||
VfsEntry::Dir(dir) => {
|
||||
current_dir = dir;
|
||||
}
|
||||
_ => unreachable!("{}", path.display()),
|
||||
};
|
||||
}
|
||||
|
||||
Some(current_dir)
|
||||
}
|
||||
|
||||
pub fn add_file_at_path(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
// ok, building fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let file_bytes = std::fs::read(path)
|
||||
.with_context(|| format!("Reading {}", path.display()))?;
|
||||
self.add_file_with_data(
|
||||
path,
|
||||
AddFileDataOptions {
|
||||
data: file_bytes,
|
||||
maybe_cjs_export_analysis: None,
|
||||
maybe_transpiled: None,
|
||||
maybe_source_map: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn add_file_at_path_not_symlink(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
// ok, building fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let file_bytes = std::fs::read(path)
|
||||
.with_context(|| format!("Reading {}", path.display()))?;
|
||||
self.add_file_with_data_raw(path, file_bytes)
|
||||
}
|
||||
|
||||
pub fn add_file_with_data(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
options: AddFileDataOptions,
|
||||
) -> Result<(), AnyError> {
|
||||
// ok, fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let metadata = std::fs::symlink_metadata(path).with_context(|| {
|
||||
format!("Resolving target path for '{}'", path.display())
|
||||
})?;
|
||||
if metadata.is_symlink() {
|
||||
let target = self.add_symlink(path)?.into_path_buf();
|
||||
self.add_file_with_data_raw_options(&target, options)
|
||||
} else {
|
||||
self.add_file_with_data_raw_options(path, options)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_file_with_data_raw(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), AnyError> {
|
||||
self.add_file_with_data_raw_options(
|
||||
path,
|
||||
AddFileDataOptions {
|
||||
data,
|
||||
maybe_transpiled: None,
|
||||
maybe_cjs_export_analysis: None,
|
||||
maybe_source_map: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn add_file_with_data_raw_options(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
options: AddFileDataOptions,
|
||||
) -> Result<(), AnyError> {
|
||||
log::debug!("Adding file '{}'", path.display());
|
||||
let case_sensitivity = self.case_sensitivity;
|
||||
|
||||
let offset_and_len = self.files.add_data(options.data);
|
||||
let transpiled_offset = options
|
||||
.maybe_transpiled
|
||||
.map(|data| self.files.add_data(data));
|
||||
let source_map_offset = options
|
||||
.maybe_source_map
|
||||
.map(|data| self.files.add_data(data));
|
||||
let cjs_export_analysis_offset = options
|
||||
.maybe_cjs_export_analysis
|
||||
.map(|data| self.files.add_data(data));
|
||||
let dir = self.add_dir_raw(path.parent().unwrap());
|
||||
let name = path.file_name().unwrap().to_string_lossy();
|
||||
|
||||
dir.entries.insert_or_modify(
|
||||
&name,
|
||||
case_sensitivity,
|
||||
|| {
|
||||
VfsEntry::File(VirtualFile {
|
||||
name: name.to_string(),
|
||||
offset: offset_and_len,
|
||||
transpiled_offset,
|
||||
cjs_export_analysis_offset,
|
||||
source_map_offset,
|
||||
})
|
||||
},
|
||||
|entry| match entry {
|
||||
VfsEntry::File(virtual_file) => {
|
||||
virtual_file.offset = offset_and_len;
|
||||
// doesn't overwrite to None
|
||||
if transpiled_offset.is_some() {
|
||||
virtual_file.transpiled_offset = transpiled_offset;
|
||||
}
|
||||
if source_map_offset.is_some() {
|
||||
virtual_file.source_map_offset = source_map_offset;
|
||||
}
|
||||
if cjs_export_analysis_offset.is_some() {
|
||||
virtual_file.cjs_export_analysis_offset =
|
||||
cjs_export_analysis_offset;
|
||||
}
|
||||
}
|
||||
VfsEntry::Dir(_) | VfsEntry::Symlink(_) => unreachable!(),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_target_path(&mut self, path: &Path) -> Result<PathBuf, AnyError> {
|
||||
// ok, fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let metadata = std::fs::symlink_metadata(path).with_context(|| {
|
||||
format!("Resolving target path for '{}'", path.display())
|
||||
})?;
|
||||
if metadata.is_symlink() {
|
||||
Ok(self.add_symlink(path)?.into_path_buf())
|
||||
} else {
|
||||
Ok(path.to_path_buf())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_symlink(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> Result<SymlinkTarget, AnyError> {
|
||||
self.add_symlink_inner(path, &mut IndexSet::new())
|
||||
}
|
||||
|
||||
fn add_symlink_inner(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
visited: &mut IndexSet<PathBuf>,
|
||||
) -> Result<SymlinkTarget, AnyError> {
|
||||
log::debug!("Adding symlink '{}'", path.display());
|
||||
let target = strip_unc_prefix(
|
||||
// ok, fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
std::fs::read_link(path)
|
||||
.with_context(|| format!("Reading symlink '{}'", path.display()))?,
|
||||
);
|
||||
let case_sensitivity = self.case_sensitivity;
|
||||
let target = normalize_path(path.parent().unwrap().join(&target));
|
||||
let dir = self.add_dir_raw(path.parent().unwrap());
|
||||
let name = path.file_name().unwrap().to_string_lossy();
|
||||
dir.entries.insert_or_modify(
|
||||
&name,
|
||||
case_sensitivity,
|
||||
|| {
|
||||
VfsEntry::Symlink(VirtualSymlink {
|
||||
name: name.to_string(),
|
||||
dest_parts: VirtualSymlinkParts::from_path(&target),
|
||||
})
|
||||
},
|
||||
|_| {
|
||||
// ignore previously inserted
|
||||
},
|
||||
);
|
||||
// ok, fs implementation
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let target_metadata =
|
||||
std::fs::symlink_metadata(&target).with_context(|| {
|
||||
format!("Reading symlink target '{}'", target.display())
|
||||
})?;
|
||||
if target_metadata.is_symlink() {
|
||||
if !visited.insert(target.clone()) {
|
||||
// todo: probably don't error in this scenario
|
||||
bail!(
|
||||
"Circular symlink detected: {} -> {}",
|
||||
visited
|
||||
.iter()
|
||||
.map(|p| p.display().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" -> "),
|
||||
target.display()
|
||||
);
|
||||
}
|
||||
self.add_symlink_inner(&target, visited)
|
||||
} else if target_metadata.is_dir() {
|
||||
Ok(SymlinkTarget::Dir(target))
|
||||
} else {
|
||||
Ok(SymlinkTarget::File(target))
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the CJS export analysis to the provided file.
|
||||
///
|
||||
/// Warning: This will panic if the file wasn't properly
|
||||
/// setup before calling this.
|
||||
pub fn add_cjs_export_analysis(&mut self, path: &Path, data: Vec<u8>) {
|
||||
self.add_data_for_file_or_panic(path, data, |file, offset_with_length| {
|
||||
file.cjs_export_analysis_offset = Some(offset_with_length);
|
||||
})
|
||||
}
|
||||
|
||||
fn add_data_for_file_or_panic(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
data: Vec<u8>,
|
||||
update_file: impl FnOnce(&mut VirtualFile, OffsetWithLength),
|
||||
) {
|
||||
let offset_with_length = self.files.add_data(data);
|
||||
let case_sensitivity = self.case_sensitivity;
|
||||
let dir = self.get_dir_mut(path.parent().unwrap()).unwrap();
|
||||
let name = path.file_name().unwrap().to_string_lossy();
|
||||
let file = dir
|
||||
.entries
|
||||
.get_mut_by_name(&name, case_sensitivity)
|
||||
.unwrap();
|
||||
match file {
|
||||
VfsEntry::File(virtual_file) => {
|
||||
update_file(virtual_file, offset_with_length);
|
||||
}
|
||||
VfsEntry::Dir(_) | VfsEntry::Symlink(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates through all the files in the virtual file system.
|
||||
pub fn iter_files(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (PathBuf, &VirtualFile)> + '_ {
|
||||
FileIterator {
|
||||
pending_dirs: VecDeque::from([(
|
||||
WindowsSystemRootablePath::root_for_current_os(),
|
||||
&self.executable_root,
|
||||
)]),
|
||||
current_dir_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> BuiltVfs {
|
||||
fn strip_prefix_from_symlinks(
|
||||
dir: &mut VirtualDirectory,
|
||||
parts: &[String],
|
||||
) {
|
||||
for entry in dir.entries.iter_mut() {
|
||||
match entry {
|
||||
VfsEntry::Dir(dir) => {
|
||||
strip_prefix_from_symlinks(dir, parts);
|
||||
}
|
||||
VfsEntry::File(_) => {}
|
||||
VfsEntry::Symlink(symlink) => {
|
||||
let parts = symlink
|
||||
.dest_parts
|
||||
.take_parts()
|
||||
.into_iter()
|
||||
.skip(parts.len())
|
||||
.collect();
|
||||
symlink.dest_parts.set_parts(parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_dir = self.executable_root;
|
||||
let mut current_path = WindowsSystemRootablePath::root_for_current_os();
|
||||
loop {
|
||||
if current_dir.entries.len() != 1 {
|
||||
break;
|
||||
}
|
||||
if self.min_root_dir.as_ref() == Some(¤t_path) {
|
||||
break;
|
||||
}
|
||||
match current_dir.entries.iter().next().unwrap() {
|
||||
VfsEntry::Dir(dir) => {
|
||||
if dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME {
|
||||
// special directory we want to maintain
|
||||
break;
|
||||
}
|
||||
match current_dir.entries.remove(0) {
|
||||
VfsEntry::Dir(dir) => {
|
||||
current_path =
|
||||
WindowsSystemRootablePath::Path(current_path.join(&dir.name));
|
||||
current_dir = dir;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
VfsEntry::File(_) | VfsEntry::Symlink(_) => break,
|
||||
}
|
||||
}
|
||||
if let WindowsSystemRootablePath::Path(path) = ¤t_path {
|
||||
strip_prefix_from_symlinks(
|
||||
&mut current_dir,
|
||||
VirtualSymlinkParts::from_path(path).parts(),
|
||||
);
|
||||
}
|
||||
BuiltVfs {
|
||||
root_path: current_path,
|
||||
case_sensitivity: self.case_sensitivity,
|
||||
entries: current_dir.entries,
|
||||
files: self.files.files,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FileIterator<'a> {
|
||||
pending_dirs: VecDeque<(WindowsSystemRootablePath, &'a VirtualDirectory)>,
|
||||
current_dir_index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FileIterator<'a> {
|
||||
type Item = (PathBuf, &'a VirtualFile);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while !self.pending_dirs.is_empty() {
|
||||
let (dir_path, current_dir) = self.pending_dirs.front()?;
|
||||
if let Some(entry) =
|
||||
current_dir.entries.get_by_index(self.current_dir_index)
|
||||
{
|
||||
self.current_dir_index += 1;
|
||||
match entry {
|
||||
VfsEntry::Dir(virtual_directory) => {
|
||||
self.pending_dirs.push_back((
|
||||
WindowsSystemRootablePath::Path(
|
||||
dir_path.join(&virtual_directory.name),
|
||||
),
|
||||
virtual_directory,
|
||||
));
|
||||
}
|
||||
VfsEntry::File(virtual_file) => {
|
||||
return Some((dir_path.join(&virtual_file.name), virtual_file));
|
||||
}
|
||||
VfsEntry::Symlink(_) => {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.pending_dirs.pop_front();
|
||||
self.current_dir_index = 0;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymlinkTarget {
|
||||
File(PathBuf),
|
||||
Dir(PathBuf),
|
||||
}
|
||||
|
||||
impl SymlinkTarget {
|
||||
pub fn into_path_buf(self) -> PathBuf {
|
||||
match self {
|
||||
Self::File(path) => path,
|
||||
Self::Dir(path) => path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,44 +2,33 @@
|
|||
|
||||
use std::io::Write;
|
||||
|
||||
use deno_telemetry::OtelConfig;
|
||||
use deno_telemetry::OtelConsoleConfig;
|
||||
use deno_runtime::deno_telemetry;
|
||||
use deno_runtime::deno_telemetry::OtelConfig;
|
||||
use deno_runtime::deno_telemetry::OtelConsoleConfig;
|
||||
|
||||
use super::draw_thread::DrawThread;
|
||||
|
||||
struct CliLogger {
|
||||
struct CliLogger<FnOnLogStart: Fn(), FnOnLogEnd: Fn()> {
|
||||
otel_console_config: OtelConsoleConfig,
|
||||
logger: env_logger::Logger,
|
||||
on_log_start: FnOnLogStart,
|
||||
on_log_end: FnOnLogEnd,
|
||||
}
|
||||
|
||||
impl CliLogger {
|
||||
pub fn new(
|
||||
logger: env_logger::Logger,
|
||||
otel_console_config: OtelConsoleConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
logger,
|
||||
otel_console_config,
|
||||
}
|
||||
}
|
||||
|
||||
impl<FnOnLogStart: Fn(), FnOnLogEnd: Fn()> CliLogger<FnOnLogStart, FnOnLogEnd> {
|
||||
pub fn filter(&self) -> log::LevelFilter {
|
||||
self.logger.filter()
|
||||
}
|
||||
}
|
||||
|
||||
impl log::Log for CliLogger {
|
||||
impl<FnOnLogStart: Fn() + Send + Sync, FnOnLogEnd: Fn() + Send + Sync> log::Log
|
||||
for CliLogger<FnOnLogStart, FnOnLogEnd>
|
||||
{
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
self.logger.enabled(metadata)
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
// it was considered to hold the draw thread's internal lock
|
||||
// across logging, but if outputting to stderr blocks then that
|
||||
// could potentially block other threads that access the draw
|
||||
// thread's state
|
||||
DrawThread::hide();
|
||||
(self.on_log_start)();
|
||||
|
||||
match self.otel_console_config {
|
||||
OtelConsoleConfig::Ignore => {
|
||||
|
@ -54,7 +43,7 @@ impl log::Log for CliLogger {
|
|||
}
|
||||
}
|
||||
|
||||
DrawThread::show();
|
||||
(self.on_log_end)();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,8 +52,20 @@ impl log::Log for CliLogger {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn init(maybe_level: Option<log::Level>, otel_config: Option<OtelConfig>) {
|
||||
let log_level = maybe_level.unwrap_or(log::Level::Info);
|
||||
pub struct InitLoggingOptions<FnOnLogStart: Fn(), FnOnLogEnd: Fn()> {
|
||||
pub on_log_start: FnOnLogStart,
|
||||
pub on_log_end: FnOnLogEnd,
|
||||
pub maybe_level: Option<log::Level>,
|
||||
pub otel_config: Option<OtelConfig>,
|
||||
}
|
||||
|
||||
pub fn init<
|
||||
FOnLogStart: Fn() + Send + Sync + 'static,
|
||||
FnOnLogEnd: Fn() + Send + Sync + 'static,
|
||||
>(
|
||||
options: InitLoggingOptions<FOnLogStart, FnOnLogEnd>,
|
||||
) {
|
||||
let log_level = options.maybe_level.unwrap_or(log::Level::Info);
|
||||
let logger = env_logger::Builder::from_env(
|
||||
env_logger::Env::new()
|
||||
// Use `DENO_LOG` and `DENO_LOG_STYLE` instead of `RUST_` prefix
|
||||
|
@ -117,12 +118,15 @@ pub fn init(maybe_level: Option<log::Level>, otel_config: Option<OtelConfig>) {
|
|||
})
|
||||
.build();
|
||||
|
||||
let cli_logger = CliLogger::new(
|
||||
let cli_logger = CliLogger {
|
||||
on_log_start: options.on_log_start,
|
||||
on_log_end: options.on_log_end,
|
||||
logger,
|
||||
otel_config
|
||||
otel_console_config: options
|
||||
.otel_config
|
||||
.map(|c| c.console)
|
||||
.unwrap_or(OtelConsoleConfig::Ignore),
|
||||
);
|
||||
};
|
||||
let max_level = cli_logger.filter();
|
||||
let r = log::set_boxed_logger(Box::new(cli_logger));
|
||||
if r.is_ok() {
|
|
@ -1,3 +1,8 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub mod checksum;
|
||||
pub mod hash;
|
||||
pub mod logger;
|
||||
pub mod result;
|
||||
pub mod text_encoding;
|
||||
pub mod v8;
|
||||
|
|
|
@ -4,10 +4,10 @@ use std::convert::Infallible;
|
|||
use std::fmt::Debug;
|
||||
use std::fmt::Display;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::CoreError;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_error::JsErrorClass;
|
||||
use deno_runtime::deno_core::error::AnyError;
|
||||
use deno_runtime::deno_core::error::CoreError;
|
||||
|
||||
pub trait InfallibleResultExt<T> {
|
||||
fn unwrap_infallible(self) -> T;
|
45
cli/lib/util/text_encoding.rs
Normal file
45
cli/lib/util/text_encoding.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_utf8_lossy_owned(bytes: Vec<u8>) -> String {
|
||||
match String::from_utf8_lossy(&bytes) {
|
||||
Cow::Owned(code) => code,
|
||||
// SAFETY: `String::from_utf8_lossy` guarantees that the result is valid
|
||||
// UTF-8 if `Cow::Borrowed` is returned.
|
||||
Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(bytes) },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_utf8_lossy_cow(bytes: Cow<[u8]>) -> Cow<str> {
|
||||
match bytes {
|
||||
Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes),
|
||||
Cow::Owned(bytes) => Cow::Owned(from_utf8_lossy_owned(bytes)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an `Arc<str>` to an `Arc<[u8]>`.
|
||||
#[allow(dead_code)]
|
||||
pub fn arc_str_to_bytes(arc_str: Arc<str>) -> Arc<[u8]> {
|
||||
let raw = Arc::into_raw(arc_str);
|
||||
// SAFETY: This is safe because they have the same memory layout.
|
||||
unsafe { Arc::from_raw(raw as *const [u8]) }
|
||||
}
|
||||
|
||||
/// Converts an `Arc<u8>` to an `Arc<str>` if able.
|
||||
#[allow(dead_code)]
|
||||
pub fn arc_u8_to_arc_str(
|
||||
arc_u8: Arc<[u8]>,
|
||||
) -> Result<Arc<str>, std::str::Utf8Error> {
|
||||
// Check that the string is valid UTF-8.
|
||||
std::str::from_utf8(&arc_u8)?;
|
||||
// SAFETY: the string is valid UTF-8, and the layout Arc<[u8]> is the same as
|
||||
// Arc<str>. This is proven by the From<Arc<str>> impl for Arc<[u8]> from the
|
||||
// standard library.
|
||||
Ok(unsafe {
|
||||
std::mem::transmute::<std::sync::Arc<[u8]>, std::sync::Arc<str>>(arc_u8)
|
||||
})
|
||||
}
|
14
cli/lib/util/v8.rs
Normal file
14
cli/lib/util/v8.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
#[inline(always)]
|
||||
pub fn construct_v8_flags(
|
||||
default_v8_flags: &[String],
|
||||
v8_flags: &[String],
|
||||
env_v8_flags: Vec<String>,
|
||||
) -> Vec<String> {
|
||||
std::iter::once("UNUSED_BUT_NECESSARY_ARG0".to_owned())
|
||||
.chain(default_v8_flags.iter().cloned())
|
||||
.chain(env_v8_flags)
|
||||
.chain(v8_flags.iter().cloned())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
94
cli/lib/version.rs
Normal file
94
cli/lib/version.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use deno_runtime::deno_telemetry::OtelRuntimeConfig;
|
||||
|
||||
use crate::shared::ReleaseChannel;
|
||||
|
||||
pub fn otel_runtime_config() -> OtelRuntimeConfig {
|
||||
OtelRuntimeConfig {
|
||||
runtime_name: Cow::Borrowed("deno"),
|
||||
runtime_version: Cow::Borrowed(crate::version::DENO_VERSION_INFO.deno),
|
||||
}
|
||||
}
|
||||
|
||||
const GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH");
|
||||
const TYPESCRIPT: &str = "5.6.2";
|
||||
const DENO_VERSION: &str = env!("DENO_VERSION");
|
||||
// TODO(bartlomieju): ideally we could remove this const.
|
||||
const IS_CANARY: bool = option_env!("DENO_CANARY").is_some();
|
||||
// TODO(bartlomieju): this is temporary, to allow Homebrew to cut RC releases as well
|
||||
const IS_RC: bool = option_env!("DENO_RC").is_some();
|
||||
|
||||
pub static DENO_VERSION_INFO: std::sync::LazyLock<DenoVersionInfo> =
|
||||
std::sync::LazyLock::new(|| {
|
||||
let release_channel = libsui::find_section("denover")
|
||||
.and_then(|buf| std::str::from_utf8(buf).ok())
|
||||
.and_then(|str_| ReleaseChannel::deserialize(str_).ok())
|
||||
.unwrap_or({
|
||||
if IS_CANARY {
|
||||
ReleaseChannel::Canary
|
||||
} else if IS_RC {
|
||||
ReleaseChannel::Rc
|
||||
} else {
|
||||
ReleaseChannel::Stable
|
||||
}
|
||||
});
|
||||
|
||||
DenoVersionInfo {
|
||||
deno: if release_channel == ReleaseChannel::Canary {
|
||||
concat!(env!("DENO_VERSION"), "+", env!("GIT_COMMIT_HASH_SHORT"))
|
||||
} else {
|
||||
env!("DENO_VERSION")
|
||||
},
|
||||
|
||||
release_channel,
|
||||
|
||||
git_hash: GIT_COMMIT_HASH,
|
||||
|
||||
// Keep in sync with `deno` field.
|
||||
user_agent: if release_channel == ReleaseChannel::Canary {
|
||||
concat!(
|
||||
"Deno/",
|
||||
env!("DENO_VERSION"),
|
||||
"+",
|
||||
env!("GIT_COMMIT_HASH_SHORT")
|
||||
)
|
||||
} else {
|
||||
concat!("Deno/", env!("DENO_VERSION"))
|
||||
},
|
||||
|
||||
typescript: TYPESCRIPT,
|
||||
}
|
||||
});
|
||||
|
||||
pub struct DenoVersionInfo {
|
||||
/// Human-readable version of the current Deno binary.
|
||||
///
|
||||
/// For stable release, a semver, eg. `v1.46.2`.
|
||||
/// For canary release, a semver + 7-char git hash, eg. `v1.46.3+asdfqwq`.
|
||||
pub deno: &'static str,
|
||||
|
||||
pub release_channel: ReleaseChannel,
|
||||
|
||||
/// A full git hash.
|
||||
pub git_hash: &'static str,
|
||||
|
||||
/// A user-agent header that will be used in HTTP client.
|
||||
pub user_agent: &'static str,
|
||||
|
||||
pub typescript: &'static str,
|
||||
}
|
||||
|
||||
impl DenoVersionInfo {
|
||||
/// For stable release, a semver like, eg. `v1.46.2`.
|
||||
/// For canary release a full git hash, eg. `9bdab6fb6b93eb43b1930f40987fa4997287f9c8`.
|
||||
pub fn version_or_git_hash(&self) -> &'static str {
|
||||
if self.release_channel == ReleaseChannel::Canary {
|
||||
self.git_hash
|
||||
} else {
|
||||
DENO_VERSION
|
||||
}
|
||||
}
|
||||
}
|
1
cli/lib/version.txt
Normal file
1
cli/lib/version.txt
Normal file
|
@ -0,0 +1 @@
|
|||
2.1.6
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
@ -42,9 +43,10 @@ use deno_runtime::BootstrapOptions;
|
|||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
|
||||
use node_resolver::errors::ResolvePkgJsonBinExportError;
|
||||
use url::Url;
|
||||
|
||||
use crate::env::has_trace_permissions_enabled;
|
||||
use crate::args::has_trace_permissions_enabled;
|
||||
use crate::sys::DenoLibSys;
|
||||
use crate::util::checksum;
|
||||
|
||||
|
@ -113,9 +115,9 @@ impl StorageKeyResolver {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): this should be moved to some other place, added to avoid string
|
||||
// duplication between worker setups and `deno info` output.
|
||||
pub fn get_cache_storage_dir() -> PathBuf {
|
||||
// ok because this won't ever be used by the js runtime
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
// Note: we currently use temp_dir() to avoid managing storage size.
|
||||
std::env::temp_dir().join("deno_cache")
|
||||
}
|
||||
|
@ -131,10 +133,31 @@ pub fn create_isolate_create_params() -> Option<v8::CreateParams> {
|
|||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum ResolveNpmBinaryEntrypointError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
ResolvePkgJsonBinExport(ResolvePkgJsonBinExportError),
|
||||
#[class(generic)]
|
||||
#[error("{original:#}\n\nFallback failed: {fallback:#}")]
|
||||
Fallback {
|
||||
fallback: ResolveNpmBinaryEntrypointFallbackError,
|
||||
original: ResolvePkgJsonBinExportError,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum ResolveNpmBinaryEntrypointFallbackError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
PackageSubpathResolve(node_resolver::errors::PackageSubpathResolveError),
|
||||
#[class(generic)]
|
||||
#[error("Cannot find module '{0}'")]
|
||||
ModuleNotFound(Url),
|
||||
}
|
||||
|
||||
pub struct LibMainWorkerOptions {
|
||||
pub argv: Vec<String>,
|
||||
pub deno_version: &'static str,
|
||||
pub deno_user_agent: &'static str,
|
||||
pub log_level: WorkerLogLevel,
|
||||
pub enable_op_summary_metrics: bool,
|
||||
pub enable_testing_features: bool,
|
||||
|
@ -263,7 +286,7 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
|
|||
main_module: args.main_module.clone(),
|
||||
worker_id: args.worker_id,
|
||||
bootstrap: BootstrapOptions {
|
||||
deno_version: shared.options.deno_version.to_string(),
|
||||
deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
|
||||
args: shared.options.argv.clone(),
|
||||
cpu_count: std::thread::available_parallelism()
|
||||
.map(|p| p.get())
|
||||
|
@ -278,7 +301,7 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
|
|||
is_stdout_tty: deno_terminal::is_stdout_tty(),
|
||||
is_stderr_tty: deno_terminal::is_stderr_tty(),
|
||||
unstable_features,
|
||||
user_agent: shared.options.deno_user_agent.to_string(),
|
||||
user_agent: crate::version::DENO_VERSION_INFO.user_agent.to_string(),
|
||||
inspect: shared.options.is_inspecting,
|
||||
has_node_modules_dir: shared.options.has_node_modules_dir,
|
||||
argv0: shared.options.argv0.clone(),
|
||||
|
@ -359,6 +382,21 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_main_worker(
|
||||
&self,
|
||||
mode: WorkerExecutionMode,
|
||||
permissions: PermissionsContainer,
|
||||
main_module: Url,
|
||||
) -> Result<LibMainWorker, CoreError> {
|
||||
self.create_custom_worker(
|
||||
mode,
|
||||
main_module,
|
||||
permissions,
|
||||
vec![],
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_custom_worker(
|
||||
&self,
|
||||
mode: WorkerExecutionMode,
|
||||
|
@ -420,7 +458,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
|
||||
let options = WorkerOptions {
|
||||
bootstrap: BootstrapOptions {
|
||||
deno_version: shared.options.deno_version.to_string(),
|
||||
deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
|
||||
args: shared.options.argv.clone(),
|
||||
cpu_count: std::thread::available_parallelism()
|
||||
.map(|p| p.get())
|
||||
|
@ -435,7 +473,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
is_stderr_tty: deno_terminal::is_stderr_tty(),
|
||||
color_level: colors::get_color_level(),
|
||||
unstable_features,
|
||||
user_agent: shared.options.deno_user_agent.to_string(),
|
||||
user_agent: crate::version::DENO_VERSION_INFO.user_agent.to_string(),
|
||||
inspect: shared.options.is_inspecting,
|
||||
has_node_modules_dir: shared.options.has_node_modules_dir,
|
||||
argv0: shared.options.argv0.clone(),
|
||||
|
@ -476,6 +514,76 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
worker,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_npm_binary_entrypoint(
|
||||
&self,
|
||||
package_folder: &Path,
|
||||
sub_path: Option<&str>,
|
||||
) -> Result<Url, ResolveNpmBinaryEntrypointError> {
|
||||
match self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve_binary_export(package_folder, sub_path)
|
||||
{
|
||||
Ok(specifier) => Ok(specifier),
|
||||
Err(original_err) => {
|
||||
// if the binary entrypoint was not found, fallback to regular node resolution
|
||||
let result =
|
||||
self.resolve_binary_entrypoint_fallback(package_folder, sub_path);
|
||||
match result {
|
||||
Ok(Some(specifier)) => Ok(specifier),
|
||||
Ok(None) => {
|
||||
Err(ResolveNpmBinaryEntrypointError::ResolvePkgJsonBinExport(
|
||||
original_err,
|
||||
))
|
||||
}
|
||||
Err(fallback_err) => Err(ResolveNpmBinaryEntrypointError::Fallback {
|
||||
original: original_err,
|
||||
fallback: fallback_err,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// resolve the binary entrypoint using regular node resolution
|
||||
fn resolve_binary_entrypoint_fallback(
|
||||
&self,
|
||||
package_folder: &Path,
|
||||
sub_path: Option<&str>,
|
||||
) -> Result<Option<Url>, ResolveNpmBinaryEntrypointFallbackError> {
|
||||
// only fallback if the user specified a sub path
|
||||
if sub_path.is_none() {
|
||||
// it's confusing to users if the package doesn't have any binary
|
||||
// entrypoint and we just execute the main script which will likely
|
||||
// have blank output, so do not resolve the entrypoint in this case
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let specifier = self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve_package_subpath_from_deno_module(
|
||||
package_folder,
|
||||
sub_path,
|
||||
/* referrer */ None,
|
||||
node_resolver::ResolutionMode::Import,
|
||||
node_resolver::NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(
|
||||
ResolveNpmBinaryEntrypointFallbackError::PackageSubpathResolve,
|
||||
)?;
|
||||
if deno_path_util::url_to_file_path(&specifier)
|
||||
.map(|p| self.shared.sys.fs_exists_no_err(p))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(Some(specifier))
|
||||
} else {
|
||||
Err(ResolveNpmBinaryEntrypointFallbackError::ModuleNotFound(
|
||||
specifier,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LibMainWorker {
|
||||
|
@ -536,6 +644,33 @@ impl LibMainWorker {
|
|||
self.worker.evaluate_module(id).await
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<i32, CoreError> {
|
||||
log::debug!("main_module {}", self.main_module);
|
||||
|
||||
self.execute_main_module().await?;
|
||||
self.worker.dispatch_load_event()?;
|
||||
|
||||
loop {
|
||||
self
|
||||
.worker
|
||||
.run_event_loop(/* wait for inspector */ false)
|
||||
.await?;
|
||||
|
||||
let web_continue = self.worker.dispatch_beforeunload_event()?;
|
||||
if !web_continue {
|
||||
let node_continue = self.worker.dispatch_process_beforeexit_event()?;
|
||||
if !node_continue {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.worker.dispatch_unload_event()?;
|
||||
self.worker.dispatch_process_exit_event()?;
|
||||
|
||||
Ok(self.worker.exit_code())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn run_event_loop(
|
||||
&mut self,
|
||||
|
|
|
@ -8,9 +8,9 @@ use std::time::SystemTime;
|
|||
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_lib::cache::DenoDir;
|
||||
use deno_path_util::url_to_file_path;
|
||||
|
||||
use crate::cache::DenoDir;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::cache::LocalLspHttpCache;
|
||||
|
@ -70,7 +70,7 @@ fn calculate_fs_version_in_cache(
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LspCache {
|
||||
deno_dir: DenoDir<CliSys>,
|
||||
deno_dir: DenoDir,
|
||||
global: Arc<GlobalHttpCache>,
|
||||
vendors_by_scope: BTreeMap<ModuleSpecifier, Option<Arc<LocalLspHttpCache>>>,
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ impl LspCache {
|
|||
.collect();
|
||||
}
|
||||
|
||||
pub fn deno_dir(&self) -> &DenoDir<CliSys> {
|
||||
pub fn deno_dir(&self) -> &DenoDir {
|
||||
&self.deno_dir
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ use deno_core::serde_json::json;
|
|||
use deno_core::serde_json::Value;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_lib::env::has_flag_env_var;
|
||||
use deno_lib::args::has_flag_env_var;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lint::linter::LintConfig as DenoLintConfig;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonCache;
|
||||
|
@ -61,7 +62,6 @@ use crate::args::CliLockfileReadFromPathOptions;
|
|||
use crate::args::ConfigFile;
|
||||
use crate::args::LintFlags;
|
||||
use crate::args::LintOptions;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
|
|
|
@ -265,7 +265,7 @@ impl TsDiagnosticsStore {
|
|||
}
|
||||
|
||||
pub fn should_send_diagnostic_batch_index_notifications() -> bool {
|
||||
deno_lib::env::has_flag_env_var(
|
||||
deno_lib::args::has_flag_env_var(
|
||||
"DENO_DONT_USE_INTERNAL_LSP_DIAGNOSTIC_SYNC_FLAG",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,10 @@ use deno_core::url::Url;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_graph::Resolution;
|
||||
use deno_lib::env::has_flag_env_var;
|
||||
use deno_lib::args::get_root_cert_store;
|
||||
use deno_lib::args::has_flag_env_var;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
|
@ -95,8 +98,6 @@ use super::urls;
|
|||
use super::urls::uri_to_url;
|
||||
use super::urls::url_to_uri;
|
||||
use crate::args::create_default_npmrc;
|
||||
use crate::args::get_root_cert_store;
|
||||
use crate::args::CaData;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
use crate::args::InternalFlags;
|
||||
|
@ -703,7 +704,7 @@ impl Inner {
|
|||
|
||||
let version = format!(
|
||||
"{} ({}, {})",
|
||||
crate::version::DENO_VERSION_INFO.deno,
|
||||
DENO_VERSION_INFO.deno,
|
||||
env!("PROFILE"),
|
||||
env!("TARGET")
|
||||
);
|
||||
|
|
|
@ -39,6 +39,7 @@ use deno_core::ModuleSpecifier;
|
|||
use deno_core::OpState;
|
||||
use deno_core::PollEventLoopOptions;
|
||||
use deno_core::RuntimeOptions;
|
||||
use deno_lib::util::result::InfallibleResultExt;
|
||||
use deno_lib::worker::create_isolate_create_params;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
|
@ -96,7 +97,6 @@ use crate::tsc::ResolveArgs;
|
|||
use crate::tsc::MISSING_DEPENDENCY_SPECIFIER;
|
||||
use crate::util::path::relative_specifier;
|
||||
use crate::util::path::to_percent_decoded_str;
|
||||
use crate::util::result::InfallibleResultExt;
|
||||
use crate::util::v8::convert;
|
||||
|
||||
static BRACKET_ACCESSOR_RE: Lazy<Regex> =
|
||||
|
|
50
cli/main.rs
50
cli/main.rs
|
@ -17,16 +17,18 @@ mod node;
|
|||
mod npm;
|
||||
mod ops;
|
||||
mod resolver;
|
||||
mod shared;
|
||||
mod standalone;
|
||||
mod sys;
|
||||
mod task_runner;
|
||||
mod tools;
|
||||
mod tsc;
|
||||
mod util;
|
||||
mod version;
|
||||
mod worker;
|
||||
|
||||
pub mod sys {
|
||||
#[allow(clippy::disallowed_types)] // ok, definition
|
||||
pub type CliSys = sys_traits::impls::RealSys;
|
||||
}
|
||||
|
||||
use std::env;
|
||||
use std::future::Future;
|
||||
use std::io::IsTerminal;
|
||||
|
@ -40,18 +42,22 @@ use deno_core::error::AnyError;
|
|||
use deno_core::error::CoreError;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::unsync::JoinHandle;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError;
|
||||
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
|
||||
use deno_telemetry::OtelConfig;
|
||||
use deno_terminal::colors;
|
||||
use factory::CliFactory;
|
||||
use standalone::MODULE_NOT_FOUND;
|
||||
use standalone::UNSUPPORTED_SCHEME;
|
||||
|
||||
const MODULE_NOT_FOUND: &str = "Module not found";
|
||||
const UNSUPPORTED_SCHEME: &str = "Unsupported scheme";
|
||||
|
||||
use self::npm::ResolveSnapshotError;
|
||||
use self::util::draw_thread::DrawThread;
|
||||
use crate::args::flags_from_vec;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::Flags;
|
||||
|
@ -201,7 +207,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
match result {
|
||||
Ok(v) => Ok(v),
|
||||
Err(script_err) => {
|
||||
if let Some(worker::CreateCustomWorkerError::ResolvePkgFolderFromDenoReq(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_)))) = util::result::any_and_jserrorbox_downcast_ref::<worker::CreateCustomWorkerError>(&script_err) {
|
||||
if let Some(worker::CreateCustomWorkerError::ResolvePkgFolderFromDenoReq(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_)))) = any_and_jserrorbox_downcast_ref::<worker::CreateCustomWorkerError>(&script_err) {
|
||||
if flags.node_modules_dir.is_none() {
|
||||
let mut flags = flags.deref().clone();
|
||||
let watch = match &flags.subcommand {
|
||||
|
@ -351,7 +357,7 @@ fn setup_panic_hook() {
|
|||
eprintln!("var set and include the backtrace in your report.");
|
||||
eprintln!();
|
||||
eprintln!("Platform: {} {}", env::consts::OS, env::consts::ARCH);
|
||||
eprintln!("Version: {}", version::DENO_VERSION_INFO.deno);
|
||||
eprintln!("Version: {}", deno_lib::version::DENO_VERSION_INFO.deno);
|
||||
eprintln!("Args: {:?}", env::args().collect::<Vec<_>>());
|
||||
eprintln!();
|
||||
orig_hook(panic_info);
|
||||
|
@ -373,13 +379,11 @@ fn exit_for_error(error: AnyError) -> ! {
|
|||
let mut error_code = 1;
|
||||
|
||||
if let Some(CoreError::Js(e)) =
|
||||
util::result::any_and_jserrorbox_downcast_ref::<CoreError>(&error)
|
||||
any_and_jserrorbox_downcast_ref::<CoreError>(&error)
|
||||
{
|
||||
error_string = format_js_error(e);
|
||||
} else if let Some(e @ ResolveSnapshotError { .. }) =
|
||||
util::result::any_and_jserrorbox_downcast_ref::<ResolveSnapshotError>(
|
||||
&error,
|
||||
)
|
||||
any_and_jserrorbox_downcast_ref::<ResolveSnapshotError>(&error)
|
||||
{
|
||||
if let Some(e) = e.maybe_integrity_check_error() {
|
||||
error_string = e.to_string();
|
||||
|
@ -442,19 +446,19 @@ fn resolve_flags_and_init(
|
|||
if err.kind() == clap::error::ErrorKind::DisplayVersion =>
|
||||
{
|
||||
// Ignore results to avoid BrokenPipe errors.
|
||||
util::logger::init(None, None);
|
||||
init_logging(None, None);
|
||||
let _ = err.print();
|
||||
deno_runtime::exit(0);
|
||||
}
|
||||
Err(err) => {
|
||||
util::logger::init(None, None);
|
||||
init_logging(None, None);
|
||||
exit_for_error(AnyError::from(err))
|
||||
}
|
||||
};
|
||||
|
||||
let otel_config = flags.otel_config();
|
||||
deno_telemetry::init(crate::args::otel_runtime_config(), &otel_config)?;
|
||||
util::logger::init(flags.log_level, Some(otel_config));
|
||||
deno_telemetry::init(deno_lib::version::otel_runtime_config(), &otel_config)?;
|
||||
init_logging(flags.log_level, Some(otel_config));
|
||||
|
||||
// TODO(bartlomieju): remove in Deno v2.5 and hard error then.
|
||||
if flags.unstable_config.legacy_flag_enabled {
|
||||
|
@ -487,3 +491,19 @@ fn resolve_flags_and_init(
|
|||
|
||||
Ok(flags)
|
||||
}
|
||||
|
||||
fn init_logging(
|
||||
maybe_level: Option<log::Level>,
|
||||
otel_config: Option<OtelConfig>,
|
||||
) {
|
||||
deno_lib::util::logger::init(deno_lib::util::logger::InitLoggingOptions {
|
||||
maybe_level,
|
||||
otel_config,
|
||||
// it was considered to hold the draw thread's internal lock
|
||||
// across logging, but if outputting to stderr blocks then that
|
||||
// could potentially block other threads that access the draw
|
||||
// thread's state
|
||||
on_log_start: DrawThread::hide,
|
||||
on_log_end: DrawThread::show,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -37,7 +37,11 @@ use deno_graph::ModuleGraph;
|
|||
use deno_graph::ModuleGraphError;
|
||||
use deno_graph::Resolution;
|
||||
use deno_graph::WasmModule;
|
||||
use deno_lib::loader::ModuleCodeStringSource;
|
||||
use deno_lib::loader::NotSupportedKindInNpmError;
|
||||
use deno_lib::loader::NpmModuleLoadError;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionChecker;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lib::worker::CreateModuleLoaderResult;
|
||||
use deno_lib::worker::ModuleLoaderFactory;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
|
@ -45,6 +49,7 @@ use deno_runtime::code_cache;
|
|||
use deno_runtime::deno_node::create_host_defined_options;
|
||||
use deno_runtime::deno_node::ops::require::UnableToGetCwdError;
|
||||
use deno_runtime::deno_node::NodeRequireLoader;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
|
@ -59,7 +64,6 @@ use crate::args::CliOptions;
|
|||
use crate::args::DenoSubcommand;
|
||||
use crate::args::TsTypeLib;
|
||||
use crate::cache::CodeCache;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::emit::Emitter;
|
||||
use crate::graph_container::MainModuleGraphContainer;
|
||||
|
@ -69,15 +73,13 @@ use crate::graph_util::enhance_graph_error;
|
|||
use crate::graph_util::CreateGraphOptions;
|
||||
use crate::graph_util::EnhanceGraphErrorMode;
|
||||
use crate::graph_util::ModuleGraphBuilder;
|
||||
use crate::node::CliCjsCodeAnalyzer;
|
||||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::node::CliNodeResolver;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliCjsTracker;
|
||||
use crate::resolver::CliNpmReqResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::ModuleCodeStringSource;
|
||||
use crate::resolver::NotSupportedKindInNpmError;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::sys::CliSys;
|
||||
use crate::tools::check;
|
||||
use crate::tools::check::CheckError;
|
||||
|
@ -86,6 +88,14 @@ use crate::util::progress_bar::ProgressBar;
|
|||
use crate::util::text_encoding::code_without_source_map;
|
||||
use crate::util::text_encoding::source_map_from_code;
|
||||
|
||||
pub type CliNpmModuleLoader = deno_lib::loader::NpmModuleLoader<
|
||||
CliCjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum PrepareModuleLoadError {
|
||||
#[class(inherit)]
|
||||
|
@ -246,7 +256,7 @@ struct SharedCliModuleLoaderState {
|
|||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
node_code_translator: Arc<CliNodeCodeTranslator>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
npm_module_loader: CliNpmModuleLoader,
|
||||
npm_registry_permission_checker:
|
||||
Arc<NpmRegistryReadPermissionChecker<CliSys>>,
|
||||
npm_req_resolver: Arc<CliNpmReqResolver>,
|
||||
|
@ -308,7 +318,7 @@ impl CliModuleLoaderFactory {
|
|||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
node_code_translator: Arc<CliNodeCodeTranslator>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
npm_module_loader: CliNpmModuleLoader,
|
||||
npm_registry_permission_checker: Arc<
|
||||
NpmRegistryReadPermissionChecker<CliSys>,
|
||||
>,
|
||||
|
@ -427,7 +437,7 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
|||
pub enum LoadCodeSourceError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
NpmModuleLoad(crate::resolver::NpmModuleLoadError),
|
||||
NpmModuleLoad(NpmModuleLoadError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
LoadPreparedModule(#[from] LoadPreparedModuleError),
|
||||
|
|
17
cli/node.rs
17
cli/node.rs
|
@ -12,7 +12,6 @@ use deno_runtime::deno_fs;
|
|||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use node_resolver::analyze::CjsCodeAnalysisError;
|
||||
use node_resolver::analyze::CjsCodeAnalyzer;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use serde::Deserialize;
|
||||
|
@ -76,7 +75,7 @@ impl CliCjsCodeAnalyzer {
|
|||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
source: &str,
|
||||
) -> Result<CliCjsAnalysis, CjsCodeAnalysisError> {
|
||||
) -> Result<CliCjsAnalysis, JsErrorBox> {
|
||||
let source_hash = CacheDBHash::from_hashable(source);
|
||||
if let Some(analysis) =
|
||||
self.cache.get_cjs_analysis(specifier.as_str(), source_hash)
|
||||
|
@ -93,7 +92,9 @@ impl CliCjsCodeAnalyzer {
|
|||
}
|
||||
|
||||
let cjs_tracker = self.cjs_tracker.clone();
|
||||
let is_maybe_cjs = cjs_tracker.is_maybe_cjs(specifier, media_type)?;
|
||||
let is_maybe_cjs = cjs_tracker
|
||||
.is_maybe_cjs(specifier, media_type)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let analysis = if is_maybe_cjs {
|
||||
let maybe_parsed_source = self
|
||||
.parsed_source_cache
|
||||
|
@ -103,7 +104,7 @@ impl CliCjsCodeAnalyzer {
|
|||
deno_core::unsync::spawn_blocking({
|
||||
let specifier = specifier.clone();
|
||||
let source: Arc<str> = source.into();
|
||||
move || -> Result<_, CjsCodeAnalysisError> {
|
||||
move || -> Result<_, JsErrorBox> {
|
||||
let parsed_source = maybe_parsed_source
|
||||
.map(Ok)
|
||||
.unwrap_or_else(|| {
|
||||
|
@ -118,11 +119,13 @@ impl CliCjsCodeAnalyzer {
|
|||
})
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let is_script = parsed_source.compute_is_script();
|
||||
let is_cjs = cjs_tracker.is_cjs_with_known_is_script(
|
||||
let is_cjs = cjs_tracker
|
||||
.is_cjs_with_known_is_script(
|
||||
parsed_source.specifier(),
|
||||
media_type,
|
||||
is_script,
|
||||
)?;
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
if is_cjs {
|
||||
let analysis = parsed_source.analyze_cjs();
|
||||
Ok(CliCjsAnalysis::Cjs {
|
||||
|
@ -154,7 +157,7 @@ impl CjsCodeAnalyzer for CliCjsCodeAnalyzer {
|
|||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
source: Option<Cow<'a, str>>,
|
||||
) -> Result<ExtNodeCjsAnalysis<'a>, CjsCodeAnalysisError> {
|
||||
) -> Result<ExtNodeCjsAnalysis<'a>, JsErrorBox> {
|
||||
let source = match source {
|
||||
Some(source) => source,
|
||||
None => {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::serde_json;
|
||||
use deno_resolver::npm::ByonmNpmResolver;
|
||||
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
|
||||
use deno_runtime::deno_process::NpmProcessStateProvider;
|
||||
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
pub type CliByonmNpmResolverCreateOptions =
|
||||
ByonmNpmResolverCreateOptions<CliSys>;
|
||||
pub type CliByonmNpmResolver = ByonmNpmResolver<CliSys>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliByonmNpmProcessStateProvider(pub Arc<CliByonmNpmResolver>);
|
||||
|
||||
impl NpmProcessStateProvider for CliByonmNpmProcessStateProvider {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Byonm,
|
||||
local_node_modules_path: self
|
||||
.0
|
||||
.root_node_modules_path()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
|
@ -220,7 +220,7 @@ impl<'a> LifecycleScripts<'a> {
|
|||
get_package_path,
|
||||
);
|
||||
let init_cwd = &self.config.initial_cwd;
|
||||
let process_state = crate::npm::managed::npm_process_state(
|
||||
let process_state = deno_lib::npm::npm_process_state(
|
||||
snapshot.as_valid_serialized(),
|
||||
Some(root_node_modules_dir_path),
|
||||
);
|
||||
|
|
|
@ -9,6 +9,7 @@ use async_trait::async_trait;
|
|||
use deno_core::futures::stream::FuturesUnordered;
|
||||
use deno_core::futures::StreamExt;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
|
@ -17,7 +18,6 @@ use super::common::lifecycle_scripts::LifecycleScriptsStrategy;
|
|||
use super::common::NpmPackageFsInstaller;
|
||||
use super::PackageCaching;
|
||||
use crate::args::LifecycleScriptsConfig;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::colors;
|
||||
use crate::npm::CliNpmCache;
|
||||
use crate::npm::CliNpmTarballCache;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::serde_json;
|
||||
use deno_error::JsError;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_npm::registry::NpmRegistryApi;
|
||||
|
@ -13,14 +11,10 @@ use deno_npm::resolution::NpmResolutionSnapshot;
|
|||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
use deno_resolver::npm::ManagedNpmResolverRc;
|
||||
use deno_runtime::deno_process::NpmProcessStateProvider;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::CliNpmRegistryInfoProvider;
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
pub type CliManagedNpmResolverCreateOptions =
|
||||
|
@ -207,27 +201,3 @@ async fn snapshot_from_lockfile(
|
|||
.await?;
|
||||
Ok(snapshot)
|
||||
}
|
||||
|
||||
pub fn npm_process_state(
|
||||
snapshot: ValidSerializedNpmResolutionSnapshot,
|
||||
node_modules_path: Option<&Path>,
|
||||
) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Snapshot(snapshot.into_serialized()),
|
||||
local_node_modules_path: node_modules_path
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliManagedNpmProcessStateProvider(pub ManagedNpmResolverRc<CliSys>);
|
||||
|
||||
impl NpmProcessStateProvider for CliManagedNpmProcessStateProvider {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
npm_process_state(
|
||||
self.0.resolution().serialized_valid_snapshot(),
|
||||
self.0.root_node_modules_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
mod byonm;
|
||||
pub mod installer;
|
||||
mod managed;
|
||||
|
||||
|
@ -10,15 +9,15 @@ use dashmap::DashMap;
|
|||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_runtime::deno_process::NpmProcessStateProviderRc;
|
||||
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use http::HeaderName;
|
||||
use http::HeaderValue;
|
||||
|
||||
pub use self::byonm::CliByonmNpmResolverCreateOptions;
|
||||
pub use self::managed::CliManagedNpmResolverCreateOptions;
|
||||
pub use self::managed::CliNpmResolverManagedSnapshotOption;
|
||||
pub use self::managed::NpmResolutionInitializer;
|
||||
|
@ -37,6 +36,8 @@ pub type CliNpmResolver = deno_resolver::npm::NpmResolver<CliSys>;
|
|||
pub type CliManagedNpmResolver = deno_resolver::npm::ManagedNpmResolver<CliSys>;
|
||||
pub type CliNpmResolverCreateOptions =
|
||||
deno_resolver::npm::NpmResolverCreateOptions<CliSys>;
|
||||
pub type CliByonmNpmResolverCreateOptions =
|
||||
ByonmNpmResolverCreateOptions<CliSys>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliNpmCacheHttpClient {
|
||||
|
@ -56,19 +57,6 @@ impl CliNpmCacheHttpClient {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_npm_process_state_provider(
|
||||
npm_resolver: &CliNpmResolver,
|
||||
) -> NpmProcessStateProviderRc {
|
||||
match npm_resolver {
|
||||
CliNpmResolver::Byonm(byonm_npm_resolver) => Arc::new(
|
||||
byonm::CliByonmNpmProcessStateProvider(byonm_npm_resolver.clone()),
|
||||
),
|
||||
CliNpmResolver::Managed(managed_npm_resolver) => Arc::new(
|
||||
managed::CliManagedNpmProcessStateProvider(managed_npm_resolver.clone()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
|
||||
async fn download_with_retries_on_any_tokio_runtime(
|
||||
|
@ -195,8 +183,8 @@ pub const NPM_CONFIG_USER_AGENT_ENV_VAR: &str = "npm_config_user_agent";
|
|||
pub fn get_npm_config_user_agent() -> String {
|
||||
format!(
|
||||
"deno/{} npm/? deno/{} {} {}",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
DENO_VERSION_INFO.deno,
|
||||
DENO_VERSION_INFO.deno,
|
||||
std::env::consts::OS,
|
||||
std::env::consts::ARCH
|
||||
)
|
||||
|
|
153
cli/resolver.rs
153
cli/resolver.rs
|
@ -1,16 +1,11 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use dashmap::DashSet;
|
||||
use deno_ast::MediaType;
|
||||
use deno_config::workspace::MappedResolutionDiagnostic;
|
||||
use deno_config::workspace::MappedResolutionError;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_graph::source::ResolveError;
|
||||
|
@ -22,23 +17,19 @@ use deno_resolver::npm::DenoInNpmPackageChecker;
|
|||
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolver;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::is_builtin_node_module;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::args::NpmCachingStrategy;
|
||||
use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
|
||||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::npm::installer::NpmInstaller;
|
||||
use crate::npm::installer::PackageCaching;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::sys::CliSys;
|
||||
use crate::util::sync::AtomicFlag;
|
||||
use crate::util::text_encoding::from_utf8_lossy_cow;
|
||||
|
||||
pub type CliCjsTracker =
|
||||
deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, CliSys>;
|
||||
|
@ -61,150 +52,6 @@ pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver<
|
|||
CliSys,
|
||||
>;
|
||||
|
||||
pub struct ModuleCodeStringSource {
|
||||
pub code: ModuleSourceCode,
|
||||
pub found_url: ModuleSpecifier,
|
||||
pub media_type: MediaType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, deno_error::JsError)]
|
||||
#[class(type)]
|
||||
#[error("{media_type} files are not supported in npm packages: {specifier}")]
|
||||
pub struct NotSupportedKindInNpmError {
|
||||
pub media_type: MediaType,
|
||||
pub specifier: Url,
|
||||
}
|
||||
|
||||
// todo(dsherret): move to module_loader.rs (it seems to be here due to use in standalone)
|
||||
#[derive(Clone)]
|
||||
pub struct NpmModuleLoader {
|
||||
cjs_tracker: Arc<CliCjsTracker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
node_code_translator: Arc<CliNodeCodeTranslator>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, deno_error::JsError)]
|
||||
pub enum NpmModuleLoadError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
NotSupportedKindInNpm(#[from] NotSupportedKindInNpmError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
|
||||
#[class(inherit)]
|
||||
#[error("{}", format_message(file_path, maybe_referrer))]
|
||||
Fs {
|
||||
file_path: PathBuf,
|
||||
maybe_referrer: Option<ModuleSpecifier>,
|
||||
#[source]
|
||||
#[inherit]
|
||||
source: deno_runtime::deno_io::fs::FsError,
|
||||
},
|
||||
}
|
||||
|
||||
fn format_message(
|
||||
file_path: &std::path::Path,
|
||||
maybe_referrer: &Option<ModuleSpecifier>,
|
||||
) -> String {
|
||||
if file_path.is_dir() {
|
||||
// directory imports are not allowed when importing from an
|
||||
// ES module, so provide the user with a helpful error message
|
||||
let dir_path = file_path;
|
||||
let mut msg = "Directory import ".to_string();
|
||||
msg.push_str(&dir_path.to_string_lossy());
|
||||
if let Some(referrer) = maybe_referrer {
|
||||
msg.push_str(" is not supported resolving import from ");
|
||||
msg.push_str(referrer.as_str());
|
||||
let entrypoint_name = ["index.mjs", "index.js", "index.cjs"]
|
||||
.iter()
|
||||
.find(|e| dir_path.join(e).is_file());
|
||||
if let Some(entrypoint_name) = entrypoint_name {
|
||||
msg.push_str("\nDid you mean to import ");
|
||||
msg.push_str(entrypoint_name);
|
||||
msg.push_str(" within the directory?");
|
||||
}
|
||||
}
|
||||
msg
|
||||
} else {
|
||||
let mut msg = "Unable to load ".to_string();
|
||||
msg.push_str(&file_path.to_string_lossy());
|
||||
if let Some(referrer) = maybe_referrer {
|
||||
msg.push_str(" imported from ");
|
||||
msg.push_str(referrer.as_str());
|
||||
}
|
||||
msg
|
||||
}
|
||||
}
|
||||
|
||||
impl NpmModuleLoader {
|
||||
pub fn new(
|
||||
cjs_tracker: Arc<CliCjsTracker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
node_code_translator: Arc<CliNodeCodeTranslator>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_tracker,
|
||||
node_code_translator,
|
||||
fs,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Result<ModuleCodeStringSource, NpmModuleLoadError> {
|
||||
let file_path = specifier.to_file_path().unwrap();
|
||||
let code = self
|
||||
.fs
|
||||
.read_file_async(file_path.clone(), None)
|
||||
.await
|
||||
.map_err(|source| NpmModuleLoadError::Fs {
|
||||
file_path,
|
||||
maybe_referrer: maybe_referrer.cloned(),
|
||||
source,
|
||||
})?;
|
||||
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
if media_type.is_emittable() {
|
||||
return Err(NpmModuleLoadError::NotSupportedKindInNpm(
|
||||
NotSupportedKindInNpmError {
|
||||
media_type,
|
||||
specifier: specifier.clone(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let code = if self.cjs_tracker.is_maybe_cjs(specifier, media_type)? {
|
||||
// translate cjs to esm if it's cjs and inject node globals
|
||||
let code = from_utf8_lossy_cow(code);
|
||||
ModuleSourceCode::String(
|
||||
self
|
||||
.node_code_translator
|
||||
.translate_cjs_to_esm(specifier, Some(code))
|
||||
.await?
|
||||
.into_owned()
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
// esm and json code is untouched
|
||||
ModuleSourceCode::Bytes(match code {
|
||||
Cow::Owned(bytes) => bytes.into_boxed_slice().into(),
|
||||
Cow::Borrowed(bytes) => bytes.into(),
|
||||
})
|
||||
};
|
||||
|
||||
Ok(ModuleCodeStringSource {
|
||||
code,
|
||||
found_url: specifier.clone(),
|
||||
media_type: MediaType::from_specifier(specifier),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FoundPackageJsonDepFlag(AtomicFlag);
|
||||
|
||||
|
|
63
cli/rt/Cargo.toml
Normal file
63
cli/rt/Cargo.toml
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
[package]
|
||||
name = "denort"
|
||||
version = "2.1.5"
|
||||
authors.workspace = true
|
||||
default-run = "denort"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
repository.workspace = true
|
||||
description = "Provides the denort executable"
|
||||
|
||||
[[bin]]
|
||||
name = "denort"
|
||||
path = "main.rs"
|
||||
doc = false
|
||||
|
||||
[[test]]
|
||||
name = "integration"
|
||||
path = "integration_tests_runner.rs"
|
||||
harness = false
|
||||
|
||||
[build-dependencies]
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting", "only_snapshotted_js_sources"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
|
||||
[dependencies]
|
||||
deno_cache_dir.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_error.workspace = true
|
||||
deno_lib.workspace = true
|
||||
deno_media_type = { workspace = true, features = ["data_url", "decoding"] }
|
||||
deno_npm.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_semver.workspace = true
|
||||
deno_snapshots.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
libsui = "0.5.0"
|
||||
node_resolver.workspace = true
|
||||
|
||||
async-trait.workspace = true
|
||||
bincode = "=1.3.3"
|
||||
import_map = { version = "=0.21.0", features = ["ext"] }
|
||||
indexmap.workspace = true
|
||||
log = { workspace = true, features = ["serde"] }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sys_traits = { workspace = true, features = ["getrandom", "filetime", "libc", "real", "strip_unc", "winapi"] }
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
tokio-util.workspace = true
|
||||
twox-hash.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
||||
sys_traits = { workspace = true, features = ["memory"] }
|
||||
test_util.workspace = true
|
682
cli/rt/binary.rs
Normal file
682
cli/rt/binary.rs
Normal file
|
@ -0,0 +1,682 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::FastString;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleType;
|
||||
use deno_error::JsError;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::standalone::binary::DenoRtDeserializable;
|
||||
use deno_lib::standalone::binary::Metadata;
|
||||
use deno_lib::standalone::binary::RemoteModuleEntry;
|
||||
use deno_lib::standalone::binary::SpecifierDataStore;
|
||||
use deno_lib::standalone::binary::SpecifierId;
|
||||
use deno_lib::standalone::binary::MAGIC_BYTES;
|
||||
use deno_lib::standalone::virtual_fs::VirtualDirectory;
|
||||
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmPackageId;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_fs::RealFs;
|
||||
use deno_runtime::deno_io::fs::FsError;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::StackString;
|
||||
use indexmap::IndexMap;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::file_system::FileBackedVfs;
|
||||
use crate::file_system::VfsRoot;
|
||||
|
||||
pub struct StandaloneData {
|
||||
pub metadata: Metadata,
|
||||
pub modules: Arc<StandaloneModules>,
|
||||
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
|
||||
pub root_path: PathBuf,
|
||||
pub vfs: Arc<FileBackedVfs>,
|
||||
}
|
||||
|
||||
/// This function will try to run this binary as a standalone binary
|
||||
/// produced by `deno compile`. It determines if this is a standalone
|
||||
/// binary by skipping over the trailer width at the end of the file,
|
||||
/// then checking for the magic trailer string `d3n0l4nd`. If found,
|
||||
/// the bundle is executed. If not, this function exits with `Ok(None)`.
|
||||
pub fn extract_standalone(
|
||||
cli_args: Cow<Vec<OsString>>,
|
||||
) -> Result<Option<StandaloneData>, AnyError> {
|
||||
let Some(data) = libsui::find_section("d3n0l4nd") else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let root_path = {
|
||||
let maybe_current_exe = std::env::current_exe().ok();
|
||||
let current_exe_name = maybe_current_exe
|
||||
.as_ref()
|
||||
.and_then(|p| p.file_name())
|
||||
.map(|p| p.to_string_lossy())
|
||||
// should never happen
|
||||
.unwrap_or_else(|| Cow::Borrowed("binary"));
|
||||
std::env::temp_dir().join(format!("deno-compile-{}", current_exe_name))
|
||||
};
|
||||
let root_url = deno_path_util::url_from_directory_path(&root_path)?;
|
||||
|
||||
let DeserializedDataSection {
|
||||
mut metadata,
|
||||
npm_snapshot,
|
||||
modules_store: remote_modules,
|
||||
vfs_root_entries,
|
||||
vfs_files_data,
|
||||
} = match deserialize_binary_data_section(&root_url, data)? {
|
||||
Some(data_section) => data_section,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let cli_args = cli_args.into_owned();
|
||||
metadata.argv.reserve(cli_args.len() - 1);
|
||||
for arg in cli_args.into_iter().skip(1) {
|
||||
metadata.argv.push(arg.into_string().unwrap());
|
||||
}
|
||||
let vfs = {
|
||||
let fs_root = VfsRoot {
|
||||
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(),
|
||||
start_file_offset: 0,
|
||||
};
|
||||
Arc::new(FileBackedVfs::new(
|
||||
Cow::Borrowed(vfs_files_data),
|
||||
fs_root,
|
||||
metadata.vfs_case_sensitivity,
|
||||
))
|
||||
};
|
||||
Ok(Some(StandaloneData {
|
||||
metadata,
|
||||
modules: Arc::new(StandaloneModules {
|
||||
modules: remote_modules,
|
||||
vfs: vfs.clone(),
|
||||
}),
|
||||
npm_snapshot,
|
||||
root_path,
|
||||
vfs,
|
||||
}))
|
||||
}
|
||||
|
||||
pub struct DeserializedDataSection {
|
||||
pub metadata: Metadata,
|
||||
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
|
||||
pub modules_store: RemoteModulesStore,
|
||||
pub vfs_root_entries: VirtualDirectoryEntries,
|
||||
pub vfs_files_data: &'static [u8],
|
||||
}
|
||||
|
||||
pub fn deserialize_binary_data_section(
|
||||
root_dir_url: &Url,
|
||||
data: &'static [u8],
|
||||
) -> Result<Option<DeserializedDataSection>, AnyError> {
|
||||
fn read_magic_bytes(input: &[u8]) -> Result<(&[u8], bool), AnyError> {
|
||||
if input.len() < MAGIC_BYTES.len() {
|
||||
bail!("Unexpected end of data. Could not find magic bytes.");
|
||||
}
|
||||
let (magic_bytes, input) = input.split_at(MAGIC_BYTES.len());
|
||||
if magic_bytes != MAGIC_BYTES {
|
||||
return Ok((input, false));
|
||||
}
|
||||
Ok((input, true))
|
||||
}
|
||||
|
||||
let (input, found) = read_magic_bytes(data)?;
|
||||
if !found {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// 1. Metadata
|
||||
let (input, data) =
|
||||
read_bytes_with_u64_len(input).context("reading metadata")?;
|
||||
let metadata: Metadata =
|
||||
serde_json::from_slice(data).context("deserializing metadata")?;
|
||||
// 2. Npm snapshot
|
||||
let (input, data) =
|
||||
read_bytes_with_u64_len(input).context("reading npm snapshot")?;
|
||||
let npm_snapshot = if data.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(deserialize_npm_snapshot(data).context("deserializing npm snapshot")?)
|
||||
};
|
||||
// 3. Specifiers
|
||||
let (input, specifiers_store) =
|
||||
SpecifierStore::deserialize(root_dir_url, input)
|
||||
.context("deserializing specifiers")?;
|
||||
// 4. Redirects
|
||||
let (input, redirects_store) =
|
||||
SpecifierDataStore::<SpecifierId>::deserialize(input)
|
||||
.context("deserializing redirects")?;
|
||||
// 5. Remote modules
|
||||
let (input, remote_modules_store) =
|
||||
SpecifierDataStore::<RemoteModuleEntry<'static>>::deserialize(input)
|
||||
.context("deserializing remote modules")?;
|
||||
// 6. VFS
|
||||
let (input, data) = read_bytes_with_u64_len(input).context("vfs")?;
|
||||
let vfs_root_entries: VirtualDirectoryEntries =
|
||||
serde_json::from_slice(data).context("deserializing vfs data")?;
|
||||
let (input, vfs_files_data) =
|
||||
read_bytes_with_u64_len(input).context("reading vfs files data")?;
|
||||
|
||||
// finally ensure we read the magic bytes at the end
|
||||
let (_input, found) = read_magic_bytes(input)?;
|
||||
if !found {
|
||||
bail!("Could not find magic bytes at the end of the data.");
|
||||
}
|
||||
|
||||
let modules_store = RemoteModulesStore::new(
|
||||
specifiers_store,
|
||||
redirects_store,
|
||||
remote_modules_store,
|
||||
);
|
||||
|
||||
Ok(Some(DeserializedDataSection {
|
||||
metadata,
|
||||
npm_snapshot,
|
||||
modules_store,
|
||||
vfs_root_entries,
|
||||
vfs_files_data,
|
||||
}))
|
||||
}
|
||||
|
||||
struct SpecifierStore {
|
||||
data: IndexMap<Arc<Url>, SpecifierId>,
|
||||
reverse: IndexMap<SpecifierId, Arc<Url>>,
|
||||
}
|
||||
|
||||
impl SpecifierStore {
|
||||
pub fn deserialize<'a>(
|
||||
root_dir_url: &Url,
|
||||
input: &'a [u8],
|
||||
) -> std::io::Result<(&'a [u8], Self)> {
|
||||
let (input, len) = read_u32_as_usize(input)?;
|
||||
let mut data = IndexMap::with_capacity(len);
|
||||
let mut reverse = IndexMap::with_capacity(len);
|
||||
let mut input = input;
|
||||
for _ in 0..len {
|
||||
let (new_input, specifier_str) = read_string_lossy(input)?;
|
||||
let specifier = match Url::parse(&specifier_str) {
|
||||
Ok(url) => url,
|
||||
Err(err) => match root_dir_url.join(&specifier_str) {
|
||||
Ok(url) => url,
|
||||
Err(_) => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
err,
|
||||
));
|
||||
}
|
||||
},
|
||||
};
|
||||
let (new_input, id) = SpecifierId::deserialize(new_input)?;
|
||||
let specifier = Arc::new(specifier);
|
||||
data.insert(specifier.clone(), id);
|
||||
reverse.insert(id, specifier);
|
||||
input = new_input;
|
||||
}
|
||||
Ok((input, Self { data, reverse }))
|
||||
}
|
||||
|
||||
pub fn get_id(&self, specifier: &Url) -> Option<SpecifierId> {
|
||||
self.data.get(specifier).cloned()
|
||||
}
|
||||
|
||||
pub fn get_specifier(&self, specifier_id: SpecifierId) -> Option<&Url> {
|
||||
self.reverse.get(&specifier_id).map(|url| url.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StandaloneModules {
|
||||
modules: RemoteModulesStore,
|
||||
vfs: Arc<FileBackedVfs>,
|
||||
}
|
||||
|
||||
impl StandaloneModules {
|
||||
pub fn resolve_specifier<'a>(
|
||||
&'a self,
|
||||
specifier: &'a Url,
|
||||
) -> Result<Option<&'a Url>, TooManyRedirectsError> {
|
||||
if specifier.scheme() == "file" {
|
||||
Ok(Some(specifier))
|
||||
} else {
|
||||
self.modules.resolve_specifier(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_file(&self, path: &Path) -> bool {
|
||||
self.vfs.file_entry(path).is_ok()
|
||||
}
|
||||
|
||||
pub fn read<'a>(
|
||||
&'a self,
|
||||
specifier: &'a Url,
|
||||
) -> Result<Option<DenoCompileModuleData<'a>>, JsErrorBox> {
|
||||
if specifier.scheme() == "file" {
|
||||
let path = deno_path_util::url_to_file_path(specifier)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let mut transpiled = None;
|
||||
let mut source_map = None;
|
||||
let mut cjs_export_analysis = None;
|
||||
let bytes = match self.vfs.file_entry(&path) {
|
||||
Ok(entry) => {
|
||||
let bytes = self
|
||||
.vfs
|
||||
.read_file_all(entry)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
transpiled = entry
|
||||
.transpiled_offset
|
||||
.and_then(|t| self.vfs.read_file_offset_with_len(t).ok());
|
||||
source_map = entry
|
||||
.source_map_offset
|
||||
.and_then(|t| self.vfs.read_file_offset_with_len(t).ok());
|
||||
cjs_export_analysis = entry
|
||||
.cjs_export_analysis_offset
|
||||
.and_then(|t| self.vfs.read_file_offset_with_len(t).ok());
|
||||
bytes
|
||||
}
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => {
|
||||
match RealFs.read_file_sync(&path, None) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(FsError::Io(err)) if err.kind() == ErrorKind::NotFound => {
|
||||
return Ok(None)
|
||||
}
|
||||
Err(err) => return Err(JsErrorBox::from_err(err)),
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(JsErrorBox::from_err(err)),
|
||||
};
|
||||
Ok(Some(DenoCompileModuleData {
|
||||
media_type: MediaType::from_specifier(specifier),
|
||||
specifier,
|
||||
data: bytes,
|
||||
transpiled,
|
||||
source_map,
|
||||
cjs_export_analysis,
|
||||
}))
|
||||
} else {
|
||||
self.modules.read(specifier).map_err(JsErrorBox::from_err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DenoCompileModuleData<'a> {
|
||||
pub specifier: &'a Url,
|
||||
pub media_type: MediaType,
|
||||
pub data: Cow<'static, [u8]>,
|
||||
pub transpiled: Option<Cow<'static, [u8]>>,
|
||||
pub source_map: Option<Cow<'static, [u8]>>,
|
||||
pub cjs_export_analysis: Option<Cow<'static, [u8]>>,
|
||||
}
|
||||
|
||||
impl<'a> DenoCompileModuleData<'a> {
|
||||
pub fn into_parts(self) -> (&'a Url, ModuleType, DenoCompileModuleSource) {
|
||||
fn into_string_unsafe(data: Cow<'static, [u8]>) -> DenoCompileModuleSource {
|
||||
match data {
|
||||
Cow::Borrowed(d) => DenoCompileModuleSource::String(
|
||||
// SAFETY: we know this is a valid utf8 string
|
||||
unsafe { std::str::from_utf8_unchecked(d) },
|
||||
),
|
||||
Cow::Owned(d) => DenoCompileModuleSource::Bytes(Cow::Owned(d)),
|
||||
}
|
||||
}
|
||||
|
||||
let data = self.transpiled.unwrap_or(self.data);
|
||||
let (media_type, source) = match self.media_type {
|
||||
MediaType::JavaScript
|
||||
| MediaType::Jsx
|
||||
| MediaType::Mjs
|
||||
| MediaType::Cjs
|
||||
| MediaType::TypeScript
|
||||
| MediaType::Mts
|
||||
| MediaType::Cts
|
||||
| MediaType::Dts
|
||||
| MediaType::Dmts
|
||||
| MediaType::Dcts
|
||||
| MediaType::Tsx => (ModuleType::JavaScript, into_string_unsafe(data)),
|
||||
MediaType::Json => (ModuleType::Json, into_string_unsafe(data)),
|
||||
MediaType::Wasm => {
|
||||
(ModuleType::Wasm, DenoCompileModuleSource::Bytes(data))
|
||||
}
|
||||
// just assume javascript if we made it here
|
||||
MediaType::Css | MediaType::SourceMap | MediaType::Unknown => {
|
||||
(ModuleType::JavaScript, DenoCompileModuleSource::Bytes(data))
|
||||
}
|
||||
};
|
||||
(self.specifier, media_type, source)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DenoCompileModuleSource {
|
||||
String(&'static str),
|
||||
Bytes(Cow<'static, [u8]>),
|
||||
}
|
||||
|
||||
impl DenoCompileModuleSource {
|
||||
pub fn into_for_v8(self) -> ModuleSourceCode {
|
||||
fn into_bytes(data: Cow<'static, [u8]>) -> ModuleSourceCode {
|
||||
ModuleSourceCode::Bytes(match data {
|
||||
Cow::Borrowed(d) => d.into(),
|
||||
Cow::Owned(d) => d.into_boxed_slice().into(),
|
||||
})
|
||||
}
|
||||
|
||||
match self {
|
||||
// todo(https://github.com/denoland/deno_core/pull/943): store whether
|
||||
// the string is ascii or not ahead of time so we can avoid the is_ascii()
|
||||
// check in FastString::from_static
|
||||
Self::String(s) => ModuleSourceCode::String(FastString::from_static(s)),
|
||||
Self::Bytes(b) => into_bytes(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, JsError)]
|
||||
#[class(generic)]
|
||||
#[error("Too many redirects resolving: {0}")]
|
||||
pub struct TooManyRedirectsError(Url);
|
||||
|
||||
pub struct RemoteModulesStore {
|
||||
specifiers: SpecifierStore,
|
||||
redirects: SpecifierDataStore<SpecifierId>,
|
||||
remote_modules: SpecifierDataStore<RemoteModuleEntry<'static>>,
|
||||
}
|
||||
|
||||
impl RemoteModulesStore {
|
||||
fn new(
|
||||
specifiers: SpecifierStore,
|
||||
redirects: SpecifierDataStore<SpecifierId>,
|
||||
remote_modules: SpecifierDataStore<RemoteModuleEntry<'static>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
specifiers,
|
||||
redirects,
|
||||
remote_modules,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_specifier<'a>(
|
||||
&'a self,
|
||||
specifier: &'a Url,
|
||||
) -> Result<Option<&'a Url>, TooManyRedirectsError> {
|
||||
let Some(mut current) = self.specifiers.get_id(specifier) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if count > 10 {
|
||||
return Err(TooManyRedirectsError(specifier.clone()));
|
||||
}
|
||||
match self.redirects.get(current) {
|
||||
Some(to) => {
|
||||
current = *to;
|
||||
count += 1;
|
||||
}
|
||||
None => {
|
||||
if count == 0 {
|
||||
return Ok(Some(specifier));
|
||||
} else {
|
||||
return Ok(self.specifiers.get_specifier(current));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<'a>(
|
||||
&'a self,
|
||||
original_specifier: &'a Url,
|
||||
) -> Result<Option<DenoCompileModuleData<'a>>, TooManyRedirectsError> {
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn handle_cow_ref(data: &Cow<'static, [u8]>) -> Cow<'static, [u8]> {
|
||||
match data {
|
||||
Cow::Borrowed(data) => Cow::Borrowed(data),
|
||||
Cow::Owned(data) => {
|
||||
// this variant should never happen because the data
|
||||
// should always be borrowed static in denort
|
||||
debug_assert!(false);
|
||||
Cow::Owned(data.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
let Some(mut specifier) = self.specifiers.get_id(original_specifier) else {
|
||||
return Ok(None);
|
||||
};
|
||||
loop {
|
||||
if count > 10 {
|
||||
return Err(TooManyRedirectsError(original_specifier.clone()));
|
||||
}
|
||||
match self.redirects.get(specifier) {
|
||||
Some(to) => {
|
||||
specifier = *to;
|
||||
count += 1;
|
||||
}
|
||||
None => {
|
||||
let Some(entry) = self.remote_modules.get(specifier) else {
|
||||
return Ok(None);
|
||||
};
|
||||
return Ok(Some(DenoCompileModuleData {
|
||||
specifier: if count == 0 {
|
||||
original_specifier
|
||||
} else {
|
||||
self.specifiers.get_specifier(specifier).unwrap()
|
||||
},
|
||||
media_type: entry.media_type,
|
||||
data: handle_cow_ref(&entry.data),
|
||||
transpiled: entry.maybe_transpiled.as_ref().map(handle_cow_ref),
|
||||
source_map: entry.maybe_source_map.as_ref().map(handle_cow_ref),
|
||||
cjs_export_analysis: entry
|
||||
.maybe_cjs_export_analysis
|
||||
.as_ref()
|
||||
.map(handle_cow_ref),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_npm_snapshot(
|
||||
input: &[u8],
|
||||
) -> Result<ValidSerializedNpmResolutionSnapshot, AnyError> {
|
||||
fn parse_id(input: &[u8]) -> Result<(&[u8], NpmPackageId), AnyError> {
|
||||
let (input, id) = read_string_lossy(input)?;
|
||||
let id = NpmPackageId::from_serialized(&id)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_lifetimes)] // clippy bug
|
||||
fn parse_root_package<'a>(
|
||||
id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> impl Fn(&[u8]) -> Result<(&[u8], (PackageReq, NpmPackageId)), AnyError> + 'a
|
||||
{
|
||||
|input| {
|
||||
let (input, req) = read_string_lossy(input)?;
|
||||
let req = PackageReq::from_str(&req)?;
|
||||
let (input, id) = read_u32_as_usize(input)?;
|
||||
Ok((input, (req, id_to_npm_id(id)?)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_lifetimes)] // clippy bug
|
||||
fn parse_package_dep<'a>(
|
||||
id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> impl Fn(&[u8]) -> Result<(&[u8], (StackString, NpmPackageId)), AnyError> + 'a
|
||||
{
|
||||
|input| {
|
||||
let (input, req) = read_string_lossy(input)?;
|
||||
let (input, id) = read_u32_as_usize(input)?;
|
||||
let req = StackString::from_cow(req);
|
||||
Ok((input, (req, id_to_npm_id(id)?)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_package<'a>(
|
||||
input: &'a [u8],
|
||||
id: NpmPackageId,
|
||||
id_to_npm_id: &impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> Result<(&'a [u8], SerializedNpmResolutionSnapshotPackage), AnyError> {
|
||||
let (input, deps_len) = read_u32_as_usize(input)?;
|
||||
let (input, dependencies) =
|
||||
parse_hashmap_n_times(input, deps_len, parse_package_dep(id_to_npm_id))?;
|
||||
Ok((
|
||||
input,
|
||||
SerializedNpmResolutionSnapshotPackage {
|
||||
id,
|
||||
system: Default::default(),
|
||||
dist: Default::default(),
|
||||
dependencies,
|
||||
optional_dependencies: Default::default(),
|
||||
bin: None,
|
||||
scripts: Default::default(),
|
||||
deprecated: Default::default(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
let (input, packages_len) = read_u32_as_usize(input)?;
|
||||
|
||||
// get a hashmap of all the npm package ids to their serialized ids
|
||||
let (input, data_ids_to_npm_ids) =
|
||||
parse_vec_n_times(input, packages_len, parse_id)
|
||||
.context("deserializing id")?;
|
||||
let data_id_to_npm_id = |id: usize| {
|
||||
data_ids_to_npm_ids
|
||||
.get(id)
|
||||
.cloned()
|
||||
.ok_or_else(|| deno_core::anyhow::anyhow!("Invalid npm package id"))
|
||||
};
|
||||
|
||||
let (input, root_packages_len) = read_u32_as_usize(input)?;
|
||||
let (input, root_packages) = parse_hashmap_n_times(
|
||||
input,
|
||||
root_packages_len,
|
||||
parse_root_package(&data_id_to_npm_id),
|
||||
)
|
||||
.context("deserializing root package")?;
|
||||
let (input, packages) =
|
||||
parse_vec_n_times_with_index(input, packages_len, |input, index| {
|
||||
parse_package(input, data_id_to_npm_id(index)?, &data_id_to_npm_id)
|
||||
})
|
||||
.context("deserializing package")?;
|
||||
|
||||
if !input.is_empty() {
|
||||
bail!("Unexpected data left over");
|
||||
}
|
||||
|
||||
Ok(
|
||||
SerializedNpmResolutionSnapshot {
|
||||
packages,
|
||||
root_packages,
|
||||
}
|
||||
// this is ok because we have already verified that all the
|
||||
// identifiers found in the snapshot are valid via the
|
||||
// npm package id -> npm package id mapping
|
||||
.into_valid_unsafe(),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_hashmap_n_times<TKey: std::cmp::Eq + std::hash::Hash, TValue>(
|
||||
mut input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8]) -> Result<(&[u8], (TKey, TValue)), AnyError>,
|
||||
) -> Result<(&[u8], HashMap<TKey, TValue>), AnyError> {
|
||||
let mut results = HashMap::with_capacity(times);
|
||||
for _ in 0..times {
|
||||
let result = parse(input);
|
||||
let (new_input, (key, value)) = result?;
|
||||
results.insert(key, value);
|
||||
input = new_input;
|
||||
}
|
||||
Ok((input, results))
|
||||
}
|
||||
|
||||
fn parse_vec_n_times<TResult>(
|
||||
input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8]) -> Result<(&[u8], TResult), AnyError>,
|
||||
) -> Result<(&[u8], Vec<TResult>), AnyError> {
|
||||
parse_vec_n_times_with_index(input, times, |input, _index| parse(input))
|
||||
}
|
||||
|
||||
fn parse_vec_n_times_with_index<TResult>(
|
||||
mut input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8], usize) -> Result<(&[u8], TResult), AnyError>,
|
||||
) -> Result<(&[u8], Vec<TResult>), AnyError> {
|
||||
let mut results = Vec::with_capacity(times);
|
||||
for i in 0..times {
|
||||
let result = parse(input, i);
|
||||
let (new_input, result) = result?;
|
||||
results.push(result);
|
||||
input = new_input;
|
||||
}
|
||||
Ok((input, results))
|
||||
}
|
||||
|
||||
fn read_bytes_with_u64_len(input: &[u8]) -> std::io::Result<(&[u8], &[u8])> {
|
||||
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]) -> std::io::Result<(&[u8], &[u8])> {
|
||||
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) -> std::io::Result<(&[u8], &[u8])> {
|
||||
check_has_len(input, len)?;
|
||||
let (len_bytes, input) = input.split_at(len);
|
||||
Ok((input, len_bytes))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_has_len(input: &[u8], len: usize) -> std::io::Result<()> {
|
||||
if input.len() < len {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"Unexpected end of data",
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_string_lossy(input: &[u8]) -> std::io::Result<(&[u8], Cow<str>)> {
|
||||
let (input, data_bytes) = read_bytes_with_u32_len(input)?;
|
||||
Ok((input, String::from_utf8_lossy(data_bytes)))
|
||||
}
|
||||
|
||||
fn read_u32_as_usize(input: &[u8]) -> std::io::Result<(&[u8], usize)> {
|
||||
let (input, len_bytes) = read_bytes(input, 4)?;
|
||||
let len = u32::from_le_bytes(len_bytes.try_into().unwrap());
|
||||
Ok((input, len as usize))
|
||||
}
|
||||
|
||||
fn read_u64(input: &[u8]) -> std::io::Result<(&[u8], u64)> {
|
||||
let (input, len_bytes) = read_bytes(input, 8)?;
|
||||
let len = u64::from_le_bytes(len_bytes.try_into().unwrap());
|
||||
Ok((input, len))
|
||||
}
|
11
cli/rt/build.rs
Normal file
11
cli/rt/build.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
fn main() {
|
||||
// Skip building from docs.rs.
|
||||
if std::env::var_os("DOCS_RS").is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
deno_runtime::deno_napi::print_linker_flags("denort");
|
||||
deno_runtime::deno_webgpu::print_linker_flags("denort");
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::io::BufReader;
|
||||
use std::io::BufWriter;
|
||||
|
@ -10,17 +9,15 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::unsync::sync::AtomicFlag;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_path_util::get_atomic_path;
|
||||
use deno_runtime::code_cache::CodeCache;
|
||||
use deno_runtime::code_cache::CodeCacheType;
|
||||
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::worker::CliCodeCache;
|
||||
use url::Url;
|
||||
|
||||
enum CodeCacheStrategy {
|
||||
FirstRun(FirstRunCodeCacheStrategy),
|
||||
|
@ -76,12 +73,27 @@ impl DenoCompileCodeCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_deno_core(self: Arc<Self>) -> Arc<dyn CodeCache> {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
match &self.strategy {
|
||||
CodeCacheStrategy::FirstRun(strategy) => {
|
||||
!strategy.is_finished.is_raised()
|
||||
}
|
||||
CodeCacheStrategy::SubsequentRun(strategy) => {
|
||||
!strategy.is_finished.is_raised()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CodeCache for DenoCompileCodeCache {
|
||||
fn get_sync(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
specifier: &Url,
|
||||
code_cache_type: CodeCacheType,
|
||||
source_hash: u64,
|
||||
) -> Option<Vec<u8>> {
|
||||
|
@ -106,7 +118,7 @@ impl CodeCache for DenoCompileCodeCache {
|
|||
|
||||
fn set_sync(
|
||||
&self,
|
||||
specifier: ModuleSpecifier,
|
||||
specifier: Url,
|
||||
code_cache_type: CodeCacheType,
|
||||
source_hash: u64,
|
||||
bytes: &[u8],
|
||||
|
@ -152,23 +164,6 @@ impl CodeCache for DenoCompileCodeCache {
|
|||
}
|
||||
}
|
||||
|
||||
impl CliCodeCache for DenoCompileCodeCache {
|
||||
fn enabled(&self) -> bool {
|
||||
match &self.strategy {
|
||||
CodeCacheStrategy::FirstRun(strategy) => {
|
||||
!strategy.is_finished.is_raised()
|
||||
}
|
||||
CodeCacheStrategy::SubsequentRun(strategy) => {
|
||||
!strategy.is_finished.is_raised()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_code_cache(self: Arc<Self>) -> Arc<dyn CodeCache> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type CodeCacheKey = (String, CodeCacheType);
|
||||
|
||||
struct FirstRunCodeCacheData {
|
||||
|
@ -216,7 +211,7 @@ struct SubsequentRunCodeCacheStrategy {
|
|||
impl SubsequentRunCodeCacheStrategy {
|
||||
fn take_from_cache(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
specifier: &Url,
|
||||
code_cache_type: CodeCacheType,
|
||||
source_hash: u64,
|
||||
) -> Option<Vec<u8>> {
|
||||
|
@ -395,8 +390,6 @@ fn deserialize_with_reader<T: Read>(
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
|
||||
use test_util::TempDir;
|
||||
|
||||
use super::*;
|
||||
|
@ -463,8 +456,8 @@ mod test {
|
|||
fn code_cache() {
|
||||
let temp_dir = TempDir::new();
|
||||
let file_path = temp_dir.path().join("cache.bin").to_path_buf();
|
||||
let url1 = ModuleSpecifier::parse("https://deno.land/example1.js").unwrap();
|
||||
let url2 = ModuleSpecifier::parse("https://deno.land/example2.js").unwrap();
|
||||
let url1 = Url::parse("https://deno.land/example1.js").unwrap();
|
||||
let url2 = Url::parse("https://deno.land/example2.js").unwrap();
|
||||
// first run
|
||||
{
|
||||
let code_cache = DenoCompileCodeCache::new(file_path.clone(), 1234);
|
1713
cli/rt/file_system.rs
Normal file
1713
cli/rt/file_system.rs
Normal file
File diff suppressed because it is too large
Load diff
5
cli/rt/integration_tests_runner.rs
Normal file
5
cli/rt/integration_tests_runner.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub fn main() {
|
||||
// this file exists to cause the executable to be built when running cargo test
|
||||
}
|
|
@ -1,46 +1,27 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
// Allow unused code warnings because we share
|
||||
// code between the two bin targets.
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod standalone;
|
||||
|
||||
mod args;
|
||||
mod cache;
|
||||
mod emit;
|
||||
mod file_fetcher;
|
||||
mod http_util;
|
||||
mod js;
|
||||
mod node;
|
||||
mod npm;
|
||||
mod resolver;
|
||||
mod shared;
|
||||
mod sys;
|
||||
mod task_runner;
|
||||
mod util;
|
||||
mod version;
|
||||
mod worker;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::env::current_exe;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::CoreError;
|
||||
use deno_core::error::JsError;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_lib::version::otel_runtime_config;
|
||||
use deno_runtime::deno_telemetry::OtelConfig;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||
pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
|
||||
use deno_terminal::colors;
|
||||
use indexmap::IndexMap;
|
||||
use standalone::DenoCompileFileSystem;
|
||||
|
||||
use crate::args::Flags;
|
||||
use crate::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use self::binary::extract_standalone;
|
||||
use self::file_system::DenoRtSys;
|
||||
|
||||
mod binary;
|
||||
mod code_cache;
|
||||
mod file_system;
|
||||
mod node;
|
||||
mod run;
|
||||
|
||||
pub(crate) fn unstable_exit_cb(feature: &str, api_name: &str) {
|
||||
log::error!(
|
||||
|
@ -87,27 +68,26 @@ fn load_env_vars(env_vars: &IndexMap<String, String>) {
|
|||
fn main() {
|
||||
deno_runtime::deno_permissions::mark_standalone();
|
||||
let args: Vec<_> = env::args_os().collect();
|
||||
let standalone = standalone::extract_standalone(Cow::Owned(args));
|
||||
let standalone = extract_standalone(Cow::Owned(args));
|
||||
let future = async move {
|
||||
match standalone {
|
||||
Ok(Some(data)) => {
|
||||
deno_telemetry::init(
|
||||
crate::args::otel_runtime_config(),
|
||||
deno_runtime::deno_telemetry::init(
|
||||
otel_runtime_config(),
|
||||
&data.metadata.otel_config,
|
||||
)?;
|
||||
util::logger::init(
|
||||
init_logging(
|
||||
data.metadata.log_level,
|
||||
Some(data.metadata.otel_config.clone()),
|
||||
);
|
||||
load_env_vars(&data.metadata.env_vars_from_env_file);
|
||||
let fs = DenoCompileFileSystem::new(data.vfs.clone());
|
||||
let sys = crate::sys::CliSys::DenoCompile(fs.clone());
|
||||
let exit_code = standalone::run(Arc::new(fs), sys, data).await?;
|
||||
let sys = DenoRtSys::new(data.vfs.clone());
|
||||
let exit_code = run::run(Arc::new(sys.clone()), sys, data).await?;
|
||||
deno_runtime::exit(exit_code);
|
||||
}
|
||||
Ok(None) => Ok(()),
|
||||
Err(err) => {
|
||||
util::logger::init(None, None);
|
||||
init_logging(None, None);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
@ -115,3 +95,15 @@ fn main() {
|
|||
|
||||
unwrap_or_exit(create_and_run_current_thread_with_maybe_metrics(future));
|
||||
}
|
||||
|
||||
fn init_logging(
|
||||
maybe_level: Option<log::Level>,
|
||||
otel_config: Option<OtelConfig>,
|
||||
) {
|
||||
deno_lib::util::logger::init(deno_lib::util::logger::InitLoggingOptions {
|
||||
maybe_level,
|
||||
otel_config,
|
||||
on_log_start: || {},
|
||||
on_log_end: || {},
|
||||
})
|
||||
}
|
165
cli/rt/node.rs
Normal file
165
cli/rt/node.rs
Normal file
|
@ -0,0 +1,165 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::url::Url;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::loader::NpmModuleLoader;
|
||||
use deno_lib::standalone::binary::CjsExportAnalysisEntry;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmReqResolver;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::analyze::CjsAnalysis;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
|
||||
use crate::binary::StandaloneModules;
|
||||
use crate::file_system::DenoRtSys;
|
||||
|
||||
pub type DenoRtCjsTracker =
|
||||
deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, DenoRtSys>;
|
||||
pub type DenoRtNpmResolver = deno_resolver::npm::NpmResolver<DenoRtSys>;
|
||||
pub type DenoRtNpmModuleLoader = NpmModuleLoader<
|
||||
CjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
pub type DenoRtNodeCodeTranslator = NodeCodeTranslator<
|
||||
CjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
pub type DenoRtNodeResolver = deno_runtime::deno_node::NodeResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
pub type DenoRtNpmReqResolver = NpmReqResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
|
||||
pub struct CjsCodeAnalyzer {
|
||||
cjs_tracker: Arc<DenoRtCjsTracker>,
|
||||
modules: Arc<StandaloneModules>,
|
||||
sys: DenoRtSys,
|
||||
}
|
||||
|
||||
impl CjsCodeAnalyzer {
|
||||
pub fn new(
|
||||
cjs_tracker: Arc<DenoRtCjsTracker>,
|
||||
modules: Arc<StandaloneModules>,
|
||||
sys: DenoRtSys,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_tracker,
|
||||
modules,
|
||||
sys,
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_cjs_analysis<'a>(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
source: Cow<'a, str>,
|
||||
) -> Result<CjsAnalysis<'a>, JsErrorBox> {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
if media_type == MediaType::Json {
|
||||
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
||||
exports: vec![],
|
||||
reexports: vec![],
|
||||
}));
|
||||
}
|
||||
|
||||
let cjs_tracker = self.cjs_tracker.clone();
|
||||
let is_maybe_cjs = cjs_tracker
|
||||
.is_maybe_cjs(specifier, media_type)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let analysis = if is_maybe_cjs {
|
||||
let data = self
|
||||
.modules
|
||||
.read(specifier)?
|
||||
.and_then(|d| d.cjs_export_analysis);
|
||||
match data {
|
||||
Some(data) => {
|
||||
let data: CjsExportAnalysisEntry = bincode::deserialize(&data)
|
||||
.map_err(|err| JsErrorBox::generic(err.to_string()))?;
|
||||
match data {
|
||||
CjsExportAnalysisEntry::Esm => {
|
||||
cjs_tracker.set_is_known_script(specifier, false);
|
||||
CjsAnalysis::Esm(source)
|
||||
}
|
||||
CjsExportAnalysisEntry::Cjs(analysis) => {
|
||||
cjs_tracker.set_is_known_script(specifier, true);
|
||||
CjsAnalysis::Cjs(analysis)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if log::log_enabled!(log::Level::Debug) {
|
||||
if self.sys.is_specifier_in_vfs(specifier) {
|
||||
log::debug!(
|
||||
"No CJS export analysis was stored for '{}'. Assuming ESM. This might indicate a bug in Deno.",
|
||||
specifier
|
||||
);
|
||||
} else {
|
||||
log::debug!(
|
||||
"Analyzing potentially CommonJS files is not supported at runtime in a compiled executable ({}). Assuming ESM.",
|
||||
specifier
|
||||
);
|
||||
}
|
||||
}
|
||||
// assume ESM as we don't have access to swc here
|
||||
CjsAnalysis::Esm(source)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CjsAnalysis::Esm(source)
|
||||
};
|
||||
|
||||
Ok(analysis)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl node_resolver::analyze::CjsCodeAnalyzer for CjsCodeAnalyzer {
|
||||
async fn analyze_cjs<'a>(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
source: Option<Cow<'a, str>>,
|
||||
) -> Result<CjsAnalysis<'a>, JsErrorBox> {
|
||||
let source = match source {
|
||||
Some(source) => source,
|
||||
None => {
|
||||
if let Ok(path) = deno_path_util::url_to_file_path(specifier) {
|
||||
// todo(dsherret): should this use the sync method instead?
|
||||
if let Ok(source_from_file) =
|
||||
self.sys.read_text_file_lossy_async(path, None).await
|
||||
{
|
||||
source_from_file
|
||||
} else {
|
||||
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
||||
exports: vec![],
|
||||
reexports: vec![],
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
||||
exports: vec![],
|
||||
reexports: vec![],
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
self.inner_cjs_analysis(specifier, source)
|
||||
}
|
||||
}
|
990
cli/rt/run.rs
Normal file
990
cli/rt/run.rs
Normal file
|
@ -0,0 +1,990 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_config::workspace::ResolverWorkspaceJsrPackage;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::ModuleLoaderError;
|
||||
use deno_core::futures::future::LocalBoxFuture;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::v8_set_flags;
|
||||
use deno_core::FastString;
|
||||
use deno_core::FeatureChecker;
|
||||
use deno_core::ModuleLoader;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleType;
|
||||
use deno_core::RequestedModuleType;
|
||||
use deno_core::ResolutionKind;
|
||||
use deno_core::SourceCodeCacheInfo;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::args::get_root_cert_store;
|
||||
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::RootCertStoreLoadError;
|
||||
use deno_lib::loader::NpmModuleLoader;
|
||||
use deno_lib::npm::create_npm_process_state_provider;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionChecker;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
|
||||
use deno_lib::standalone::binary::NodeModules;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lib::util::text_encoding::from_utf8_lossy_cow;
|
||||
use deno_lib::util::text_encoding::from_utf8_lossy_owned;
|
||||
use deno_lib::util::v8::construct_v8_flags;
|
||||
use deno_lib::worker::CreateModuleLoaderResult;
|
||||
use deno_lib::worker::LibMainWorkerFactory;
|
||||
use deno_lib::worker::LibMainWorkerOptions;
|
||||
use deno_lib::worker::ModuleLoaderFactory;
|
||||
use deno_lib::worker::StorageKeyResolver;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm::resolution::NpmResolutionSnapshot;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_resolver::cjs::CjsTracker;
|
||||
use deno_resolver::cjs::IsCjsResolutionMode;
|
||||
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
|
||||
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
|
||||
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmReqResolver;
|
||||
use deno_resolver::npm::NpmReqResolverOptions;
|
||||
use deno_resolver::npm::NpmResolver;
|
||||
use deno_resolver::npm::NpmResolverCreateOptions;
|
||||
use deno_runtime::code_cache::CodeCache;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::create_host_defined_options;
|
||||
use deno_runtime::deno_node::NodeRequireLoader;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::NodeResolver;
|
||||
use node_resolver::PackageJsonResolver;
|
||||
use node_resolver::ResolutionMode;
|
||||
|
||||
use crate::binary::DenoCompileModuleSource;
|
||||
use crate::binary::StandaloneData;
|
||||
use crate::binary::StandaloneModules;
|
||||
use crate::code_cache::DenoCompileCodeCache;
|
||||
use crate::file_system::DenoRtSys;
|
||||
use crate::file_system::FileBackedVfs;
|
||||
use crate::node::CjsCodeAnalyzer;
|
||||
use crate::node::DenoRtCjsTracker;
|
||||
use crate::node::DenoRtNodeCodeTranslator;
|
||||
use crate::node::DenoRtNodeResolver;
|
||||
use crate::node::DenoRtNpmModuleLoader;
|
||||
use crate::node::DenoRtNpmReqResolver;
|
||||
|
||||
struct SharedModuleLoaderState {
|
||||
cjs_tracker: Arc<DenoRtCjsTracker>,
|
||||
code_cache: Option<Arc<DenoCompileCodeCache>>,
|
||||
modules: Arc<StandaloneModules>,
|
||||
node_code_translator: Arc<DenoRtNodeCodeTranslator>,
|
||||
node_resolver: Arc<DenoRtNodeResolver>,
|
||||
npm_module_loader: Arc<DenoRtNpmModuleLoader>,
|
||||
npm_registry_permission_checker: NpmRegistryReadPermissionChecker<DenoRtSys>,
|
||||
npm_req_resolver: Arc<DenoRtNpmReqResolver>,
|
||||
vfs: Arc<FileBackedVfs>,
|
||||
workspace_resolver: WorkspaceResolver,
|
||||
}
|
||||
|
||||
impl SharedModuleLoaderState {
|
||||
fn get_code_cache(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
source: &[u8],
|
||||
) -> Option<SourceCodeCacheInfo> {
|
||||
let Some(code_cache) = &self.code_cache else {
|
||||
return None;
|
||||
};
|
||||
if !code_cache.enabled() {
|
||||
return None;
|
||||
}
|
||||
// deno version is already included in the root cache key
|
||||
let hash = FastInsecureHasher::new_without_deno_version()
|
||||
.write_hashable(source)
|
||||
.finish();
|
||||
let data = code_cache.get_sync(
|
||||
specifier,
|
||||
deno_runtime::code_cache::CodeCacheType::EsModule,
|
||||
hash,
|
||||
);
|
||||
Some(SourceCodeCacheInfo {
|
||||
hash,
|
||||
data: data.map(Cow::Owned),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct EmbeddedModuleLoader {
|
||||
shared: Arc<SharedModuleLoaderState>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EmbeddedModuleLoader {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EmbeddedModuleLoader").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleLoader for EmbeddedModuleLoader {
|
||||
fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer: &str,
|
||||
kind: ResolutionKind,
|
||||
) -> Result<Url, ModuleLoaderError> {
|
||||
let referrer = if referrer == "." {
|
||||
if kind != ResolutionKind::MainModule {
|
||||
return Err(
|
||||
JsErrorBox::generic(format!(
|
||||
"Expected to resolve main module, got {:?} instead.",
|
||||
kind
|
||||
))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
deno_core::resolve_path(".", ¤t_dir)?
|
||||
} else {
|
||||
Url::parse(referrer).map_err(|err| {
|
||||
JsErrorBox::type_error(format!(
|
||||
"Referrer uses invalid specifier: {}",
|
||||
err
|
||||
))
|
||||
})?
|
||||
};
|
||||
let referrer_kind = if self
|
||||
.shared
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))
|
||||
.map_err(JsErrorBox::from_err)?
|
||||
{
|
||||
ResolutionMode::Require
|
||||
} else {
|
||||
ResolutionMode::Import
|
||||
};
|
||||
|
||||
if self.shared.node_resolver.in_npm_package(&referrer) {
|
||||
return Ok(
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve(
|
||||
raw_specifier,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?
|
||||
.into_url(),
|
||||
);
|
||||
}
|
||||
|
||||
let mapped_resolution = self
|
||||
.shared
|
||||
.workspace_resolver
|
||||
.resolve(raw_specifier, &referrer);
|
||||
|
||||
match mapped_resolution {
|
||||
Ok(MappedResolution::WorkspaceJsrPackage { specifier, .. }) => {
|
||||
Ok(specifier)
|
||||
}
|
||||
Ok(MappedResolution::WorkspaceNpmPackage {
|
||||
target_pkg_json: pkg_json,
|
||||
sub_path,
|
||||
..
|
||||
}) => Ok(
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve_package_subpath_from_deno_module(
|
||||
pkg_json.dir_path(),
|
||||
sub_path.as_deref(),
|
||||
Some(&referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?,
|
||||
),
|
||||
Ok(MappedResolution::PackageJson {
|
||||
dep_result,
|
||||
sub_path,
|
||||
alias,
|
||||
..
|
||||
}) => match dep_result
|
||||
.as_ref()
|
||||
.map_err(|e| JsErrorBox::from_err(e.clone()))?
|
||||
{
|
||||
PackageJsonDepValue::Req(req) => self
|
||||
.shared
|
||||
.npm_req_resolver
|
||||
.resolve_req_with_sub_path(
|
||||
req,
|
||||
sub_path.as_deref(),
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(|e| JsErrorBox::from_err(e).into()),
|
||||
PackageJsonDepValue::Workspace(version_req) => {
|
||||
let pkg_folder = self
|
||||
.shared
|
||||
.workspace_resolver
|
||||
.resolve_workspace_pkg_json_folder_for_pkg_json_dep(
|
||||
alias,
|
||||
version_req,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
Ok(
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve_package_subpath_from_deno_module(
|
||||
pkg_folder,
|
||||
sub_path.as_deref(),
|
||||
Some(&referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?,
|
||||
)
|
||||
}
|
||||
},
|
||||
Ok(MappedResolution::Normal { specifier, .. })
|
||||
| Ok(MappedResolution::ImportMap { specifier, .. }) => {
|
||||
if let Ok(reference) =
|
||||
NpmPackageReqReference::from_specifier(&specifier)
|
||||
{
|
||||
return Ok(
|
||||
self
|
||||
.shared
|
||||
.npm_req_resolver
|
||||
.resolve_req_reference(
|
||||
&reference,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?,
|
||||
);
|
||||
}
|
||||
|
||||
if specifier.scheme() == "jsr" {
|
||||
if let Some(specifier) = self
|
||||
.shared
|
||||
.modules
|
||||
.resolve_specifier(&specifier)
|
||||
.map_err(JsErrorBox::from_err)?
|
||||
{
|
||||
return Ok(specifier.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.handle_if_in_node_modules(&specifier)
|
||||
.unwrap_or(specifier),
|
||||
)
|
||||
}
|
||||
Err(err)
|
||||
if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" =>
|
||||
{
|
||||
let maybe_res = self
|
||||
.shared
|
||||
.npm_req_resolver
|
||||
.resolve_if_for_npm_pkg(
|
||||
raw_specifier,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
if let Some(res) = maybe_res {
|
||||
return Ok(res.into_url());
|
||||
}
|
||||
Err(JsErrorBox::from_err(err).into())
|
||||
}
|
||||
Err(err) => Err(JsErrorBox::from_err(err).into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_host_defined_options<'s>(
|
||||
&self,
|
||||
scope: &mut deno_core::v8::HandleScope<'s>,
|
||||
name: &str,
|
||||
) -> Option<deno_core::v8::Local<'s, deno_core::v8::Data>> {
|
||||
let name = Url::parse(name).ok()?;
|
||||
if self.shared.node_resolver.in_npm_package(&name) {
|
||||
Some(create_host_defined_options(scope))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn load(
|
||||
&self,
|
||||
original_specifier: &Url,
|
||||
maybe_referrer: Option<&Url>,
|
||||
_is_dynamic: bool,
|
||||
_requested_module_type: RequestedModuleType,
|
||||
) -> deno_core::ModuleLoadResponse {
|
||||
if original_specifier.scheme() == "data" {
|
||||
let data_url_text =
|
||||
match deno_media_type::data_url::RawDataUrl::parse(original_specifier)
|
||||
.and_then(|url| url.decode())
|
||||
{
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
return deno_core::ModuleLoadResponse::Sync(Err(
|
||||
JsErrorBox::type_error(format!("{:#}", err)).into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
return deno_core::ModuleLoadResponse::Sync(Ok(
|
||||
deno_core::ModuleSource::new(
|
||||
deno_core::ModuleType::JavaScript,
|
||||
ModuleSourceCode::String(data_url_text.into()),
|
||||
original_specifier,
|
||||
None,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if self.shared.node_resolver.in_npm_package(original_specifier) {
|
||||
let shared = self.shared.clone();
|
||||
let original_specifier = original_specifier.clone();
|
||||
let maybe_referrer = maybe_referrer.cloned();
|
||||
return deno_core::ModuleLoadResponse::Async(
|
||||
async move {
|
||||
let code_source = shared
|
||||
.npm_module_loader
|
||||
.load(&original_specifier, maybe_referrer.as_ref())
|
||||
.await
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let code_cache_entry = shared.get_code_cache(
|
||||
&code_source.found_url,
|
||||
code_source.code.as_bytes(),
|
||||
);
|
||||
Ok(deno_core::ModuleSource::new_with_redirect(
|
||||
match code_source.media_type {
|
||||
MediaType::Json => ModuleType::Json,
|
||||
_ => ModuleType::JavaScript,
|
||||
},
|
||||
code_source.code,
|
||||
&original_specifier,
|
||||
&code_source.found_url,
|
||||
code_cache_entry,
|
||||
))
|
||||
}
|
||||
.boxed_local(),
|
||||
);
|
||||
}
|
||||
|
||||
match self.shared.modules.read(original_specifier) {
|
||||
Ok(Some(module)) => {
|
||||
let media_type = module.media_type;
|
||||
let (module_specifier, module_type, module_source) =
|
||||
module.into_parts();
|
||||
let is_maybe_cjs = match self
|
||||
.shared
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(original_specifier, media_type)
|
||||
{
|
||||
Ok(is_maybe_cjs) => is_maybe_cjs,
|
||||
Err(err) => {
|
||||
return deno_core::ModuleLoadResponse::Sync(Err(
|
||||
JsErrorBox::type_error(format!("{:?}", err)).into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if is_maybe_cjs {
|
||||
let original_specifier = original_specifier.clone();
|
||||
let module_specifier = module_specifier.clone();
|
||||
let shared = self.shared.clone();
|
||||
deno_core::ModuleLoadResponse::Async(
|
||||
async move {
|
||||
let source = match module_source {
|
||||
DenoCompileModuleSource::String(string) => {
|
||||
Cow::Borrowed(string)
|
||||
}
|
||||
DenoCompileModuleSource::Bytes(module_code_bytes) => {
|
||||
match module_code_bytes {
|
||||
Cow::Owned(bytes) => {
|
||||
Cow::Owned(from_utf8_lossy_owned(bytes))
|
||||
}
|
||||
Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes),
|
||||
}
|
||||
}
|
||||
};
|
||||
let source = shared
|
||||
.node_code_translator
|
||||
.translate_cjs_to_esm(&module_specifier, Some(source))
|
||||
.await
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let module_source = match source {
|
||||
Cow::Owned(source) => ModuleSourceCode::String(source.into()),
|
||||
Cow::Borrowed(source) => {
|
||||
ModuleSourceCode::String(FastString::from_static(source))
|
||||
}
|
||||
};
|
||||
let code_cache_entry = shared
|
||||
.get_code_cache(&module_specifier, module_source.as_bytes());
|
||||
Ok(deno_core::ModuleSource::new_with_redirect(
|
||||
module_type,
|
||||
module_source,
|
||||
&original_specifier,
|
||||
&module_specifier,
|
||||
code_cache_entry,
|
||||
))
|
||||
}
|
||||
.boxed_local(),
|
||||
)
|
||||
} else {
|
||||
let module_source = module_source.into_for_v8();
|
||||
let code_cache_entry = self
|
||||
.shared
|
||||
.get_code_cache(module_specifier, module_source.as_bytes());
|
||||
deno_core::ModuleLoadResponse::Sync(Ok(
|
||||
deno_core::ModuleSource::new_with_redirect(
|
||||
module_type,
|
||||
module_source,
|
||||
original_specifier,
|
||||
module_specifier,
|
||||
code_cache_entry,
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(
|
||||
JsErrorBox::type_error(format!(
|
||||
"Module not found: {}",
|
||||
original_specifier
|
||||
))
|
||||
.into(),
|
||||
)),
|
||||
Err(err) => deno_core::ModuleLoadResponse::Sync(Err(
|
||||
JsErrorBox::type_error(format!("{:?}", err)).into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn code_cache_ready(
|
||||
&self,
|
||||
specifier: Url,
|
||||
source_hash: u64,
|
||||
code_cache_data: &[u8],
|
||||
) -> LocalBoxFuture<'static, ()> {
|
||||
if let Some(code_cache) = &self.shared.code_cache {
|
||||
code_cache.set_sync(
|
||||
specifier,
|
||||
deno_runtime::code_cache::CodeCacheType::EsModule,
|
||||
source_hash,
|
||||
code_cache_data,
|
||||
);
|
||||
}
|
||||
std::future::ready(()).boxed_local()
|
||||
}
|
||||
|
||||
fn get_source_map(&self, file_name: &str) -> Option<Cow<[u8]>> {
|
||||
let url = Url::parse(file_name).ok()?;
|
||||
let data = self.shared.modules.read(&url).ok()??;
|
||||
data.source_map
|
||||
}
|
||||
|
||||
fn get_source_mapped_source_line(
|
||||
&self,
|
||||
file_name: &str,
|
||||
line_number: usize,
|
||||
) -> Option<String> {
|
||||
let specifier = Url::parse(file_name).ok()?;
|
||||
let data = self.shared.modules.read(&specifier).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 {
|
||||
fn ensure_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn deno_runtime::deno_node::NodePermissions,
|
||||
path: &'a std::path::Path,
|
||||
) -> Result<Cow<'a, std::path::Path>, JsErrorBox> {
|
||||
if self.shared.modules.has_file(path) {
|
||||
// allow reading if the file is in the snapshot
|
||||
return Ok(Cow::Borrowed(path));
|
||||
}
|
||||
|
||||
self
|
||||
.shared
|
||||
.npm_registry_permission_checker
|
||||
.ensure_read_permission(permissions, path)
|
||||
.map_err(JsErrorBox::from_err)
|
||||
}
|
||||
|
||||
fn load_text_file_lossy(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
) -> Result<Cow<'static, str>, JsErrorBox> {
|
||||
let file_entry = self
|
||||
.shared
|
||||
.vfs
|
||||
.file_entry(path)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let file_bytes = self
|
||||
.shared
|
||||
.vfs
|
||||
.read_file_offset_with_len(
|
||||
file_entry.transpiled_offset.unwrap_or(file_entry.offset),
|
||||
)
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
Ok(from_utf8_lossy_cow(file_bytes))
|
||||
}
|
||||
|
||||
fn is_maybe_cjs(&self, specifier: &Url) -> Result<bool, ClosestPkgJsonError> {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
self.shared.cjs_tracker.is_maybe_cjs(specifier, media_type)
|
||||
}
|
||||
}
|
||||
|
||||
struct StandaloneModuleLoaderFactory {
|
||||
shared: Arc<SharedModuleLoaderState>,
|
||||
}
|
||||
|
||||
impl StandaloneModuleLoaderFactory {
|
||||
pub fn create_result(&self) -> CreateModuleLoaderResult {
|
||||
let loader = Rc::new(EmbeddedModuleLoader {
|
||||
shared: self.shared.clone(),
|
||||
});
|
||||
CreateModuleLoaderResult {
|
||||
module_loader: loader.clone(),
|
||||
node_require_loader: loader,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleLoaderFactory for StandaloneModuleLoaderFactory {
|
||||
fn create_for_main(
|
||||
&self,
|
||||
_root_permissions: PermissionsContainer,
|
||||
) -> CreateModuleLoaderResult {
|
||||
self.create_result()
|
||||
}
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
_parent_permissions: PermissionsContainer,
|
||||
_permissions: PermissionsContainer,
|
||||
) -> CreateModuleLoaderResult {
|
||||
self.create_result()
|
||||
}
|
||||
}
|
||||
|
||||
struct StandaloneRootCertStoreProvider {
|
||||
ca_stores: Option<Vec<String>>,
|
||||
ca_data: Option<CaData>,
|
||||
cell: OnceLock<Result<RootCertStore, RootCertStoreLoadError>>,
|
||||
}
|
||||
|
||||
impl RootCertStoreProvider for StandaloneRootCertStoreProvider {
|
||||
fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> {
|
||||
self
|
||||
.cell
|
||||
// get_or_try_init was not stable yet when this was written
|
||||
.get_or_init(|| {
|
||||
get_root_cert_store(None, self.ca_stores.clone(), self.ca_data.clone())
|
||||
})
|
||||
.as_ref()
|
||||
.map_err(|err| JsErrorBox::from_err(err.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(
|
||||
fs: Arc<dyn FileSystem>,
|
||||
sys: DenoRtSys,
|
||||
data: StandaloneData,
|
||||
) -> Result<i32, AnyError> {
|
||||
let StandaloneData {
|
||||
metadata,
|
||||
modules,
|
||||
npm_snapshot,
|
||||
root_path,
|
||||
vfs,
|
||||
} = data;
|
||||
let root_cert_store_provider = Arc::new(StandaloneRootCertStoreProvider {
|
||||
ca_stores: metadata.ca_stores,
|
||||
ca_data: metadata.ca_data.map(CaData::Bytes),
|
||||
cell: Default::default(),
|
||||
});
|
||||
// use a dummy npm registry url
|
||||
let npm_registry_url = Url::parse("https://localhost/").unwrap();
|
||||
let root_dir_url = Arc::new(Url::from_directory_path(&root_path).unwrap());
|
||||
let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap();
|
||||
let npm_global_cache_dir = root_path.join(".deno_compile_node_modules");
|
||||
let pkg_json_resolver = Arc::new(PackageJsonResolver::new(sys.clone()));
|
||||
let npm_registry_permission_checker = {
|
||||
let mode = match &metadata.node_modules {
|
||||
Some(NodeModules::Managed {
|
||||
node_modules_dir: Some(path),
|
||||
}) => NpmRegistryReadPermissionCheckerMode::Local(PathBuf::from(path)),
|
||||
Some(NodeModules::Byonm { .. }) => {
|
||||
NpmRegistryReadPermissionCheckerMode::Byonm
|
||||
}
|
||||
Some(NodeModules::Managed {
|
||||
node_modules_dir: None,
|
||||
})
|
||||
| None => NpmRegistryReadPermissionCheckerMode::Global(
|
||||
npm_global_cache_dir.clone(),
|
||||
),
|
||||
};
|
||||
NpmRegistryReadPermissionChecker::new(sys.clone(), mode)
|
||||
};
|
||||
let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules {
|
||||
Some(NodeModules::Managed { node_modules_dir }) => {
|
||||
// create an npmrc that uses the fake npm_registry_url to resolve packages
|
||||
let npmrc = Arc::new(ResolvedNpmRc {
|
||||
default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
|
||||
registry_url: npm_registry_url.clone(),
|
||||
config: Default::default(),
|
||||
},
|
||||
scopes: Default::default(),
|
||||
registry_configs: Default::default(),
|
||||
});
|
||||
let npm_cache_dir = Arc::new(NpmCacheDir::new(
|
||||
&sys,
|
||||
npm_global_cache_dir,
|
||||
npmrc.get_all_known_registries_urls(),
|
||||
));
|
||||
let snapshot = npm_snapshot.unwrap();
|
||||
let maybe_node_modules_path = node_modules_dir
|
||||
.map(|node_modules_dir| root_path.join(node_modules_dir));
|
||||
let in_npm_pkg_checker =
|
||||
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed(
|
||||
ManagedInNpmPkgCheckerCreateOptions {
|
||||
root_cache_dir_url: npm_cache_dir.root_dir_url(),
|
||||
maybe_node_modules_path: maybe_node_modules_path.as_deref(),
|
||||
},
|
||||
));
|
||||
let npm_resolution =
|
||||
Arc::new(NpmResolutionCell::new(NpmResolutionSnapshot::new(snapshot)));
|
||||
let npm_resolver = NpmResolver::<DenoRtSys>::new::<DenoRtSys>(
|
||||
NpmResolverCreateOptions::Managed(ManagedNpmResolverCreateOptions {
|
||||
npm_resolution,
|
||||
npm_cache_dir,
|
||||
sys: sys.clone(),
|
||||
maybe_node_modules_path,
|
||||
npm_system_info: Default::default(),
|
||||
npmrc,
|
||||
}),
|
||||
);
|
||||
(in_npm_pkg_checker, npm_resolver)
|
||||
}
|
||||
Some(NodeModules::Byonm {
|
||||
root_node_modules_dir,
|
||||
}) => {
|
||||
let root_node_modules_dir =
|
||||
root_node_modules_dir.map(|p| vfs.root().join(p));
|
||||
let in_npm_pkg_checker =
|
||||
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm);
|
||||
let npm_resolver = NpmResolver::<DenoRtSys>::new::<DenoRtSys>(
|
||||
NpmResolverCreateOptions::Byonm(ByonmNpmResolverCreateOptions {
|
||||
sys: sys.clone(),
|
||||
pkg_json_resolver: pkg_json_resolver.clone(),
|
||||
root_node_modules_dir,
|
||||
}),
|
||||
);
|
||||
(in_npm_pkg_checker, npm_resolver)
|
||||
}
|
||||
None => {
|
||||
// Packages from different registries are already inlined in the binary,
|
||||
// so no need to create actual `.npmrc` configuration.
|
||||
let npmrc = create_default_npmrc();
|
||||
let npm_cache_dir = Arc::new(NpmCacheDir::new(
|
||||
&sys,
|
||||
npm_global_cache_dir,
|
||||
npmrc.get_all_known_registries_urls(),
|
||||
));
|
||||
let in_npm_pkg_checker =
|
||||
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed(
|
||||
ManagedInNpmPkgCheckerCreateOptions {
|
||||
root_cache_dir_url: npm_cache_dir.root_dir_url(),
|
||||
maybe_node_modules_path: None,
|
||||
},
|
||||
));
|
||||
let npm_resolution = Arc::new(NpmResolutionCell::default());
|
||||
let npm_resolver = NpmResolver::<DenoRtSys>::new::<DenoRtSys>(
|
||||
NpmResolverCreateOptions::Managed(ManagedNpmResolverCreateOptions {
|
||||
npm_resolution,
|
||||
sys: sys.clone(),
|
||||
npm_cache_dir,
|
||||
maybe_node_modules_path: None,
|
||||
npm_system_info: Default::default(),
|
||||
npmrc: create_default_npmrc(),
|
||||
}),
|
||||
);
|
||||
(in_npm_pkg_checker, npm_resolver)
|
||||
}
|
||||
};
|
||||
|
||||
let has_node_modules_dir = npm_resolver.root_node_modules_path().is_some();
|
||||
let node_resolver = Arc::new(NodeResolver::new(
|
||||
in_npm_pkg_checker.clone(),
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
npm_resolver.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
sys.clone(),
|
||||
node_resolver::ConditionsFromResolutionMode::default(),
|
||||
));
|
||||
let cjs_tracker = Arc::new(CjsTracker::new(
|
||||
in_npm_pkg_checker.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
if metadata.unstable_config.detect_cjs {
|
||||
IsCjsResolutionMode::ImplicitTypeCommonJs
|
||||
} else if metadata.workspace_resolver.package_jsons.is_empty() {
|
||||
IsCjsResolutionMode::Disabled
|
||||
} else {
|
||||
IsCjsResolutionMode::ExplicitTypeCommonJs
|
||||
},
|
||||
));
|
||||
let npm_req_resolver = Arc::new(NpmReqResolver::new(NpmReqResolverOptions {
|
||||
sys: sys.clone(),
|
||||
in_npm_pkg_checker: in_npm_pkg_checker.clone(),
|
||||
node_resolver: node_resolver.clone(),
|
||||
npm_resolver: npm_resolver.clone(),
|
||||
}));
|
||||
let cjs_esm_code_analyzer =
|
||||
CjsCodeAnalyzer::new(cjs_tracker.clone(), modules.clone(), sys.clone());
|
||||
let node_code_translator = Arc::new(NodeCodeTranslator::new(
|
||||
cjs_esm_code_analyzer,
|
||||
in_npm_pkg_checker,
|
||||
node_resolver.clone(),
|
||||
npm_resolver.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
sys.clone(),
|
||||
));
|
||||
let workspace_resolver = {
|
||||
let import_map = match metadata.workspace_resolver.import_map {
|
||||
Some(import_map) => Some(
|
||||
import_map::parse_from_json_with_options(
|
||||
root_dir_url.join(&import_map.specifier).unwrap(),
|
||||
&import_map.json,
|
||||
import_map::ImportMapOptions {
|
||||
address_hook: None,
|
||||
expand_imports: true,
|
||||
},
|
||||
)?
|
||||
.import_map,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
let pkg_jsons = metadata
|
||||
.workspace_resolver
|
||||
.package_jsons
|
||||
.into_iter()
|
||||
.map(|(relative_path, json)| {
|
||||
let path = root_dir_url
|
||||
.join(&relative_path)
|
||||
.unwrap()
|
||||
.to_file_path()
|
||||
.unwrap();
|
||||
let pkg_json =
|
||||
deno_package_json::PackageJson::load_from_value(path, json);
|
||||
Arc::new(pkg_json)
|
||||
})
|
||||
.collect();
|
||||
WorkspaceResolver::new_raw(
|
||||
root_dir_url.clone(),
|
||||
import_map,
|
||||
metadata
|
||||
.workspace_resolver
|
||||
.jsr_pkgs
|
||||
.iter()
|
||||
.map(|pkg| ResolverWorkspaceJsrPackage {
|
||||
is_patch: false, // only used for enhancing the diagnostic, which isn't shown in deno compile
|
||||
base: root_dir_url.join(&pkg.relative_base).unwrap(),
|
||||
name: pkg.name.clone(),
|
||||
version: pkg.version.clone(),
|
||||
exports: pkg.exports.clone(),
|
||||
})
|
||||
.collect(),
|
||||
pkg_jsons,
|
||||
metadata.workspace_resolver.pkg_json_resolution,
|
||||
)
|
||||
};
|
||||
let code_cache = match metadata.code_cache_key {
|
||||
Some(code_cache_key) => Some(Arc::new(DenoCompileCodeCache::new(
|
||||
root_path.with_file_name(format!(
|
||||
"{}.cache",
|
||||
root_path.file_name().unwrap().to_string_lossy()
|
||||
)),
|
||||
code_cache_key,
|
||||
))),
|
||||
None => {
|
||||
log::debug!("Code cache disabled.");
|
||||
None
|
||||
}
|
||||
};
|
||||
let module_loader_factory = StandaloneModuleLoaderFactory {
|
||||
shared: Arc::new(SharedModuleLoaderState {
|
||||
cjs_tracker: cjs_tracker.clone(),
|
||||
code_cache: code_cache.clone(),
|
||||
modules,
|
||||
node_code_translator: node_code_translator.clone(),
|
||||
node_resolver: node_resolver.clone(),
|
||||
npm_module_loader: Arc::new(NpmModuleLoader::new(
|
||||
cjs_tracker.clone(),
|
||||
node_code_translator,
|
||||
sys.clone(),
|
||||
)),
|
||||
npm_registry_permission_checker,
|
||||
npm_req_resolver,
|
||||
vfs: vfs.clone(),
|
||||
workspace_resolver,
|
||||
}),
|
||||
};
|
||||
|
||||
let permissions = {
|
||||
let mut permissions = metadata.permissions;
|
||||
// grant read access to the vfs
|
||||
match &mut permissions.allow_read {
|
||||
Some(vec) if vec.is_empty() => {
|
||||
// do nothing, already granted
|
||||
}
|
||||
Some(vec) => {
|
||||
vec.push(root_path.to_string_lossy().to_string());
|
||||
}
|
||||
None => {
|
||||
permissions.allow_read =
|
||||
Some(vec![root_path.to_string_lossy().to_string()]);
|
||||
}
|
||||
}
|
||||
|
||||
let desc_parser =
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(sys.clone()));
|
||||
let permissions =
|
||||
Permissions::from_options(desc_parser.as_ref(), &permissions)?;
|
||||
PermissionsContainer::new(desc_parser, permissions)
|
||||
};
|
||||
let feature_checker = Arc::new({
|
||||
let mut checker = FeatureChecker::default();
|
||||
checker.set_exit_cb(Box::new(crate::unstable_exit_cb));
|
||||
for feature in metadata.unstable_config.features {
|
||||
// `metadata` is valid for the whole lifetime of the program, so we
|
||||
// can leak the string here.
|
||||
checker.enable_feature(feature.leak());
|
||||
}
|
||||
checker
|
||||
});
|
||||
let lib_main_worker_options = LibMainWorkerOptions {
|
||||
argv: metadata.argv,
|
||||
log_level: WorkerLogLevel::Info,
|
||||
enable_op_summary_metrics: false,
|
||||
enable_testing_features: false,
|
||||
has_node_modules_dir,
|
||||
inspect_brk: false,
|
||||
inspect_wait: false,
|
||||
strace_ops: None,
|
||||
is_inspecting: false,
|
||||
skip_op_registration: true,
|
||||
location: metadata.location,
|
||||
argv0: NpmPackageReqReference::from_specifier(&main_module)
|
||||
.ok()
|
||||
.map(|req_ref| npm_pkg_req_ref_to_binary_command(&req_ref))
|
||||
.or(std::env::args().next()),
|
||||
node_debug: std::env::var("NODE_DEBUG").ok(),
|
||||
origin_data_folder_path: None,
|
||||
seed: metadata.seed,
|
||||
unsafely_ignore_certificate_errors: metadata
|
||||
.unsafely_ignore_certificate_errors,
|
||||
node_ipc: None,
|
||||
serve_port: None,
|
||||
serve_host: None,
|
||||
otel_config: metadata.otel_config,
|
||||
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
|
||||
};
|
||||
let worker_factory = LibMainWorkerFactory::new(
|
||||
Arc::new(BlobStore::default()),
|
||||
code_cache.map(|c| c.for_deno_core()),
|
||||
feature_checker,
|
||||
fs,
|
||||
None,
|
||||
Box::new(module_loader_factory),
|
||||
node_resolver.clone(),
|
||||
create_npm_process_state_provider(&npm_resolver),
|
||||
pkg_json_resolver,
|
||||
root_cert_store_provider,
|
||||
StorageKeyResolver::empty(),
|
||||
sys.clone(),
|
||||
lib_main_worker_options,
|
||||
);
|
||||
|
||||
// Initialize v8 once from the main thread.
|
||||
v8_set_flags(construct_v8_flags(&[], &metadata.v8_flags, vec![]));
|
||||
// TODO(bartlomieju): remove last argument once Deploy no longer needs it
|
||||
deno_core::JsRuntime::init_platform(None, true);
|
||||
|
||||
let main_module = match NpmPackageReqReference::from_specifier(&main_module) {
|
||||
Ok(package_ref) => {
|
||||
let pkg_folder = npm_resolver.resolve_pkg_folder_from_deno_module_req(
|
||||
package_ref.req(),
|
||||
&deno_path_util::url_from_file_path(&vfs.root().join("package.json"))?,
|
||||
)?;
|
||||
worker_factory
|
||||
.resolve_npm_binary_entrypoint(&pkg_folder, package_ref.sub_path())?
|
||||
}
|
||||
Err(_) => main_module,
|
||||
};
|
||||
|
||||
let mut worker = worker_factory.create_main_worker(
|
||||
WorkerExecutionMode::Run,
|
||||
permissions,
|
||||
main_module,
|
||||
)?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
}
|
||||
|
||||
fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
|
||||
// this is fine because multiple registries are combined into
|
||||
// one when compiling the binary
|
||||
Arc::new(ResolvedNpmRc {
|
||||
default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
|
||||
registry_url: Url::parse("https://registry.npmjs.org").unwrap(),
|
||||
config: Default::default(),
|
||||
},
|
||||
scopes: Default::default(),
|
||||
registry_configs: Default::default(),
|
||||
})
|
||||
}
|
20
cli/snapshot/Cargo.toml
Normal file
20
cli/snapshot/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
[package]
|
||||
name = "deno_snapshots"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
readme = "README.md"
|
||||
repository.workspace = true
|
||||
description = "v8 snapshot used by the Deno CLI"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
disable = []
|
||||
|
||||
[build-dependencies]
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting", "only_snapshotted_js_sources", "snapshotting"] }
|
3
cli/snapshot/README.md
Normal file
3
cli/snapshot/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# deno_snapshots
|
||||
|
||||
v8 snapshot used in the Deno CLI.
|
30
cli/snapshot/build.rs
Normal file
30
cli/snapshot/build.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
#[cfg(not(feature = "disable"))]
|
||||
mod shared;
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(feature = "disable"))]
|
||||
{
|
||||
let o = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
let cli_snapshot_path = o.join("CLI_SNAPSHOT.bin");
|
||||
create_cli_snapshot(cli_snapshot_path);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "disable"))]
|
||||
fn create_cli_snapshot(snapshot_path: std::path::PathBuf) {
|
||||
use deno_runtime::ops::bootstrap::SnapshotOptions;
|
||||
|
||||
let snapshot_options = SnapshotOptions {
|
||||
ts_version: shared::TS_VERSION.to_string(),
|
||||
v8_version: deno_runtime::deno_core::v8::VERSION_STRING,
|
||||
target: std::env::var("TARGET").unwrap(),
|
||||
};
|
||||
|
||||
deno_runtime::snapshot::create_runtime_snapshot(
|
||||
snapshot_path,
|
||||
snapshot_options,
|
||||
vec![],
|
||||
);
|
||||
}
|
13
cli/snapshot/lib.rs
Normal file
13
cli/snapshot/lib.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
#[cfg(not(feature = "disable"))]
|
||||
pub static CLI_SNAPSHOT: Option<&[u8]> = Some(include_bytes!(concat!(
|
||||
env!("OUT_DIR"),
|
||||
"/CLI_SNAPSHOT.bin"
|
||||
)));
|
||||
#[cfg(feature = "disable")]
|
||||
pub static CLI_SNAPSHOT: Option<&[u8]> = None;
|
||||
|
||||
mod shared;
|
||||
|
||||
pub use shared::TS_VERSION;
|
3
cli/snapshot/shared.rs
Normal file
3
cli/snapshot/shared.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub static TS_VERSION: &str = "5.6.2";
|
|
@ -1,111 +1,70 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::env;
|
||||
use std::env::current_exe;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Read;
|
||||
use std::io::Seek;
|
||||
use std::io::SeekFrom;
|
||||
use std::io::Write;
|
||||
use std::ops::Range;
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
|
||||
use capacity_builder::BytesAppendable;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ModuleKind;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_config::workspace::ResolverWorkspaceJsrPackage;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::io::AllowStdIo;
|
||||
use deno_core::futures::AsyncReadExt;
|
||||
use deno_core::futures::AsyncSeekExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_lib::cache::DenoDir;
|
||||
use deno_lib::standalone::virtual_fs::FileSystemCaseSensitivity;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::UnstableConfig;
|
||||
use deno_lib::shared::ReleaseChannel;
|
||||
use deno_lib::standalone::binary::CjsExportAnalysisEntry;
|
||||
use deno_lib::standalone::binary::Metadata;
|
||||
use deno_lib::standalone::binary::NodeModules;
|
||||
use deno_lib::standalone::binary::RemoteModuleEntry;
|
||||
use deno_lib::standalone::binary::SerializedResolverWorkspaceJsrPackage;
|
||||
use deno_lib::standalone::binary::SerializedWorkspaceResolver;
|
||||
use deno_lib::standalone::binary::SerializedWorkspaceResolverImportMap;
|
||||
use deno_lib::standalone::binary::SpecifierDataStore;
|
||||
use deno_lib::standalone::binary::SpecifierId;
|
||||
use deno_lib::standalone::binary::MAGIC_BYTES;
|
||||
use deno_lib::standalone::virtual_fs::BuiltVfs;
|
||||
use deno_lib::standalone::virtual_fs::VfsBuilder;
|
||||
use deno_lib::standalone::virtual_fs::VfsEntry;
|
||||
use deno_lib::standalone::virtual_fs::VfsFileSubDataKind;
|
||||
use deno_lib::standalone::virtual_fs::VirtualDirectory;
|
||||
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
|
||||
use deno_lib::standalone::virtual_fs::WindowsSystemRootablePath;
|
||||
use deno_lib::standalone::virtual_fs::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmPackageId;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::url_from_directory_path;
|
||||
use deno_path_util::url_from_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_fs::RealFs;
|
||||
use deno_runtime::deno_io::fs::FsError;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use deno_semver::npm::NpmVersionReqParseError;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::Version;
|
||||
use deno_semver::VersionReqSpecifierParseError;
|
||||
use deno_telemetry::OtelConfig;
|
||||
use indexmap::IndexMap;
|
||||
use log::Level;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use node_resolver::analyze::CjsAnalysis;
|
||||
use node_resolver::analyze::CjsCodeAnalyzer;
|
||||
|
||||
use super::file_system::DenoCompileFileSystem;
|
||||
use super::serialization::deserialize_binary_data_section;
|
||||
use super::serialization::serialize_binary_data_section;
|
||||
use super::serialization::DenoCompileModuleData;
|
||||
use super::serialization::DeserializedDataSection;
|
||||
use super::serialization::RemoteModulesStore;
|
||||
use super::serialization::RemoteModulesStoreBuilder;
|
||||
use super::serialization::SourceMapStore;
|
||||
use super::virtual_fs::output_vfs;
|
||||
use super::virtual_fs::BuiltVfs;
|
||||
use super::virtual_fs::FileBackedVfs;
|
||||
use super::virtual_fs::VfsBuilder;
|
||||
use super::virtual_fs::VfsRoot;
|
||||
use crate::args::CaData;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CompileFlags;
|
||||
use crate::args::NpmInstallDepsProvider;
|
||||
use crate::args::PermissionFlags;
|
||||
use crate::args::UnstableConfig;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::DenoDir;
|
||||
use crate::emit::Emitter;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
use crate::node::CliCjsCodeAnalyzer;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliCjsTracker;
|
||||
use crate::shared::ReleaseChannel;
|
||||
use crate::sys::CliSys;
|
||||
use crate::util::archive;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
|
||||
pub static DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME: &str =
|
||||
".deno_compile_node_modules";
|
||||
|
||||
/// A URL that can be designated as the base for relative URLs.
|
||||
///
|
||||
/// After creation, this URL may be used to get the key for a
|
||||
|
@ -151,104 +110,60 @@ impl<'a> StandaloneRelativeFileBaseUrl<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum NodeModules {
|
||||
Managed {
|
||||
/// Relative path for the node_modules directory in the vfs.
|
||||
node_modules_dir: Option<String>,
|
||||
},
|
||||
Byonm {
|
||||
root_node_modules_dir: Option<String>,
|
||||
},
|
||||
struct SpecifierStore<'a> {
|
||||
data: IndexMap<&'a Url, SpecifierId>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct SerializedWorkspaceResolverImportMap {
|
||||
pub specifier: String,
|
||||
pub json: String,
|
||||
impl<'a> SpecifierStore<'a> {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
data: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SerializedResolverWorkspaceJsrPackage {
|
||||
pub relative_base: String,
|
||||
pub name: String,
|
||||
pub version: Option<Version>,
|
||||
pub exports: IndexMap<String, String>,
|
||||
pub fn get_or_add(&mut self, specifier: &'a Url) -> SpecifierId {
|
||||
let len = self.data.len();
|
||||
let entry = self.data.entry(specifier);
|
||||
match entry {
|
||||
indexmap::map::Entry::Occupied(occupied_entry) => *occupied_entry.get(),
|
||||
indexmap::map::Entry::Vacant(vacant_entry) => {
|
||||
let new_id = SpecifierId::new(len as u32);
|
||||
vacant_entry.insert(new_id);
|
||||
new_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct SerializedWorkspaceResolver {
|
||||
pub import_map: Option<SerializedWorkspaceResolverImportMap>,
|
||||
pub jsr_pkgs: Vec<SerializedResolverWorkspaceJsrPackage>,
|
||||
pub package_jsons: BTreeMap<String, serde_json::Value>,
|
||||
pub pkg_json_resolution: PackageJsonDepResolution,
|
||||
pub fn for_serialization(
|
||||
self,
|
||||
base_url: &StandaloneRelativeFileBaseUrl<'a>,
|
||||
) -> SpecifierStoreForSerialization<'a> {
|
||||
SpecifierStoreForSerialization {
|
||||
data: self
|
||||
.data
|
||||
.into_iter()
|
||||
.map(|(specifier, id)| (base_url.specifier_key(specifier), id))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Don't use hashmaps/hashsets. Ensure the serialization
|
||||
// is deterministic.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Metadata {
|
||||
pub argv: Vec<String>,
|
||||
pub seed: Option<u64>,
|
||||
pub code_cache_key: Option<u64>,
|
||||
pub permissions: PermissionsOptions,
|
||||
pub location: Option<Url>,
|
||||
pub v8_flags: Vec<String>,
|
||||
pub log_level: Option<Level>,
|
||||
pub ca_stores: Option<Vec<String>>,
|
||||
pub ca_data: Option<Vec<u8>>,
|
||||
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
||||
pub env_vars_from_env_file: IndexMap<String, String>,
|
||||
pub workspace_resolver: SerializedWorkspaceResolver,
|
||||
pub entrypoint_key: String,
|
||||
pub node_modules: Option<NodeModules>,
|
||||
pub unstable_config: UnstableConfig,
|
||||
pub otel_config: OtelConfig,
|
||||
pub vfs_case_sensitivity: FileSystemCaseSensitivity,
|
||||
struct SpecifierStoreForSerialization<'a> {
|
||||
data: Vec<(Cow<'a, str>, SpecifierId)>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn write_binary_bytes(
|
||||
mut file_writer: File,
|
||||
original_bin: Vec<u8>,
|
||||
metadata: &Metadata,
|
||||
npm_snapshot: Option<SerializedNpmResolutionSnapshot>,
|
||||
remote_modules: &RemoteModulesStoreBuilder,
|
||||
source_map_store: &SourceMapStore,
|
||||
vfs: &BuiltVfs,
|
||||
compile_flags: &CompileFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
let data_section_bytes = serialize_binary_data_section(
|
||||
metadata,
|
||||
npm_snapshot,
|
||||
remote_modules,
|
||||
source_map_store,
|
||||
vfs,
|
||||
)
|
||||
.context("Serializing binary data section.")?;
|
||||
|
||||
let target = compile_flags.resolve_target();
|
||||
if target.contains("linux") {
|
||||
libsui::Elf::new(&original_bin).append(
|
||||
"d3n0l4nd",
|
||||
&data_section_bytes,
|
||||
&mut file_writer,
|
||||
)?;
|
||||
} else if target.contains("windows") {
|
||||
let mut pe = libsui::PortableExecutable::from(&original_bin)?;
|
||||
if let Some(icon) = compile_flags.icon.as_ref() {
|
||||
let icon = std::fs::read(icon)?;
|
||||
pe = pe.set_icon(&icon)?;
|
||||
impl<'a> BytesAppendable<'a> for &'a SpecifierStoreForSerialization<'a> {
|
||||
fn append_to_builder<TBytes: capacity_builder::BytesType>(
|
||||
self,
|
||||
builder: &mut capacity_builder::BytesBuilder<'a, TBytes>,
|
||||
) {
|
||||
builder.append_le(self.data.len() as u32);
|
||||
for (specifier_str, id) in &self.data {
|
||||
builder.append_le(specifier_str.len() as u32);
|
||||
builder.append(specifier_str.as_ref());
|
||||
builder.append(*id);
|
||||
}
|
||||
|
||||
pe.write_resource("d3n0l4nd", data_section_bytes)?
|
||||
.build(&mut file_writer)?;
|
||||
} else if target.contains("darwin") {
|
||||
libsui::Macho::from(original_bin)?
|
||||
.write_section("d3n0l4nd", data_section_bytes)?
|
||||
.build_and_sign(&mut file_writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_standalone_binary(exe_path: &Path) -> bool {
|
||||
|
@ -261,146 +176,6 @@ pub fn is_standalone_binary(exe_path: &Path) -> bool {
|
|||
|| libsui::utils::is_macho(&data)
|
||||
}
|
||||
|
||||
pub struct StandaloneData {
|
||||
pub metadata: Metadata,
|
||||
pub modules: StandaloneModules,
|
||||
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
|
||||
pub root_path: PathBuf,
|
||||
pub source_maps: SourceMapStore,
|
||||
pub vfs: Arc<FileBackedVfs>,
|
||||
}
|
||||
|
||||
pub struct StandaloneModules {
|
||||
remote_modules: RemoteModulesStore,
|
||||
vfs: Arc<FileBackedVfs>,
|
||||
}
|
||||
|
||||
impl StandaloneModules {
|
||||
pub fn resolve_specifier<'a>(
|
||||
&'a self,
|
||||
specifier: &'a ModuleSpecifier,
|
||||
) -> Result<Option<&'a ModuleSpecifier>, JsErrorBox> {
|
||||
if specifier.scheme() == "file" {
|
||||
Ok(Some(specifier))
|
||||
} else {
|
||||
self.remote_modules.resolve_specifier(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_file(&self, path: &Path) -> bool {
|
||||
self.vfs.file_entry(path).is_ok()
|
||||
}
|
||||
|
||||
pub fn read<'a>(
|
||||
&'a self,
|
||||
specifier: &'a ModuleSpecifier,
|
||||
kind: VfsFileSubDataKind,
|
||||
) -> Result<Option<DenoCompileModuleData<'a>>, AnyError> {
|
||||
if specifier.scheme() == "file" {
|
||||
let path = deno_path_util::url_to_file_path(specifier)?;
|
||||
let bytes = match self.vfs.file_entry(&path) {
|
||||
Ok(entry) => self.vfs.read_file_all(entry, kind)?,
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => {
|
||||
match RealFs.read_file_sync(&path, None) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(FsError::Io(err)) if err.kind() == ErrorKind::NotFound => {
|
||||
return Ok(None)
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
Ok(Some(DenoCompileModuleData {
|
||||
media_type: MediaType::from_specifier(specifier),
|
||||
specifier,
|
||||
data: bytes,
|
||||
}))
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function will try to run this binary as a standalone binary
|
||||
/// produced by `deno compile`. It determines if this is a standalone
|
||||
/// binary by skipping over the trailer width at the end of the file,
|
||||
/// then checking for the magic trailer string `d3n0l4nd`. If found,
|
||||
/// the bundle is executed. If not, this function exits with `Ok(None)`.
|
||||
pub fn extract_standalone(
|
||||
cli_args: Cow<Vec<OsString>>,
|
||||
) -> Result<Option<StandaloneData>, AnyError> {
|
||||
let Some(data) = libsui::find_section("d3n0l4nd") else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let DeserializedDataSection {
|
||||
mut metadata,
|
||||
npm_snapshot,
|
||||
remote_modules,
|
||||
source_maps,
|
||||
vfs_root_entries,
|
||||
vfs_files_data,
|
||||
} = match deserialize_binary_data_section(data)? {
|
||||
Some(data_section) => data_section,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let root_path = {
|
||||
let maybe_current_exe = std::env::current_exe().ok();
|
||||
let current_exe_name = maybe_current_exe
|
||||
.as_ref()
|
||||
.and_then(|p| p.file_name())
|
||||
.map(|p| p.to_string_lossy())
|
||||
// should never happen
|
||||
.unwrap_or_else(|| Cow::Borrowed("binary"));
|
||||
std::env::temp_dir().join(format!("deno-compile-{}", current_exe_name))
|
||||
};
|
||||
let cli_args = cli_args.into_owned();
|
||||
metadata.argv.reserve(cli_args.len() - 1);
|
||||
for arg in cli_args.into_iter().skip(1) {
|
||||
metadata.argv.push(arg.into_string().unwrap());
|
||||
}
|
||||
let vfs = {
|
||||
let fs_root = VfsRoot {
|
||||
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(),
|
||||
start_file_offset: 0,
|
||||
};
|
||||
Arc::new(FileBackedVfs::new(
|
||||
Cow::Borrowed(vfs_files_data),
|
||||
fs_root,
|
||||
metadata.vfs_case_sensitivity,
|
||||
))
|
||||
};
|
||||
Ok(Some(StandaloneData {
|
||||
metadata,
|
||||
modules: StandaloneModules {
|
||||
remote_modules,
|
||||
vfs: vfs.clone(),
|
||||
},
|
||||
npm_snapshot,
|
||||
root_path,
|
||||
source_maps,
|
||||
vfs,
|
||||
}))
|
||||
}
|
||||
|
||||
pub struct WriteBinOptions<'a> {
|
||||
pub writer: File,
|
||||
pub display_output_filename: &'a str,
|
||||
|
@ -411,11 +186,11 @@ pub struct WriteBinOptions<'a> {
|
|||
}
|
||||
|
||||
pub struct DenoCompileBinaryWriter<'a> {
|
||||
cjs_code_analyzer: CliCjsCodeAnalyzer,
|
||||
cjs_tracker: &'a CliCjsTracker,
|
||||
cli_options: &'a CliOptions,
|
||||
deno_dir: &'a DenoDir<CliSys>,
|
||||
deno_dir: &'a DenoDir,
|
||||
emitter: &'a Emitter,
|
||||
file_fetcher: &'a CliFileFetcher,
|
||||
http_client_provider: &'a HttpClientProvider,
|
||||
npm_resolver: &'a CliNpmResolver,
|
||||
workspace_resolver: &'a WorkspaceResolver,
|
||||
|
@ -425,22 +200,22 @@ pub struct DenoCompileBinaryWriter<'a> {
|
|||
impl<'a> DenoCompileBinaryWriter<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
cjs_code_analyzer: CliCjsCodeAnalyzer,
|
||||
cjs_tracker: &'a CliCjsTracker,
|
||||
cli_options: &'a CliOptions,
|
||||
deno_dir: &'a DenoDir<CliSys>,
|
||||
deno_dir: &'a DenoDir,
|
||||
emitter: &'a Emitter,
|
||||
file_fetcher: &'a CliFileFetcher,
|
||||
http_client_provider: &'a HttpClientProvider,
|
||||
npm_resolver: &'a CliNpmResolver,
|
||||
workspace_resolver: &'a WorkspaceResolver,
|
||||
npm_system_info: NpmSystemInfo,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_code_analyzer,
|
||||
cjs_tracker,
|
||||
cli_options,
|
||||
deno_dir,
|
||||
emitter,
|
||||
file_fetcher,
|
||||
http_client_provider,
|
||||
npm_resolver,
|
||||
workspace_resolver,
|
||||
|
@ -476,7 +251,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
self.write_standalone_binary(options, original_binary)
|
||||
self.write_standalone_binary(options, original_binary).await
|
||||
}
|
||||
|
||||
async fn get_base_binary(
|
||||
|
@ -496,17 +271,12 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
let target = compile_flags.resolve_target();
|
||||
let binary_name = format!("denort-{target}.zip");
|
||||
|
||||
let binary_path_suffix =
|
||||
match crate::version::DENO_VERSION_INFO.release_channel {
|
||||
let binary_path_suffix = match DENO_VERSION_INFO.release_channel {
|
||||
ReleaseChannel::Canary => {
|
||||
format!(
|
||||
"canary/{}/{}",
|
||||
crate::version::DENO_VERSION_INFO.git_hash,
|
||||
binary_name
|
||||
)
|
||||
format!("canary/{}/{}", DENO_VERSION_INFO.git_hash, binary_name)
|
||||
}
|
||||
_ => {
|
||||
format!("release/v{}/{}", env!("CARGO_PKG_VERSION"), binary_name)
|
||||
format!("release/v{}/{}", DENO_VERSION_INFO.deno, binary_name)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -579,7 +349,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
/// This functions creates a standalone deno binary by appending a bundle
|
||||
/// and magic trailer to the currently executing binary.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn write_standalone_binary(
|
||||
async fn write_standalone_binary(
|
||||
&self,
|
||||
options: WriteBinOptions<'_>,
|
||||
original_bin: Vec<u8>,
|
||||
|
@ -623,23 +393,50 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
.add_file_at_path(&path)
|
||||
.with_context(|| format!("Including {}", path.display()))?;
|
||||
}
|
||||
let mut remote_modules_store = RemoteModulesStoreBuilder::default();
|
||||
let mut source_maps = Vec::with_capacity(graph.specifiers_count());
|
||||
// todo(dsherret): transpile in parallel
|
||||
let specifiers_count = graph.specifiers_count();
|
||||
let mut specifier_store = SpecifierStore::with_capacity(specifiers_count);
|
||||
let mut remote_modules_store =
|
||||
SpecifierDataStore::with_capacity(specifiers_count);
|
||||
// todo(dsherret): transpile and analyze CJS in parallel
|
||||
for module in graph.modules() {
|
||||
if module.specifier().scheme() == "data" {
|
||||
continue; // don't store data urls as an entry as they're in the code
|
||||
}
|
||||
let (maybe_original_source, maybe_transpiled, media_type) = match module {
|
||||
let mut maybe_source_map = None;
|
||||
let mut maybe_transpiled = None;
|
||||
let mut maybe_cjs_analysis = None;
|
||||
let (maybe_original_source, media_type) = match module {
|
||||
deno_graph::Module::Js(m) => {
|
||||
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(
|
||||
&m.specifier,
|
||||
let specifier = &m.specifier;
|
||||
let original_bytes = m.source.as_bytes();
|
||||
if self.cjs_tracker.is_maybe_cjs(specifier, m.media_type)? {
|
||||
if self.cjs_tracker.is_cjs_with_known_is_script(
|
||||
specifier,
|
||||
m.media_type,
|
||||
m.is_script,
|
||||
)?;
|
||||
let module_kind = ModuleKind::from_is_cjs(is_cjs);
|
||||
)? {
|
||||
let cjs_analysis = self
|
||||
.cjs_code_analyzer
|
||||
.analyze_cjs(
|
||||
module.specifier(),
|
||||
Some(Cow::Borrowed(m.source.as_ref())),
|
||||
)
|
||||
.await?;
|
||||
maybe_cjs_analysis = Some(match cjs_analysis {
|
||||
CjsAnalysis::Esm(_) => CjsExportAnalysisEntry::Esm,
|
||||
CjsAnalysis::Cjs(exports) => {
|
||||
CjsExportAnalysisEntry::Cjs(exports)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
maybe_cjs_analysis = Some(CjsExportAnalysisEntry::Esm);
|
||||
}
|
||||
}
|
||||
if m.media_type.is_emittable() {
|
||||
let module_kind = match maybe_cjs_analysis.as_ref() {
|
||||
Some(CjsExportAnalysisEntry::Cjs(_)) => ModuleKind::Cjs,
|
||||
_ => ModuleKind::Esm,
|
||||
};
|
||||
let (source, source_map) =
|
||||
self.emitter.emit_parsed_source_for_deno_compile(
|
||||
&m.specifier,
|
||||
|
@ -648,60 +445,67 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
&m.source,
|
||||
)?;
|
||||
if source != m.source.as_ref() {
|
||||
source_maps.push((&m.specifier, source_map));
|
||||
Some(source.into_bytes())
|
||||
} else {
|
||||
None
|
||||
maybe_source_map = Some(source_map.into_bytes());
|
||||
maybe_transpiled = Some(source.into_bytes());
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(Some(original_bytes), maybe_transpiled, m.media_type)
|
||||
}
|
||||
(Some(original_bytes), m.media_type)
|
||||
}
|
||||
deno_graph::Module::Json(m) => {
|
||||
(Some(m.source.as_bytes().to_vec()), None, m.media_type)
|
||||
(Some(m.source.as_bytes()), m.media_type)
|
||||
}
|
||||
deno_graph::Module::Wasm(m) => {
|
||||
(Some(m.source.to_vec()), None, MediaType::Wasm)
|
||||
(Some(m.source.as_ref()), MediaType::Wasm)
|
||||
}
|
||||
deno_graph::Module::Npm(_)
|
||||
| deno_graph::Module::Node(_)
|
||||
| deno_graph::Module::External(_) => (None, None, MediaType::Unknown),
|
||||
| deno_graph::Module::External(_) => (None, MediaType::Unknown),
|
||||
};
|
||||
if let Some(original_source) = maybe_original_source {
|
||||
let maybe_cjs_export_analysis = maybe_cjs_analysis
|
||||
.as_ref()
|
||||
.map(bincode::serialize)
|
||||
.transpose()?;
|
||||
if module.specifier().scheme() == "file" {
|
||||
let file_path = deno_path_util::url_to_file_path(module.specifier())?;
|
||||
vfs
|
||||
.add_file_with_data(
|
||||
&file_path,
|
||||
original_source,
|
||||
VfsFileSubDataKind::Raw,
|
||||
)
|
||||
.with_context(|| {
|
||||
format!("Failed adding '{}'", file_path.display())
|
||||
})?;
|
||||
if let Some(transpiled_source) = maybe_transpiled {
|
||||
vfs
|
||||
.add_file_with_data(
|
||||
&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,
|
||||
deno_lib::standalone::virtual_fs::AddFileDataOptions {
|
||||
data: original_source.to_vec(),
|
||||
maybe_transpiled,
|
||||
maybe_source_map,
|
||||
maybe_cjs_export_analysis,
|
||||
},
|
||||
)
|
||||
.with_context(|| {
|
||||
format!("Failed adding '{}'", file_path.display())
|
||||
})?;
|
||||
} else {
|
||||
let specifier_id = specifier_store.get_or_add(module.specifier());
|
||||
remote_modules_store.add(
|
||||
specifier_id,
|
||||
RemoteModuleEntry {
|
||||
media_type,
|
||||
data: Cow::Borrowed(original_source),
|
||||
maybe_transpiled: maybe_transpiled.map(Cow::Owned),
|
||||
maybe_source_map: maybe_source_map.map(Cow::Owned),
|
||||
maybe_cjs_export_analysis: maybe_cjs_export_analysis
|
||||
.map(Cow::Owned),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
remote_modules_store.add_redirects(&graph.redirects);
|
||||
|
||||
let mut redirects_store =
|
||||
SpecifierDataStore::with_capacity(graph.redirects.len());
|
||||
for (from, to) in &graph.redirects {
|
||||
redirects_store.add(
|
||||
specifier_store.get_or_add(from),
|
||||
specifier_store.get_or_add(to),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(import_map) = self.workspace_resolver.maybe_import_map() {
|
||||
if let Ok(file_path) = url_to_file_path(import_map.base_url()) {
|
||||
|
@ -719,7 +523,48 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// do CJS export analysis on all the files in the VFS
|
||||
// todo(dsherret): analyze cjs in parallel
|
||||
let mut to_add = Vec::new();
|
||||
for (file_path, file) in vfs.iter_files() {
|
||||
if file.cjs_export_analysis_offset.is_some() {
|
||||
continue; // already analyzed
|
||||
}
|
||||
let specifier = deno_path_util::url_from_file_path(&file_path)?;
|
||||
let media_type = MediaType::from_specifier(&specifier);
|
||||
if self.cjs_tracker.is_maybe_cjs(&specifier, media_type)? {
|
||||
let maybe_source = vfs
|
||||
.file_bytes(file.offset)
|
||||
.map(|text| String::from_utf8_lossy(text));
|
||||
let cjs_analysis_result = self
|
||||
.cjs_code_analyzer
|
||||
.analyze_cjs(&specifier, maybe_source)
|
||||
.await;
|
||||
let maybe_analysis = match cjs_analysis_result {
|
||||
Ok(CjsAnalysis::Esm(_)) => Some(CjsExportAnalysisEntry::Esm),
|
||||
Ok(CjsAnalysis::Cjs(exports)) => {
|
||||
Some(CjsExportAnalysisEntry::Cjs(exports))
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!(
|
||||
"Ignoring cjs export analysis for '{}': {}",
|
||||
specifier,
|
||||
err
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some(analysis) = &maybe_analysis {
|
||||
to_add.push((file_path, bincode::serialize(analysis)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (file_path, analysis) in to_add {
|
||||
vfs.add_cjs_export_analysis(&file_path, analysis);
|
||||
}
|
||||
|
||||
let vfs = self.build_vfs_consolidating_global_npm_cache(vfs);
|
||||
|
||||
let root_dir_url = match &vfs.root_path {
|
||||
WindowsSystemRootablePath::Path(dir) => {
|
||||
Some(url_from_directory_path(dir)?)
|
||||
|
@ -745,14 +590,6 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
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 {
|
||||
CliNpmResolver::Managed(_) => {
|
||||
npm_snapshot.as_ref().map(|_| NodeModules::Managed {
|
||||
|
@ -862,16 +699,17 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
vfs_case_sensitivity: vfs.case_sensitivity,
|
||||
};
|
||||
|
||||
write_binary_bytes(
|
||||
writer,
|
||||
original_bin,
|
||||
let data_section_bytes = serialize_binary_data_section(
|
||||
&metadata,
|
||||
npm_snapshot.map(|s| s.into_serialized()),
|
||||
&specifier_store.for_serialization(&root_dir_url),
|
||||
&redirects_store,
|
||||
&remote_modules_store,
|
||||
&source_map_store,
|
||||
&vfs,
|
||||
compile_flags,
|
||||
)
|
||||
.context("Serializing binary data section.")?;
|
||||
|
||||
write_binary_bytes(writer, original_bin, data_section_bytes, compile_flags)
|
||||
.context("Writing binary bytes")
|
||||
}
|
||||
|
||||
|
@ -1043,6 +881,146 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn write_binary_bytes(
|
||||
mut file_writer: File,
|
||||
original_bin: Vec<u8>,
|
||||
data_section_bytes: Vec<u8>,
|
||||
compile_flags: &CompileFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
let target = compile_flags.resolve_target();
|
||||
if target.contains("linux") {
|
||||
libsui::Elf::new(&original_bin).append(
|
||||
"d3n0l4nd",
|
||||
&data_section_bytes,
|
||||
&mut file_writer,
|
||||
)?;
|
||||
} else if target.contains("windows") {
|
||||
let mut pe = libsui::PortableExecutable::from(&original_bin)?;
|
||||
if let Some(icon) = compile_flags.icon.as_ref() {
|
||||
let icon = std::fs::read(icon)?;
|
||||
pe = pe.set_icon(&icon)?;
|
||||
}
|
||||
|
||||
pe.write_resource("d3n0l4nd", data_section_bytes)?
|
||||
.build(&mut file_writer)?;
|
||||
} else if target.contains("darwin") {
|
||||
libsui::Macho::from(original_bin)?
|
||||
.write_section("d3n0l4nd", data_section_bytes)?
|
||||
.build_and_sign(&mut file_writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Binary format:
|
||||
/// * d3n0l4nd
|
||||
/// * <metadata_len><metadata>
|
||||
/// * <npm_snapshot_len><npm_snapshot>
|
||||
/// * <specifiers>
|
||||
/// * <redirects>
|
||||
/// * <remote_modules>
|
||||
/// * <vfs_headers_len><vfs_headers>
|
||||
/// * <vfs_file_data_len><vfs_file_data>
|
||||
/// * d3n0l4nd
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn serialize_binary_data_section(
|
||||
metadata: &Metadata,
|
||||
npm_snapshot: Option<SerializedNpmResolutionSnapshot>,
|
||||
specifiers: &SpecifierStoreForSerialization,
|
||||
redirects: &SpecifierDataStore<SpecifierId>,
|
||||
remote_modules: &SpecifierDataStore<RemoteModuleEntry<'_>>,
|
||||
vfs: &BuiltVfs,
|
||||
) -> Result<Vec<u8>, AnyError> {
|
||||
let metadata = serde_json::to_string(metadata)?;
|
||||
let npm_snapshot =
|
||||
npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default();
|
||||
let serialized_vfs = serde_json::to_string(&vfs.entries)?;
|
||||
|
||||
let bytes = capacity_builder::BytesBuilder::build(|builder| {
|
||||
builder.append(MAGIC_BYTES);
|
||||
// 1. Metadata
|
||||
{
|
||||
builder.append_le(metadata.len() as u64);
|
||||
builder.append(&metadata);
|
||||
}
|
||||
// 2. Npm snapshot
|
||||
{
|
||||
builder.append_le(npm_snapshot.len() as u64);
|
||||
builder.append(&npm_snapshot);
|
||||
}
|
||||
// 3. Specifiers
|
||||
builder.append(specifiers);
|
||||
// 4. Redirects
|
||||
redirects.serialize(builder);
|
||||
// 5. Remote modules
|
||||
remote_modules.serialize(builder);
|
||||
// 6. VFS
|
||||
{
|
||||
builder.append_le(serialized_vfs.len() as u64);
|
||||
builder.append(&serialized_vfs);
|
||||
let vfs_bytes_len = vfs.files.iter().map(|f| f.len() as u64).sum::<u64>();
|
||||
builder.append_le(vfs_bytes_len);
|
||||
for file in &vfs.files {
|
||||
builder.append(file);
|
||||
}
|
||||
}
|
||||
|
||||
// write the magic bytes at the end so we can use it
|
||||
// to make sure we've deserialized correctly
|
||||
builder.append(MAGIC_BYTES);
|
||||
})?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn serialize_npm_snapshot(
|
||||
mut snapshot: SerializedNpmResolutionSnapshot,
|
||||
) -> Vec<u8> {
|
||||
fn append_string(bytes: &mut Vec<u8>, string: &str) {
|
||||
let len = string.len() as u32;
|
||||
bytes.extend_from_slice(&len.to_le_bytes());
|
||||
bytes.extend_from_slice(string.as_bytes());
|
||||
}
|
||||
|
||||
snapshot.packages.sort_by(|a, b| a.id.cmp(&b.id)); // determinism
|
||||
let ids_to_stored_ids = snapshot
|
||||
.packages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, pkg)| (&pkg.id, i as u32))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut root_packages: Vec<_> = snapshot.root_packages.iter().collect();
|
||||
root_packages.sort();
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
bytes.extend_from_slice(&(snapshot.packages.len() as u32).to_le_bytes());
|
||||
for pkg in &snapshot.packages {
|
||||
append_string(&mut bytes, &pkg.id.as_serialized());
|
||||
}
|
||||
|
||||
bytes.extend_from_slice(&(root_packages.len() as u32).to_le_bytes());
|
||||
for (req, id) in root_packages {
|
||||
append_string(&mut bytes, &req.to_string());
|
||||
let id = ids_to_stored_ids.get(&id).unwrap();
|
||||
bytes.extend_from_slice(&id.to_le_bytes());
|
||||
}
|
||||
|
||||
for pkg in &snapshot.packages {
|
||||
let deps_len = pkg.dependencies.len() as u32;
|
||||
bytes.extend_from_slice(&deps_len.to_le_bytes());
|
||||
let mut deps: Vec<_> = pkg.dependencies.iter().collect();
|
||||
deps.sort();
|
||||
for (req, id) in deps {
|
||||
append_string(&mut bytes, req);
|
||||
let id = ids_to_stored_ids.get(&id).unwrap();
|
||||
bytes.extend_from_slice(&id.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
fn get_denort_path(deno_exe: PathBuf) -> Option<OsString> {
|
||||
let mut denort = deno_exe;
|
||||
denort.set_file_name(if cfg!(windows) {
|
||||
|
|
|
@ -1,884 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use deno_lib::standalone::virtual_fs::VfsFileSubDataKind;
|
||||
use deno_runtime::deno_fs::AccessCheckCb;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_fs::FsDirEntry;
|
||||
use deno_runtime::deno_fs::FsFileType;
|
||||
use deno_runtime::deno_fs::OpenOptions;
|
||||
use deno_runtime::deno_fs::RealFs;
|
||||
use deno_runtime::deno_io::fs::File;
|
||||
use deno_runtime::deno_io::fs::FsError;
|
||||
use deno_runtime::deno_io::fs::FsResult;
|
||||
use deno_runtime::deno_io::fs::FsStat;
|
||||
use sys_traits::boxed::BoxedFsDirEntry;
|
||||
use sys_traits::boxed::BoxedFsMetadataValue;
|
||||
use sys_traits::boxed::FsMetadataBoxed;
|
||||
use sys_traits::boxed::FsReadDirBoxed;
|
||||
use sys_traits::FsCopy;
|
||||
use sys_traits::FsMetadata;
|
||||
|
||||
use super::virtual_fs::FileBackedVfs;
|
||||
use super::virtual_fs::FileBackedVfsDirEntry;
|
||||
use super::virtual_fs::FileBackedVfsFile;
|
||||
use super::virtual_fs::FileBackedVfsMetadata;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DenoCompileFileSystem(Arc<FileBackedVfs>);
|
||||
|
||||
impl DenoCompileFileSystem {
|
||||
pub fn new(vfs: Arc<FileBackedVfs>) -> Self {
|
||||
Self(vfs)
|
||||
}
|
||||
|
||||
fn error_if_in_vfs(&self, path: &Path) -> FsResult<()> {
|
||||
if self.0.is_path_within(path) {
|
||||
Err(FsError::NotSupported)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_to_real_path(
|
||||
&self,
|
||||
oldpath: &Path,
|
||||
newpath: &Path,
|
||||
) -> std::io::Result<u64> {
|
||||
let old_file = self.0.file_entry(oldpath)?;
|
||||
let old_file_bytes =
|
||||
self.0.read_file_all(old_file, VfsFileSubDataKind::Raw)?;
|
||||
let len = old_file_bytes.len() as u64;
|
||||
RealFs
|
||||
.write_file_sync(
|
||||
newpath,
|
||||
OpenOptions {
|
||||
read: false,
|
||||
write: true,
|
||||
create: true,
|
||||
truncate: true,
|
||||
append: false,
|
||||
create_new: false,
|
||||
mode: None,
|
||||
},
|
||||
None,
|
||||
&old_file_bytes,
|
||||
)
|
||||
.map_err(|err| err.into_io_error())?;
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl FileSystem for DenoCompileFileSystem {
|
||||
fn cwd(&self) -> FsResult<PathBuf> {
|
||||
RealFs.cwd()
|
||||
}
|
||||
|
||||
fn tmp_dir(&self) -> FsResult<PathBuf> {
|
||||
RealFs.tmp_dir()
|
||||
}
|
||||
|
||||
fn chdir(&self, path: &Path) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.chdir(path)
|
||||
}
|
||||
|
||||
fn umask(&self, mask: Option<u32>) -> FsResult<u32> {
|
||||
RealFs.umask(mask)
|
||||
}
|
||||
|
||||
fn open_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
options: OpenOptions,
|
||||
access_check: Option<AccessCheckCb>,
|
||||
) -> FsResult<Rc<dyn File>> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(Rc::new(self.0.open_file(path)?))
|
||||
} else {
|
||||
RealFs.open_sync(path, options, access_check)
|
||||
}
|
||||
}
|
||||
async fn open_async<'a>(
|
||||
&'a self,
|
||||
path: PathBuf,
|
||||
options: OpenOptions,
|
||||
access_check: Option<AccessCheckCb<'a>>,
|
||||
) -> FsResult<Rc<dyn File>> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(Rc::new(self.0.open_file(&path)?))
|
||||
} else {
|
||||
RealFs.open_async(path, options, access_check).await
|
||||
}
|
||||
}
|
||||
|
||||
fn mkdir_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
recursive: bool,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.mkdir_sync(path, recursive, mode)
|
||||
}
|
||||
async fn mkdir_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.mkdir_async(path, recursive, mode).await
|
||||
}
|
||||
|
||||
fn chmod_sync(&self, path: &Path, mode: u32) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.chmod_sync(path, mode)
|
||||
}
|
||||
async fn chmod_async(&self, path: PathBuf, mode: u32) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.chmod_async(path, mode).await
|
||||
}
|
||||
|
||||
fn chown_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
uid: Option<u32>,
|
||||
gid: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.chown_sync(path, uid, gid)
|
||||
}
|
||||
async fn chown_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
uid: Option<u32>,
|
||||
gid: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.chown_async(path, uid, gid).await
|
||||
}
|
||||
|
||||
fn lchown_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
uid: Option<u32>,
|
||||
gid: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.lchown_sync(path, uid, gid)
|
||||
}
|
||||
|
||||
async fn lchown_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
uid: Option<u32>,
|
||||
gid: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.lchown_async(path, uid, gid).await
|
||||
}
|
||||
|
||||
fn remove_sync(&self, path: &Path, recursive: bool) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.remove_sync(path, recursive)
|
||||
}
|
||||
async fn remove_async(&self, path: PathBuf, recursive: bool) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.remove_async(path, recursive).await
|
||||
}
|
||||
|
||||
fn copy_file_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
|
||||
self.error_if_in_vfs(newpath)?;
|
||||
if self.0.is_path_within(oldpath) {
|
||||
self
|
||||
.copy_to_real_path(oldpath, newpath)
|
||||
.map(|_| ())
|
||||
.map_err(FsError::Io)
|
||||
} else {
|
||||
RealFs.copy_file_sync(oldpath, newpath)
|
||||
}
|
||||
}
|
||||
async fn copy_file_async(
|
||||
&self,
|
||||
oldpath: PathBuf,
|
||||
newpath: PathBuf,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&newpath)?;
|
||||
if self.0.is_path_within(&oldpath) {
|
||||
let fs = self.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
fs.copy_to_real_path(&oldpath, &newpath)
|
||||
.map(|_| ())
|
||||
.map_err(FsError::Io)
|
||||
})
|
||||
.await?
|
||||
} else {
|
||||
RealFs.copy_file_async(oldpath, newpath).await
|
||||
}
|
||||
}
|
||||
|
||||
fn cp_sync(&self, from: &Path, to: &Path) -> FsResult<()> {
|
||||
self.error_if_in_vfs(to)?;
|
||||
|
||||
RealFs.cp_sync(from, to)
|
||||
}
|
||||
async fn cp_async(&self, from: PathBuf, to: PathBuf) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&to)?;
|
||||
|
||||
RealFs.cp_async(from, to).await
|
||||
}
|
||||
|
||||
fn stat_sync(&self, path: &Path) -> FsResult<FsStat> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(self.0.stat(path)?.as_fs_stat())
|
||||
} else {
|
||||
RealFs.stat_sync(path)
|
||||
}
|
||||
}
|
||||
async fn stat_async(&self, path: PathBuf) -> FsResult<FsStat> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(self.0.stat(&path)?.as_fs_stat())
|
||||
} else {
|
||||
RealFs.stat_async(path).await
|
||||
}
|
||||
}
|
||||
|
||||
fn lstat_sync(&self, path: &Path) -> FsResult<FsStat> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(self.0.lstat(path)?.as_fs_stat())
|
||||
} else {
|
||||
RealFs.lstat_sync(path)
|
||||
}
|
||||
}
|
||||
async fn lstat_async(&self, path: PathBuf) -> FsResult<FsStat> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(self.0.lstat(&path)?.as_fs_stat())
|
||||
} else {
|
||||
RealFs.lstat_async(path).await
|
||||
}
|
||||
}
|
||||
|
||||
fn realpath_sync(&self, path: &Path) -> FsResult<PathBuf> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(self.0.canonicalize(path)?)
|
||||
} else {
|
||||
RealFs.realpath_sync(path)
|
||||
}
|
||||
}
|
||||
async fn realpath_async(&self, path: PathBuf) -> FsResult<PathBuf> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(self.0.canonicalize(&path)?)
|
||||
} else {
|
||||
RealFs.realpath_async(path).await
|
||||
}
|
||||
}
|
||||
|
||||
fn read_dir_sync(&self, path: &Path) -> FsResult<Vec<FsDirEntry>> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(self.0.read_dir(path)?)
|
||||
} else {
|
||||
RealFs.read_dir_sync(path)
|
||||
}
|
||||
}
|
||||
async fn read_dir_async(&self, path: PathBuf) -> FsResult<Vec<FsDirEntry>> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(self.0.read_dir(&path)?)
|
||||
} else {
|
||||
RealFs.read_dir_async(path).await
|
||||
}
|
||||
}
|
||||
|
||||
fn rename_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
|
||||
self.error_if_in_vfs(oldpath)?;
|
||||
self.error_if_in_vfs(newpath)?;
|
||||
RealFs.rename_sync(oldpath, newpath)
|
||||
}
|
||||
async fn rename_async(
|
||||
&self,
|
||||
oldpath: PathBuf,
|
||||
newpath: PathBuf,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&oldpath)?;
|
||||
self.error_if_in_vfs(&newpath)?;
|
||||
RealFs.rename_async(oldpath, newpath).await
|
||||
}
|
||||
|
||||
fn link_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
|
||||
self.error_if_in_vfs(oldpath)?;
|
||||
self.error_if_in_vfs(newpath)?;
|
||||
RealFs.link_sync(oldpath, newpath)
|
||||
}
|
||||
async fn link_async(
|
||||
&self,
|
||||
oldpath: PathBuf,
|
||||
newpath: PathBuf,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&oldpath)?;
|
||||
self.error_if_in_vfs(&newpath)?;
|
||||
RealFs.link_async(oldpath, newpath).await
|
||||
}
|
||||
|
||||
fn symlink_sync(
|
||||
&self,
|
||||
oldpath: &Path,
|
||||
newpath: &Path,
|
||||
file_type: Option<FsFileType>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(oldpath)?;
|
||||
self.error_if_in_vfs(newpath)?;
|
||||
RealFs.symlink_sync(oldpath, newpath, file_type)
|
||||
}
|
||||
async fn symlink_async(
|
||||
&self,
|
||||
oldpath: PathBuf,
|
||||
newpath: PathBuf,
|
||||
file_type: Option<FsFileType>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&oldpath)?;
|
||||
self.error_if_in_vfs(&newpath)?;
|
||||
RealFs.symlink_async(oldpath, newpath, file_type).await
|
||||
}
|
||||
|
||||
fn read_link_sync(&self, path: &Path) -> FsResult<PathBuf> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(self.0.read_link(path)?)
|
||||
} else {
|
||||
RealFs.read_link_sync(path)
|
||||
}
|
||||
}
|
||||
async fn read_link_async(&self, path: PathBuf) -> FsResult<PathBuf> {
|
||||
if self.0.is_path_within(&path) {
|
||||
Ok(self.0.read_link(&path)?)
|
||||
} else {
|
||||
RealFs.read_link_async(path).await
|
||||
}
|
||||
}
|
||||
|
||||
fn truncate_sync(&self, path: &Path, len: u64) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.truncate_sync(path, len)
|
||||
}
|
||||
async fn truncate_async(&self, path: PathBuf, len: u64) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.truncate_async(path, len).await
|
||||
}
|
||||
|
||||
fn utime_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
atime_secs: i64,
|
||||
atime_nanos: u32,
|
||||
mtime_secs: i64,
|
||||
mtime_nanos: u32,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.utime_sync(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
}
|
||||
async fn utime_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
atime_secs: i64,
|
||||
atime_nanos: u32,
|
||||
mtime_secs: i64,
|
||||
mtime_nanos: u32,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs
|
||||
.utime_async(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
.await
|
||||
}
|
||||
|
||||
fn lutime_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
atime_secs: i64,
|
||||
atime_nanos: u32,
|
||||
mtime_secs: i64,
|
||||
mtime_nanos: u32,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.lutime_sync(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
}
|
||||
async fn lutime_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
atime_secs: i64,
|
||||
atime_nanos: u32,
|
||||
mtime_secs: i64,
|
||||
mtime_nanos: u32,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs
|
||||
.lutime_async(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsHardLink for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
self.link_sync(src, dst).map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRead for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_read(&self, path: &Path) -> std::io::Result<Cow<'static, [u8]>> {
|
||||
self
|
||||
.read_file_sync(path, None)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsMetadataValue for FileBackedVfsMetadata {
|
||||
fn file_type(&self) -> sys_traits::FileType {
|
||||
self.file_type
|
||||
}
|
||||
|
||||
fn len(&self) -> u64 {
|
||||
self.len
|
||||
}
|
||||
|
||||
fn accessed(&self) -> std::io::Result<SystemTime> {
|
||||
Err(not_supported("accessed time"))
|
||||
}
|
||||
|
||||
fn created(&self) -> std::io::Result<SystemTime> {
|
||||
Err(not_supported("created time"))
|
||||
}
|
||||
|
||||
fn changed(&self) -> std::io::Result<SystemTime> {
|
||||
Err(not_supported("changed time"))
|
||||
}
|
||||
|
||||
fn modified(&self) -> std::io::Result<SystemTime> {
|
||||
Err(not_supported("modified time"))
|
||||
}
|
||||
|
||||
fn dev(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn ino(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn mode(&self) -> std::io::Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn nlink(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn uid(&self) -> std::io::Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn gid(&self) -> std::io::Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn rdev(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn blksize(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn blocks(&self) -> std::io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn is_block_device(&self) -> std::io::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn is_char_device(&self) -> std::io::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn is_fifo(&self) -> std::io::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn is_socket(&self) -> std::io::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn file_attributes(&self) -> std::io::Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn not_supported(name: &str) -> std::io::Error {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Unsupported,
|
||||
format!(
|
||||
"{} is not supported for an embedded deno compile file",
|
||||
name
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
impl sys_traits::FsDirEntry for FileBackedVfsDirEntry {
|
||||
type Metadata = BoxedFsMetadataValue;
|
||||
|
||||
fn file_name(&self) -> Cow<std::ffi::OsStr> {
|
||||
Cow::Borrowed(self.metadata.name.as_ref())
|
||||
}
|
||||
|
||||
fn file_type(&self) -> std::io::Result<sys_traits::FileType> {
|
||||
Ok(self.metadata.file_type)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> std::io::Result<Self::Metadata> {
|
||||
Ok(BoxedFsMetadataValue(Box::new(self.metadata.clone())))
|
||||
}
|
||||
|
||||
fn path(&self) -> Cow<Path> {
|
||||
Cow::Owned(self.parent_path.join(&self.metadata.name))
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsReadDir for DenoCompileFileSystem {
|
||||
type ReadDirEntry = BoxedFsDirEntry;
|
||||
|
||||
fn base_fs_read_dir(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> std::io::Result<
|
||||
Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>> + '_>,
|
||||
> {
|
||||
if self.0.is_path_within(path) {
|
||||
let entries = self.0.read_dir_with_metadata(path)?;
|
||||
Ok(Box::new(
|
||||
entries.map(|entry| Ok(BoxedFsDirEntry::new(entry))),
|
||||
))
|
||||
} else {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.fs_read_dir_boxed(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCanonicalize for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> {
|
||||
self.realpath_sync(path).map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsMetadata for DenoCompileFileSystem {
|
||||
type Metadata = BoxedFsMetadataValue;
|
||||
|
||||
#[inline]
|
||||
fn base_fs_metadata(&self, path: &Path) -> std::io::Result<Self::Metadata> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(BoxedFsMetadataValue::new(self.0.stat(path)?))
|
||||
} else {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.fs_metadata_boxed(path)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn base_fs_symlink_metadata(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> std::io::Result<Self::Metadata> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(BoxedFsMetadataValue::new(self.0.lstat(path)?))
|
||||
} else {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.fs_symlink_metadata_boxed(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCopy for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_copy(&self, from: &Path, to: &Path) -> std::io::Result<u64> {
|
||||
self
|
||||
.error_if_in_vfs(to)
|
||||
.map_err(|err| err.into_io_error())?;
|
||||
if self.0.is_path_within(from) {
|
||||
self.copy_to_real_path(from, to)
|
||||
} else {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.fs_copy(from, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCloneFile for DenoCompileFileSystem {
|
||||
fn base_fs_clone_file(
|
||||
&self,
|
||||
_from: &Path,
|
||||
_to: &Path,
|
||||
) -> std::io::Result<()> {
|
||||
// will cause a fallback in the code that uses this
|
||||
Err(not_supported("cloning files"))
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCreateDir for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_create_dir(
|
||||
&self,
|
||||
path: &Path,
|
||||
options: &sys_traits::CreateDirOptions,
|
||||
) -> std::io::Result<()> {
|
||||
self
|
||||
.mkdir_sync(path, options.recursive, options.mode)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRemoveFile for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.remove_sync(path, false)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRename for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn base_fs_rename(&self, from: &Path, to: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.rename_sync(from, to)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum FsFileAdapter {
|
||||
Real(sys_traits::impls::RealFsFile),
|
||||
Vfs(FileBackedVfsFile),
|
||||
}
|
||||
|
||||
impl sys_traits::FsFile for FsFileAdapter {}
|
||||
|
||||
impl sys_traits::FsFileAsRaw for FsFileAdapter {
|
||||
#[cfg(windows)]
|
||||
fn fs_file_as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_as_raw_handle(),
|
||||
Self::Vfs(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn fs_file_as_raw_fd(&self) -> Option<std::os::fd::RawFd> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_as_raw_fd(),
|
||||
Self::Vfs(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileSyncData for FsFileAdapter {
|
||||
fn fs_file_sync_data(&mut self) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_sync_data(),
|
||||
Self::Vfs(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileSyncAll for FsFileAdapter {
|
||||
fn fs_file_sync_all(&mut self) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_sync_all(),
|
||||
Self::Vfs(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileSetPermissions for FsFileAdapter {
|
||||
#[inline]
|
||||
fn fs_file_set_permissions(&mut self, mode: u32) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_set_permissions(mode),
|
||||
Self::Vfs(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Read for FsFileAdapter {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match self {
|
||||
Self::Real(file) => file.read(buf),
|
||||
Self::Vfs(file) => file.read_to_buf(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Seek for FsFileAdapter {
|
||||
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
|
||||
match self {
|
||||
Self::Real(file) => file.seek(pos),
|
||||
Self::Vfs(file) => file.seek(pos),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Write for FsFileAdapter {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
match self {
|
||||
Self::Real(file) => file.write(buf),
|
||||
Self::Vfs(_) => Err(not_supported("writing files")),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.flush(),
|
||||
Self::Vfs(_) => Err(not_supported("writing files")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileSetLen for FsFileAdapter {
|
||||
#[inline]
|
||||
fn fs_file_set_len(&mut self, len: u64) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_set_len(len),
|
||||
Self::Vfs(_) => Err(not_supported("setting file length")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileSetTimes for FsFileAdapter {
|
||||
fn fs_file_set_times(
|
||||
&mut self,
|
||||
times: sys_traits::FsFileTimes,
|
||||
) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_set_times(times),
|
||||
Self::Vfs(_) => Err(not_supported("setting file times")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileLock for FsFileAdapter {
|
||||
fn fs_file_lock(
|
||||
&mut self,
|
||||
mode: sys_traits::FsFileLockMode,
|
||||
) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_lock(mode),
|
||||
Self::Vfs(_) => Err(not_supported("locking files")),
|
||||
}
|
||||
}
|
||||
|
||||
fn fs_file_try_lock(
|
||||
&mut self,
|
||||
mode: sys_traits::FsFileLockMode,
|
||||
) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_try_lock(mode),
|
||||
Self::Vfs(_) => Err(not_supported("locking files")),
|
||||
}
|
||||
}
|
||||
|
||||
fn fs_file_unlock(&mut self) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_unlock(),
|
||||
Self::Vfs(_) => Err(not_supported("unlocking files")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::FsFileIsTerminal for FsFileAdapter {
|
||||
#[inline]
|
||||
fn fs_file_is_terminal(&self) -> bool {
|
||||
match self {
|
||||
Self::Real(file) => file.fs_file_is_terminal(),
|
||||
Self::Vfs(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsOpen for DenoCompileFileSystem {
|
||||
type File = FsFileAdapter;
|
||||
|
||||
fn base_fs_open(
|
||||
&self,
|
||||
path: &Path,
|
||||
options: &sys_traits::OpenOptions,
|
||||
) -> std::io::Result<Self::File> {
|
||||
if self.0.is_path_within(path) {
|
||||
Ok(FsFileAdapter::Vfs(self.0.open_file(path)?))
|
||||
} else {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
Ok(FsFileAdapter::Real(
|
||||
sys_traits::impls::RealSys.base_fs_open(path, options)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsSymlinkDir for DenoCompileFileSystem {
|
||||
fn base_fs_symlink_dir(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.symlink_sync(src, dst, Some(FsFileType::Directory))
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::SystemRandom for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.sys_random(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::SystemTimeNow for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn sys_time_now(&self) -> SystemTime {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.sys_time_now()
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::ThreadSleep for DenoCompileFileSystem {
|
||||
#[inline]
|
||||
fn thread_sleep(&self, dur: Duration) {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.thread_sleep(dur)
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::EnvCurrentDir for DenoCompileFileSystem {
|
||||
fn env_current_dir(&self) -> std::io::Result<PathBuf> {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.env_current_dir()
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseEnvVar for DenoCompileFileSystem {
|
||||
fn base_env_var_os(
|
||||
&self,
|
||||
key: &std::ffi::OsStr,
|
||||
) -> Option<std::ffi::OsString> {
|
||||
#[allow(clippy::disallowed_types)] // ok because we're implementing the fs
|
||||
sys_traits::impls::RealSys.base_env_var_os(key)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,788 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
|
||||
use capacity_builder::BytesAppendable;
|
||||
use deno_ast::swc::common::source_map;
|
||||
use deno_ast::MediaType;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::FastString;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleType;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
|
||||
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmPackageId;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::StackString;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use super::binary::Metadata;
|
||||
use super::virtual_fs::BuiltVfs;
|
||||
use super::virtual_fs::VfsBuilder;
|
||||
|
||||
const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd";
|
||||
|
||||
/// Binary format:
|
||||
/// * d3n0l4nd
|
||||
/// * <metadata_len><metadata>
|
||||
/// * <npm_snapshot_len><npm_snapshot>
|
||||
/// * <remote_modules>
|
||||
/// * <vfs_headers_len><vfs_headers>
|
||||
/// * <vfs_file_data_len><vfs_file_data>
|
||||
/// * <source_map_data>
|
||||
/// * d3n0l4nd
|
||||
pub fn serialize_binary_data_section(
|
||||
metadata: &Metadata,
|
||||
npm_snapshot: Option<SerializedNpmResolutionSnapshot>,
|
||||
remote_modules: &RemoteModulesStoreBuilder,
|
||||
source_map_store: &SourceMapStore,
|
||||
vfs: &BuiltVfs,
|
||||
) -> Result<Vec<u8>, AnyError> {
|
||||
let metadata = serde_json::to_string(metadata)?;
|
||||
let npm_snapshot =
|
||||
npm_snapshot.map(serialize_npm_snapshot).unwrap_or_default();
|
||||
let serialized_vfs = serde_json::to_string(&vfs.entries)?;
|
||||
|
||||
let bytes = capacity_builder::BytesBuilder::build(|builder| {
|
||||
builder.append(MAGIC_BYTES);
|
||||
// 1. Metadata
|
||||
{
|
||||
builder.append_le(metadata.len() as u64);
|
||||
builder.append(&metadata);
|
||||
}
|
||||
// 2. Npm snapshot
|
||||
{
|
||||
builder.append_le(npm_snapshot.len() as u64);
|
||||
builder.append(&npm_snapshot);
|
||||
}
|
||||
// 3. Remote modules
|
||||
{
|
||||
remote_modules.write(builder);
|
||||
}
|
||||
// 4. VFS
|
||||
{
|
||||
builder.append_le(serialized_vfs.len() as u64);
|
||||
builder.append(&serialized_vfs);
|
||||
let vfs_bytes_len = vfs.files.iter().map(|f| f.len() as u64).sum::<u64>();
|
||||
builder.append_le(vfs_bytes_len);
|
||||
for file in &vfs.files {
|
||||
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
|
||||
// to make sure we've deserialized correctly
|
||||
builder.append(MAGIC_BYTES);
|
||||
})?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub struct DeserializedDataSection {
|
||||
pub metadata: Metadata,
|
||||
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,
|
||||
pub remote_modules: RemoteModulesStore,
|
||||
pub source_maps: SourceMapStore,
|
||||
pub vfs_root_entries: VirtualDirectoryEntries,
|
||||
pub vfs_files_data: &'static [u8],
|
||||
}
|
||||
|
||||
pub fn deserialize_binary_data_section(
|
||||
data: &'static [u8],
|
||||
) -> Result<Option<DeserializedDataSection>, AnyError> {
|
||||
fn read_magic_bytes(input: &[u8]) -> Result<(&[u8], bool), AnyError> {
|
||||
if input.len() < MAGIC_BYTES.len() {
|
||||
bail!("Unexpected end of data. Could not find magic bytes.");
|
||||
}
|
||||
let (magic_bytes, input) = input.split_at(MAGIC_BYTES.len());
|
||||
if magic_bytes != MAGIC_BYTES {
|
||||
return Ok((input, false));
|
||||
}
|
||||
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)?;
|
||||
if !found {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// 1. Metadata
|
||||
let (input, data) =
|
||||
read_bytes_with_u64_len(input).context("reading metadata")?;
|
||||
let metadata: Metadata =
|
||||
serde_json::from_slice(data).context("deserializing metadata")?;
|
||||
// 2. Npm snapshot
|
||||
let (input, data) =
|
||||
read_bytes_with_u64_len(input).context("reading npm snapshot")?;
|
||||
let npm_snapshot = if data.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(deserialize_npm_snapshot(data).context("deserializing npm snapshot")?)
|
||||
};
|
||||
// 3. Remote modules
|
||||
let (input, remote_modules) =
|
||||
RemoteModulesStore::build(input).context("deserializing remote modules")?;
|
||||
// 4. VFS
|
||||
let (input, data) = read_bytes_with_u64_len(input).context("vfs")?;
|
||||
let vfs_root_entries: VirtualDirectoryEntries =
|
||||
serde_json::from_slice(data).context("deserializing vfs data")?;
|
||||
let (input, 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
|
||||
let (_input, found) = read_magic_bytes(input)?;
|
||||
if !found {
|
||||
bail!("Could not find magic bytes at the end of the data.");
|
||||
}
|
||||
|
||||
Ok(Some(DeserializedDataSection {
|
||||
metadata,
|
||||
npm_snapshot,
|
||||
remote_modules,
|
||||
source_maps,
|
||||
vfs_root_entries,
|
||||
vfs_files_data,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RemoteModulesStoreBuilder {
|
||||
specifiers: Vec<(String, u64)>,
|
||||
data: Vec<(MediaType, Vec<u8>, Option<Vec<u8>>)>,
|
||||
data_byte_len: u64,
|
||||
redirects: Vec<(String, String)>,
|
||||
redirects_len: u64,
|
||||
}
|
||||
|
||||
impl RemoteModulesStoreBuilder {
|
||||
pub fn add(
|
||||
&mut self,
|
||||
specifier: &Url,
|
||||
media_type: MediaType,
|
||||
data: Vec<u8>,
|
||||
maybe_transpiled: Option<Vec<u8>>,
|
||||
) {
|
||||
log::debug!("Adding '{}' ({})", specifier, media_type);
|
||||
let specifier = specifier.to_string();
|
||||
self.specifiers.push((specifier, self.data_byte_len));
|
||||
let maybe_transpiled_len = match &maybe_transpiled {
|
||||
// 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>) {
|
||||
self.redirects.reserve(redirects.len());
|
||||
for (from, to) in redirects {
|
||||
log::debug!("Adding redirect '{}' -> '{}'", from, to);
|
||||
let from = from.to_string();
|
||||
let to = to.to_string();
|
||||
self.redirects_len += (4 + from.len() + 4 + to.len()) as u64;
|
||||
self.redirects.push((from, to));
|
||||
}
|
||||
}
|
||||
|
||||
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.redirects.len() as u32);
|
||||
for (specifier, offset) in &self.specifiers {
|
||||
builder.append_le(specifier.len() as u32);
|
||||
builder.append(specifier);
|
||||
builder.append_le(*offset);
|
||||
}
|
||||
for (from, to) in &self.redirects {
|
||||
builder.append_le(from.len() as u32);
|
||||
builder.append(from);
|
||||
builder.append_le(to.len() as u32);
|
||||
builder.append(to);
|
||||
}
|
||||
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_le(data.len() as u32);
|
||||
builder.append(data);
|
||||
if let Some(transpiled) = maybe_transpiled {
|
||||
builder.append(1);
|
||||
builder.append_le(transpiled.len() as u32);
|
||||
builder.append(transpiled);
|
||||
} else {
|
||||
builder.append(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DenoCompileModuleSource {
|
||||
String(&'static str),
|
||||
Bytes(Cow<'static, [u8]>),
|
||||
}
|
||||
|
||||
impl DenoCompileModuleSource {
|
||||
pub fn into_for_v8(self) -> ModuleSourceCode {
|
||||
fn into_bytes(data: Cow<'static, [u8]>) -> ModuleSourceCode {
|
||||
ModuleSourceCode::Bytes(match data {
|
||||
Cow::Borrowed(d) => d.into(),
|
||||
Cow::Owned(d) => d.into_boxed_slice().into(),
|
||||
})
|
||||
}
|
||||
|
||||
match self {
|
||||
// todo(https://github.com/denoland/deno_core/pull/943): store whether
|
||||
// the string is ascii or not ahead of time so we can avoid the is_ascii()
|
||||
// check in FastString::from_static
|
||||
Self::String(s) => ModuleSourceCode::String(FastString::from_static(s)),
|
||||
Self::Bytes(b) => into_bytes(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 specifier: &'a Url,
|
||||
pub media_type: MediaType,
|
||||
pub data: Cow<'static, [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> DenoCompileModuleData<'a> {
|
||||
pub fn into_parts(self) -> (&'a Url, ModuleType, DenoCompileModuleSource) {
|
||||
fn into_string_unsafe(data: Cow<'static, [u8]>) -> DenoCompileModuleSource {
|
||||
match data {
|
||||
Cow::Borrowed(d) => DenoCompileModuleSource::String(
|
||||
// SAFETY: we know this is a valid utf8 string
|
||||
unsafe { std::str::from_utf8_unchecked(d) },
|
||||
),
|
||||
Cow::Owned(d) => DenoCompileModuleSource::Bytes(Cow::Owned(d)),
|
||||
}
|
||||
}
|
||||
|
||||
let (media_type, source) = match self.media_type {
|
||||
MediaType::JavaScript
|
||||
| MediaType::Jsx
|
||||
| MediaType::Mjs
|
||||
| MediaType::Cjs
|
||||
| MediaType::TypeScript
|
||||
| MediaType::Mts
|
||||
| MediaType::Cts
|
||||
| MediaType::Dts
|
||||
| MediaType::Dmts
|
||||
| MediaType::Dcts
|
||||
| MediaType::Tsx => {
|
||||
(ModuleType::JavaScript, into_string_unsafe(self.data))
|
||||
}
|
||||
MediaType::Json => (ModuleType::Json, into_string_unsafe(self.data)),
|
||||
MediaType::Wasm => {
|
||||
(ModuleType::Wasm, DenoCompileModuleSource::Bytes(self.data))
|
||||
}
|
||||
// just assume javascript if we made it here
|
||||
MediaType::Css | MediaType::SourceMap | MediaType::Unknown => (
|
||||
ModuleType::JavaScript,
|
||||
DenoCompileModuleSource::Bytes(self.data),
|
||||
),
|
||||
};
|
||||
(self.specifier, media_type, source)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
Data(usize),
|
||||
Redirect(Url),
|
||||
}
|
||||
|
||||
pub struct RemoteModulesStore {
|
||||
specifiers: HashMap<Url, RemoteModulesStoreSpecifierValue>,
|
||||
files_data: &'static [u8],
|
||||
}
|
||||
|
||||
impl RemoteModulesStore {
|
||||
fn build(input: &'static [u8]) -> Result<(&'static [u8], Self), AnyError> {
|
||||
fn read_specifier(input: &[u8]) -> Result<(&[u8], (Url, u64)), AnyError> {
|
||||
let (input, specifier) = read_string_lossy(input)?;
|
||||
let specifier = Url::parse(&specifier)?;
|
||||
let (input, offset) = read_u64(input)?;
|
||||
Ok((input, (specifier, offset)))
|
||||
}
|
||||
|
||||
fn read_redirect(input: &[u8]) -> Result<(&[u8], (Url, Url)), AnyError> {
|
||||
let (input, from) = read_string_lossy(input)?;
|
||||
let from = Url::parse(&from)?;
|
||||
let (input, to) = read_string_lossy(input)?;
|
||||
let to = Url::parse(&to)?;
|
||||
Ok((input, (from, to)))
|
||||
}
|
||||
|
||||
fn read_headers(
|
||||
input: &[u8],
|
||||
) -> Result<(&[u8], HashMap<Url, RemoteModulesStoreSpecifierValue>), AnyError>
|
||||
{
|
||||
let (input, specifiers_len) = read_u32_as_usize(input)?;
|
||||
let (mut input, redirects_len) = read_u32_as_usize(input)?;
|
||||
let mut specifiers =
|
||||
HashMap::with_capacity(specifiers_len + redirects_len);
|
||||
for _ in 0..specifiers_len {
|
||||
let (current_input, (specifier, offset)) =
|
||||
read_specifier(input).context("reading specifier")?;
|
||||
input = current_input;
|
||||
specifiers.insert(
|
||||
specifier,
|
||||
RemoteModulesStoreSpecifierValue::Data(offset as usize),
|
||||
);
|
||||
}
|
||||
|
||||
for _ in 0..redirects_len {
|
||||
let (current_input, (from, to)) = read_redirect(input)?;
|
||||
input = current_input;
|
||||
specifiers.insert(from, RemoteModulesStoreSpecifierValue::Redirect(to));
|
||||
}
|
||||
|
||||
Ok((input, specifiers))
|
||||
}
|
||||
|
||||
let (input, specifiers) = read_headers(input)?;
|
||||
let (input, files_data) = read_bytes_with_u64_len(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Self {
|
||||
specifiers,
|
||||
files_data,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn resolve_specifier<'a>(
|
||||
&'a self,
|
||||
specifier: &'a Url,
|
||||
) -> Result<Option<&'a Url>, JsErrorBox> {
|
||||
let mut count = 0;
|
||||
let mut current = specifier;
|
||||
loop {
|
||||
if count > 10 {
|
||||
return Err(JsErrorBox::generic(format!(
|
||||
"Too many redirects resolving '{}'",
|
||||
specifier
|
||||
)));
|
||||
}
|
||||
match self.specifiers.get(current) {
|
||||
Some(RemoteModulesStoreSpecifierValue::Redirect(to)) => {
|
||||
current = to;
|
||||
count += 1;
|
||||
}
|
||||
Some(RemoteModulesStoreSpecifierValue::Data(_)) => {
|
||||
return Ok(Some(current));
|
||||
}
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<'a>(
|
||||
&'a self,
|
||||
original_specifier: &'a Url,
|
||||
) -> Result<Option<RemoteModuleEntry<'a>>, AnyError> {
|
||||
let mut count = 0;
|
||||
let mut specifier = original_specifier;
|
||||
loop {
|
||||
if count > 10 {
|
||||
bail!("Too many redirects resolving '{}'", original_specifier);
|
||||
}
|
||||
match self.specifiers.get(specifier) {
|
||||
Some(RemoteModulesStoreSpecifierValue::Redirect(to)) => {
|
||||
specifier = to;
|
||||
count += 1;
|
||||
}
|
||||
Some(RemoteModulesStoreSpecifierValue::Data(offset)) => {
|
||||
let input = &self.files_data[*offset..];
|
||||
let (input, media_type_byte) = read_bytes(input, 1)?;
|
||||
let media_type = deserialize_media_type(media_type_byte[0])?;
|
||||
let (input, data) = read_bytes_with_u32_len(input)?;
|
||||
check_has_len(input, 1)?;
|
||||
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,
|
||||
media_type,
|
||||
data: Cow::Borrowed(data),
|
||||
transpiled_data: transpiled_data.map(Cow::Borrowed),
|
||||
}));
|
||||
}
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_npm_snapshot(
|
||||
mut snapshot: SerializedNpmResolutionSnapshot,
|
||||
) -> Vec<u8> {
|
||||
fn append_string(bytes: &mut Vec<u8>, string: &str) {
|
||||
let len = string.len() as u32;
|
||||
bytes.extend_from_slice(&len.to_le_bytes());
|
||||
bytes.extend_from_slice(string.as_bytes());
|
||||
}
|
||||
|
||||
snapshot.packages.sort_by(|a, b| a.id.cmp(&b.id)); // determinism
|
||||
let ids_to_stored_ids = snapshot
|
||||
.packages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, pkg)| (&pkg.id, i as u32))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut root_packages: Vec<_> = snapshot.root_packages.iter().collect();
|
||||
root_packages.sort();
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
bytes.extend_from_slice(&(snapshot.packages.len() as u32).to_le_bytes());
|
||||
for pkg in &snapshot.packages {
|
||||
append_string(&mut bytes, &pkg.id.as_serialized());
|
||||
}
|
||||
|
||||
bytes.extend_from_slice(&(root_packages.len() as u32).to_le_bytes());
|
||||
for (req, id) in root_packages {
|
||||
append_string(&mut bytes, &req.to_string());
|
||||
let id = ids_to_stored_ids.get(&id).unwrap();
|
||||
bytes.extend_from_slice(&id.to_le_bytes());
|
||||
}
|
||||
|
||||
for pkg in &snapshot.packages {
|
||||
let deps_len = pkg.dependencies.len() as u32;
|
||||
bytes.extend_from_slice(&deps_len.to_le_bytes());
|
||||
let mut deps: Vec<_> = pkg.dependencies.iter().collect();
|
||||
deps.sort();
|
||||
for (req, id) in deps {
|
||||
append_string(&mut bytes, req);
|
||||
let id = ids_to_stored_ids.get(&id).unwrap();
|
||||
bytes.extend_from_slice(&id.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
fn deserialize_npm_snapshot(
|
||||
input: &[u8],
|
||||
) -> Result<ValidSerializedNpmResolutionSnapshot, AnyError> {
|
||||
fn parse_id(input: &[u8]) -> Result<(&[u8], NpmPackageId), AnyError> {
|
||||
let (input, id) = read_string_lossy(input)?;
|
||||
let id = NpmPackageId::from_serialized(&id)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_lifetimes)] // clippy bug
|
||||
fn parse_root_package<'a>(
|
||||
id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> impl Fn(&[u8]) -> Result<(&[u8], (PackageReq, NpmPackageId)), AnyError> + 'a
|
||||
{
|
||||
|input| {
|
||||
let (input, req) = read_string_lossy(input)?;
|
||||
let req = PackageReq::from_str(&req)?;
|
||||
let (input, id) = read_u32_as_usize(input)?;
|
||||
Ok((input, (req, id_to_npm_id(id)?)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_lifetimes)] // clippy bug
|
||||
fn parse_package_dep<'a>(
|
||||
id_to_npm_id: &'a impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> impl Fn(&[u8]) -> Result<(&[u8], (StackString, NpmPackageId)), AnyError> + 'a
|
||||
{
|
||||
|input| {
|
||||
let (input, req) = read_string_lossy(input)?;
|
||||
let (input, id) = read_u32_as_usize(input)?;
|
||||
let req = StackString::from_cow(req);
|
||||
Ok((input, (req, id_to_npm_id(id)?)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_package<'a>(
|
||||
input: &'a [u8],
|
||||
id: NpmPackageId,
|
||||
id_to_npm_id: &impl Fn(usize) -> Result<NpmPackageId, AnyError>,
|
||||
) -> Result<(&'a [u8], SerializedNpmResolutionSnapshotPackage), AnyError> {
|
||||
let (input, deps_len) = read_u32_as_usize(input)?;
|
||||
let (input, dependencies) =
|
||||
parse_hashmap_n_times(input, deps_len, parse_package_dep(id_to_npm_id))?;
|
||||
Ok((
|
||||
input,
|
||||
SerializedNpmResolutionSnapshotPackage {
|
||||
id,
|
||||
system: Default::default(),
|
||||
dist: Default::default(),
|
||||
dependencies,
|
||||
optional_dependencies: Default::default(),
|
||||
bin: None,
|
||||
scripts: Default::default(),
|
||||
deprecated: Default::default(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
let (input, packages_len) = read_u32_as_usize(input)?;
|
||||
|
||||
// get a hashmap of all the npm package ids to their serialized ids
|
||||
let (input, data_ids_to_npm_ids) =
|
||||
parse_vec_n_times(input, packages_len, parse_id)
|
||||
.context("deserializing id")?;
|
||||
let data_id_to_npm_id = |id: usize| {
|
||||
data_ids_to_npm_ids
|
||||
.get(id)
|
||||
.cloned()
|
||||
.ok_or_else(|| deno_core::anyhow::anyhow!("Invalid npm package id"))
|
||||
};
|
||||
|
||||
let (input, root_packages_len) = read_u32_as_usize(input)?;
|
||||
let (input, root_packages) = parse_hashmap_n_times(
|
||||
input,
|
||||
root_packages_len,
|
||||
parse_root_package(&data_id_to_npm_id),
|
||||
)
|
||||
.context("deserializing root package")?;
|
||||
let (input, packages) =
|
||||
parse_vec_n_times_with_index(input, packages_len, |input, index| {
|
||||
parse_package(input, data_id_to_npm_id(index)?, &data_id_to_npm_id)
|
||||
})
|
||||
.context("deserializing package")?;
|
||||
|
||||
if !input.is_empty() {
|
||||
bail!("Unexpected data left over");
|
||||
}
|
||||
|
||||
Ok(
|
||||
SerializedNpmResolutionSnapshot {
|
||||
packages,
|
||||
root_packages,
|
||||
}
|
||||
// this is ok because we have already verified that all the
|
||||
// identifiers found in the snapshot are valid via the
|
||||
// npm package id -> npm package id mapping
|
||||
.into_valid_unsafe(),
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize_media_type(media_type: MediaType) -> u8 {
|
||||
match media_type {
|
||||
MediaType::JavaScript => 0,
|
||||
MediaType::Jsx => 1,
|
||||
MediaType::Mjs => 2,
|
||||
MediaType::Cjs => 3,
|
||||
MediaType::TypeScript => 4,
|
||||
MediaType::Mts => 5,
|
||||
MediaType::Cts => 6,
|
||||
MediaType::Dts => 7,
|
||||
MediaType::Dmts => 8,
|
||||
MediaType::Dcts => 9,
|
||||
MediaType::Tsx => 10,
|
||||
MediaType::Json => 11,
|
||||
MediaType::Wasm => 12,
|
||||
MediaType::Css => 13,
|
||||
MediaType::SourceMap => 14,
|
||||
MediaType::Unknown => 15,
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_media_type(value: u8) -> Result<MediaType, AnyError> {
|
||||
match value {
|
||||
0 => Ok(MediaType::JavaScript),
|
||||
1 => Ok(MediaType::Jsx),
|
||||
2 => Ok(MediaType::Mjs),
|
||||
3 => Ok(MediaType::Cjs),
|
||||
4 => Ok(MediaType::TypeScript),
|
||||
5 => Ok(MediaType::Mts),
|
||||
6 => Ok(MediaType::Cts),
|
||||
7 => Ok(MediaType::Dts),
|
||||
8 => Ok(MediaType::Dmts),
|
||||
9 => Ok(MediaType::Dcts),
|
||||
10 => Ok(MediaType::Tsx),
|
||||
11 => Ok(MediaType::Json),
|
||||
12 => Ok(MediaType::Wasm),
|
||||
13 => Ok(MediaType::Css),
|
||||
14 => Ok(MediaType::SourceMap),
|
||||
15 => Ok(MediaType::Unknown),
|
||||
_ => bail!("Unknown media type value: {}", value),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hashmap_n_times<TKey: std::cmp::Eq + std::hash::Hash, TValue>(
|
||||
mut input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8]) -> Result<(&[u8], (TKey, TValue)), AnyError>,
|
||||
) -> Result<(&[u8], HashMap<TKey, TValue>), AnyError> {
|
||||
let mut results = HashMap::with_capacity(times);
|
||||
for _ in 0..times {
|
||||
let result = parse(input);
|
||||
let (new_input, (key, value)) = result?;
|
||||
results.insert(key, value);
|
||||
input = new_input;
|
||||
}
|
||||
Ok((input, results))
|
||||
}
|
||||
|
||||
fn parse_vec_n_times<TResult>(
|
||||
input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8]) -> Result<(&[u8], TResult), AnyError>,
|
||||
) -> Result<(&[u8], Vec<TResult>), AnyError> {
|
||||
parse_vec_n_times_with_index(input, times, |input, _index| parse(input))
|
||||
}
|
||||
|
||||
fn parse_vec_n_times_with_index<TResult>(
|
||||
mut input: &[u8],
|
||||
times: usize,
|
||||
parse: impl Fn(&[u8], usize) -> Result<(&[u8], TResult), AnyError>,
|
||||
) -> Result<(&[u8], Vec<TResult>), AnyError> {
|
||||
let mut results = Vec::with_capacity(times);
|
||||
for i in 0..times {
|
||||
let result = parse(input, i);
|
||||
let (new_input, result) = result?;
|
||||
results.push(result);
|
||||
input = new_input;
|
||||
}
|
||||
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> {
|
||||
check_has_len(input, len)?;
|
||||
let (len_bytes, input) = input.split_at(len);
|
||||
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> {
|
||||
let (input, data_bytes) = read_bytes_with_u32_len(input)?;
|
||||
Ok((input, String::from_utf8_lossy(data_bytes)))
|
||||
}
|
||||
|
||||
fn read_u32_as_usize(input: &[u8]) -> Result<(&[u8], usize), AnyError> {
|
||||
let (input, len_bytes) = read_bytes(input, 4)?;
|
||||
let len = u32::from_le_bytes(len_bytes.try_into()?);
|
||||
Ok((input, len as usize))
|
||||
}
|
||||
|
||||
fn read_u64(input: &[u8]) -> Result<(&[u8], u64), AnyError> {
|
||||
let (input, len_bytes) = read_bytes(input, 8)?;
|
||||
let len = u64::from_le_bytes(len_bytes.try_into()?);
|
||||
Ok((input, len))
|
||||
}
|
File diff suppressed because it is too large
Load diff
232
cli/sys.rs
232
cli/sys.rs
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
// todo(dsherret): this should instead use conditional compilation and directly
|
||||
// surface the underlying implementation.
|
||||
//
|
||||
// The problem atm is that there's no way to have conditional compilation for
|
||||
// denort or the deno binary. We should extract out denort to a separate binary.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use sys_traits::boxed::BoxedFsDirEntry;
|
||||
use sys_traits::boxed::BoxedFsFile;
|
||||
use sys_traits::boxed::BoxedFsMetadataValue;
|
||||
use sys_traits::boxed::FsMetadataBoxed;
|
||||
use sys_traits::boxed::FsOpenBoxed;
|
||||
use sys_traits::boxed::FsReadDirBoxed;
|
||||
use sys_traits::CreateDirOptions;
|
||||
|
||||
use crate::standalone::DenoCompileFileSystem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CliSys {
|
||||
#[allow(dead_code)] // will be dead code for denort
|
||||
#[allow(clippy::disallowed_types)] // ok because sys impl
|
||||
Real(sys_traits::impls::RealSys),
|
||||
#[allow(dead_code)] // will be dead code for deno
|
||||
DenoCompile(DenoCompileFileSystem),
|
||||
}
|
||||
|
||||
impl deno_lib::sys::DenoLibSys for CliSys {}
|
||||
|
||||
impl Default for CliSys {
|
||||
fn default() -> Self {
|
||||
Self::Real(sys_traits::impls::RealSys)
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_runtime::deno_node::ExtNodeSys for CliSys {}
|
||||
|
||||
impl sys_traits::BaseFsCloneFile for CliSys {
|
||||
fn base_fs_clone_file(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_clone_file(src, dst),
|
||||
Self::DenoCompile(sys) => sys.base_fs_clone_file(src, dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsSymlinkDir for CliSys {
|
||||
fn base_fs_symlink_dir(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_symlink_dir(src, dst),
|
||||
Self::DenoCompile(sys) => sys.base_fs_symlink_dir(src, dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCopy for CliSys {
|
||||
fn base_fs_copy(&self, src: &Path, dst: &Path) -> std::io::Result<u64> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_copy(src, dst),
|
||||
Self::DenoCompile(sys) => sys.base_fs_copy(src, dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsHardLink for CliSys {
|
||||
fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_hard_link(src, dst),
|
||||
Self::DenoCompile(sys) => sys.base_fs_hard_link(src, dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRead for CliSys {
|
||||
fn base_fs_read(&self, p: &Path) -> std::io::Result<Cow<'static, [u8]>> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_read(p),
|
||||
Self::DenoCompile(sys) => sys.base_fs_read(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsReadDir for CliSys {
|
||||
type ReadDirEntry = BoxedFsDirEntry;
|
||||
|
||||
fn base_fs_read_dir(
|
||||
&self,
|
||||
p: &Path,
|
||||
) -> std::io::Result<
|
||||
Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>> + '_>,
|
||||
> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.fs_read_dir_boxed(p),
|
||||
Self::DenoCompile(sys) => sys.fs_read_dir_boxed(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCanonicalize for CliSys {
|
||||
fn base_fs_canonicalize(&self, p: &Path) -> std::io::Result<PathBuf> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_canonicalize(p),
|
||||
Self::DenoCompile(sys) => sys.base_fs_canonicalize(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsMetadata for CliSys {
|
||||
type Metadata = BoxedFsMetadataValue;
|
||||
|
||||
fn base_fs_metadata(&self, path: &Path) -> std::io::Result<Self::Metadata> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.fs_metadata_boxed(path),
|
||||
Self::DenoCompile(sys) => sys.fs_metadata_boxed(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn base_fs_symlink_metadata(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> std::io::Result<Self::Metadata> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.fs_symlink_metadata_boxed(path),
|
||||
Self::DenoCompile(sys) => sys.fs_symlink_metadata_boxed(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsCreateDir for CliSys {
|
||||
fn base_fs_create_dir(
|
||||
&self,
|
||||
p: &Path,
|
||||
options: &CreateDirOptions,
|
||||
) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_create_dir(p, options),
|
||||
Self::DenoCompile(sys) => sys.base_fs_create_dir(p, options),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsOpen for CliSys {
|
||||
type File = BoxedFsFile;
|
||||
|
||||
fn base_fs_open(
|
||||
&self,
|
||||
path: &Path,
|
||||
options: &sys_traits::OpenOptions,
|
||||
) -> std::io::Result<Self::File> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.fs_open_boxed(path, options),
|
||||
Self::DenoCompile(sys) => sys.fs_open_boxed(path, options),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRemoveFile for CliSys {
|
||||
fn base_fs_remove_file(&self, p: &Path) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_remove_file(p),
|
||||
Self::DenoCompile(sys) => sys.base_fs_remove_file(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseFsRename for CliSys {
|
||||
fn base_fs_rename(&self, old: &Path, new: &Path) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_fs_rename(old, new),
|
||||
Self::DenoCompile(sys) => sys.base_fs_rename(old, new),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::SystemRandom for CliSys {
|
||||
fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.sys_random(buf),
|
||||
Self::DenoCompile(sys) => sys.sys_random(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::SystemTimeNow for CliSys {
|
||||
fn sys_time_now(&self) -> std::time::SystemTime {
|
||||
match self {
|
||||
Self::Real(sys) => sys.sys_time_now(),
|
||||
Self::DenoCompile(sys) => sys.sys_time_now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::ThreadSleep for CliSys {
|
||||
fn thread_sleep(&self, dur: std::time::Duration) {
|
||||
match self {
|
||||
Self::Real(sys) => sys.thread_sleep(dur),
|
||||
Self::DenoCompile(sys) => sys.thread_sleep(dur),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::EnvCurrentDir for CliSys {
|
||||
fn env_current_dir(&self) -> std::io::Result<PathBuf> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.env_current_dir(),
|
||||
Self::DenoCompile(sys) => sys.env_current_dir(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::BaseEnvVar for CliSys {
|
||||
fn base_env_var_os(
|
||||
&self,
|
||||
key: &std::ffi::OsStr,
|
||||
) -> Option<std::ffi::OsString> {
|
||||
match self {
|
||||
Self::Real(sys) => sys.base_env_var_os(key),
|
||||
Self::DenoCompile(sys) => sys.base_env_var_os(key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sys_traits::EnvHomeDir for CliSys {
|
||||
fn env_home_dir(&self) -> Option<PathBuf> {
|
||||
#[allow(clippy::disallowed_types)] // ok because sys impl
|
||||
sys_traits::impls::RealSys.env_home_dir()
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::*;
|
||||
use crate::tools::test::TestFailureFormatOptions;
|
||||
use crate::version;
|
||||
|
||||
pub trait BenchReporter {
|
||||
fn report_group_summary(&mut self);
|
||||
|
@ -31,11 +31,7 @@ impl Default for JsonReporterOutput {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
version: JSON_SCHEMA_VERSION,
|
||||
runtime: format!(
|
||||
"{} {}",
|
||||
version::DENO_VERSION_INFO.user_agent,
|
||||
env!("TARGET")
|
||||
),
|
||||
runtime: format!("{} {}", DENO_VERSION_INFO.user_agent, env!("TARGET")),
|
||||
cpu: mitata::cpu::name(),
|
||||
benches: vec![],
|
||||
}
|
||||
|
@ -163,7 +159,7 @@ impl BenchReporter for ConsoleReporter {
|
|||
"{}\n",
|
||||
colors::gray(format!(
|
||||
"Runtime | Deno {} ({})",
|
||||
crate::version::DENO_VERSION_INFO.deno,
|
||||
DENO_VERSION_INFO.deno,
|
||||
env!("TARGET")
|
||||
))
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ use deno_graph::Module;
|
|||
use deno_graph::ModuleError;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_graph::ModuleLoadError;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_semver::npm::NpmPackageNvReference;
|
||||
use deno_terminal::colors;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -28,7 +29,6 @@ use crate::args::TsTypeLib;
|
|||
use crate::args::TypeCheckMode;
|
||||
use crate::cache::CacheDBHash;
|
||||
use crate::cache::Caches;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::TypeCheckCache;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::graph_util::maybe_additional_sloppy_imports_message;
|
||||
|
|
|
@ -4,8 +4,8 @@ use std::path::Path;
|
|||
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_lib::cache::DenoDir;
|
||||
|
||||
use crate::cache::DenoDir;
|
||||
use crate::colors;
|
||||
use crate::display;
|
||||
use crate::sys::CliSys;
|
||||
|
|
|
@ -11,6 +11,7 @@ use std::path::PathBuf;
|
|||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::url::Url;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
|
||||
use super::util;
|
||||
use super::CoverageReport;
|
||||
|
@ -559,7 +560,7 @@ impl HtmlCoverageReporter {
|
|||
|
||||
/// Creates footer part of the contents for html report.
|
||||
pub fn create_html_footer(&self, now: &str) -> String {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let version = DENO_VERSION_INFO.deno;
|
||||
format!(
|
||||
"
|
||||
<div class='footer quiet pad2 space-top1 center small'>
|
||||
|
|
|
@ -20,6 +20,7 @@ use deno_graph::EsParser;
|
|||
use deno_graph::GraphKind;
|
||||
use deno_graph::ModuleAnalyzer;
|
||||
use deno_graph::ModuleSpecifier;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use doc::html::ShortPath;
|
||||
use doc::DocDiagnostic;
|
||||
use indexmap::IndexMap;
|
||||
|
@ -280,7 +281,7 @@ impl deno_doc::html::HrefResolver for DocResolver {
|
|||
if self.deno_ns.contains_key(symbol) {
|
||||
Some(format!(
|
||||
"https://deno.land/api@v{}?s={}",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
DENO_VERSION_INFO.deno,
|
||||
symbol.join(".")
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@ use deno_core::anyhow::Context;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_core::url::Url;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use log::Level;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -26,7 +27,6 @@ use regex::RegexBuilder;
|
|||
|
||||
use crate::args::resolve_no_prompt;
|
||||
use crate::args::AddFlags;
|
||||
use crate::args::CaData;
|
||||
use crate::args::ConfigFlag;
|
||||
use crate::args::Flags;
|
||||
use crate::args::InstallFlags;
|
||||
|
@ -657,6 +657,7 @@ fn is_in_path(dir: &Path) -> bool {
|
|||
mod tests {
|
||||
use std::process::Command;
|
||||
|
||||
use deno_lib::args::UnstableConfig;
|
||||
use test_util::testdata_path;
|
||||
use test_util::TempDir;
|
||||
|
||||
|
@ -664,7 +665,6 @@ mod tests {
|
|||
use crate::args::ConfigFlag;
|
||||
use crate::args::PermissionFlags;
|
||||
use crate::args::UninstallFlagsGlobal;
|
||||
use crate::args::UnstableConfig;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -18,6 +18,7 @@ use deno_core::parking_lot::Mutex;
|
|||
use deno_core::serde_json;
|
||||
use deno_core::CancelFuture;
|
||||
use deno_core::CancelHandle;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use jupyter_runtime::messaging;
|
||||
use jupyter_runtime::ConnectionInfo;
|
||||
use jupyter_runtime::ExecutionCount;
|
||||
|
@ -679,10 +680,10 @@ fn kernel_info() -> messaging::KernelInfoReply {
|
|||
status: ReplyStatus::Ok,
|
||||
protocol_version: "5.3".to_string(),
|
||||
implementation: "Deno kernel".to_string(),
|
||||
implementation_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
|
||||
implementation_version: DENO_VERSION_INFO.deno.to_string(),
|
||||
language_info: messaging::LanguageInfo {
|
||||
name: "typescript".to_string(),
|
||||
version: crate::version::DENO_VERSION_INFO.typescript.to_string(),
|
||||
version: DENO_VERSION_INFO.typescript.to_string(),
|
||||
mimetype: "text/x.typescript".to_string(),
|
||||
file_extension: ".ts".to_string(),
|
||||
pygments_lexer: "typescript".to_string(),
|
||||
|
|
|
@ -8,6 +8,7 @@ use deno_core::error::AnyError;
|
|||
use deno_core::futures::StreamExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use rustyline::error::ReadlineError;
|
||||
|
||||
|
@ -244,7 +245,7 @@ pub async fn run(
|
|||
if !cli_options.is_quiet() {
|
||||
let mut handle = io::stdout().lock();
|
||||
|
||||
writeln!(handle, "Deno {}", crate::version::DENO_VERSION_INFO.deno)?;
|
||||
writeln!(handle, "Deno {}", DENO_VERSION_INFO.deno)?;
|
||||
writeln!(handle, "exit using ctrl+d, ctrl+c, or close()")?;
|
||||
|
||||
if repl_flags.is_default_command {
|
||||
|
|
|
@ -32,6 +32,7 @@ use deno_error::JsErrorBox;
|
|||
use deno_graph::Position;
|
||||
use deno_graph::PositionRange;
|
||||
use deno_graph::SpecifierWithRange;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
|
@ -402,18 +403,16 @@ impl ReplSession {
|
|||
}
|
||||
Err(err) => {
|
||||
// handle a parsing diagnostic
|
||||
match crate::util::result::any_and_jserrorbox_downcast_ref::<
|
||||
deno_ast::ParseDiagnostic,
|
||||
>(&err)
|
||||
{
|
||||
match any_and_jserrorbox_downcast_ref::<deno_ast::ParseDiagnostic>(
|
||||
&err,
|
||||
) {
|
||||
Some(diagnostic) => {
|
||||
Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
|
||||
}
|
||||
None => {
|
||||
match crate::util::result::any_and_jserrorbox_downcast_ref::<
|
||||
ParseDiagnosticsError,
|
||||
>(&err)
|
||||
{
|
||||
match any_and_jserrorbox_downcast_ref::<ParseDiagnosticsError>(
|
||||
&err,
|
||||
) {
|
||||
Some(diagnostics) => Ok(EvaluationOutput::Error(
|
||||
diagnostics
|
||||
.0
|
||||
|
|
|
@ -19,6 +19,8 @@ use deno_core::anyhow::Context;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::unsync::spawn;
|
||||
use deno_core::url::Url;
|
||||
use deno_lib::shared::ReleaseChannel;
|
||||
use deno_lib::version;
|
||||
use deno_semver::SmallStackString;
|
||||
use deno_semver::Version;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -30,11 +32,9 @@ use crate::colors;
|
|||
use crate::factory::CliFactory;
|
||||
use crate::http_util::HttpClient;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
use crate::shared::ReleaseChannel;
|
||||
use crate::util::archive;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use crate::version;
|
||||
|
||||
const RELEASE_URL: &str = "https://github.com/denoland/deno/releases";
|
||||
const CANARY_URL: &str = "https://dl.deno.land/canary";
|
||||
|
|
|
@ -29,6 +29,7 @@ use deno_graph::Module;
|
|||
use deno_graph::ModuleGraph;
|
||||
use deno_graph::ResolutionResolved;
|
||||
use deno_lib::util::checksum;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lib::worker::create_isolate_create_params;
|
||||
use deno_resolver::npm::managed::ResolvePkgFolderFromDenoModuleError;
|
||||
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
|
||||
|
@ -44,7 +45,6 @@ use thiserror::Error;
|
|||
|
||||
use crate::args::TsConfig;
|
||||
use crate::args::TypeCheckMode;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::ModuleInfoCache;
|
||||
use crate::node::CliNodeResolver;
|
||||
use crate::npm::CliNpmResolver;
|
||||
|
|
|
@ -14,6 +14,7 @@ use deno_core::error::CoreError;
|
|||
use deno_core::futures::Future;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use log::info;
|
||||
use notify::event::Event as NotifyEvent;
|
||||
|
@ -82,10 +83,8 @@ where
|
|||
{
|
||||
let result = watch_future.await;
|
||||
if let Err(err) = result {
|
||||
let error_string =
|
||||
match crate::util::result::any_and_jserrorbox_downcast_ref::<CoreError>(
|
||||
&err,
|
||||
) {
|
||||
let error_string = match any_and_jserrorbox_downcast_ref::<CoreError>(&err)
|
||||
{
|
||||
Some(CoreError::Js(e)) => format_js_error(e),
|
||||
_ => format!("{err:?}"),
|
||||
};
|
||||
|
|
|
@ -9,10 +9,8 @@ pub mod draw_thread;
|
|||
pub mod extract;
|
||||
pub mod file_watcher;
|
||||
pub mod fs;
|
||||
pub mod logger;
|
||||
pub mod path;
|
||||
pub mod progress_bar;
|
||||
pub mod result;
|
||||
pub mod retry;
|
||||
pub mod sync;
|
||||
pub mod text_encoding;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
|
@ -11,24 +9,6 @@ use deno_core::ModuleSourceCode;
|
|||
static SOURCE_MAP_PREFIX: &[u8] =
|
||||
b"//# sourceMappingURL=data:application/json;base64,";
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_utf8_lossy_cow(bytes: Cow<[u8]>) -> Cow<str> {
|
||||
match bytes {
|
||||
Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes),
|
||||
Cow::Owned(bytes) => Cow::Owned(from_utf8_lossy_owned(bytes)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_utf8_lossy_owned(bytes: Vec<u8>) -> String {
|
||||
match String::from_utf8_lossy(&bytes) {
|
||||
Cow::Owned(code) => code,
|
||||
// SAFETY: `String::from_utf8_lossy` guarantees that the result is valid
|
||||
// UTF-8 if `Cow::Borrowed` is returned.
|
||||
Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(bytes) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_map_from_code(code: &[u8]) -> Option<Vec<u8>> {
|
||||
let range = find_source_map_range(code)?;
|
||||
let source_map_range = &code[range];
|
||||
|
@ -105,29 +85,6 @@ fn find_source_map_range(code: &[u8]) -> Option<Range<usize>> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts an `Arc<str>` to an `Arc<[u8]>`.
|
||||
#[allow(dead_code)]
|
||||
pub fn arc_str_to_bytes(arc_str: Arc<str>) -> Arc<[u8]> {
|
||||
let raw = Arc::into_raw(arc_str);
|
||||
// SAFETY: This is safe because they have the same memory layout.
|
||||
unsafe { Arc::from_raw(raw as *const [u8]) }
|
||||
}
|
||||
|
||||
/// Converts an `Arc<u8>` to an `Arc<str>` if able.
|
||||
#[allow(dead_code)]
|
||||
pub fn arc_u8_to_arc_str(
|
||||
arc_u8: Arc<[u8]>,
|
||||
) -> Result<Arc<str>, std::str::Utf8Error> {
|
||||
// Check that the string is valid UTF-8.
|
||||
std::str::from_utf8(&arc_u8)?;
|
||||
// SAFETY: the string is valid UTF-8, and the layout Arc<[u8]> is the same as
|
||||
// Arc<str>. This is proven by the From<Arc<str>> impl for Arc<[u8]> from the
|
||||
// standard library.
|
||||
Ok(unsafe {
|
||||
std::mem::transmute::<std::sync::Arc<[u8]>, std::sync::Arc<str>>(arc_u8)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use deno_lib::util::v8::construct_v8_flags;
|
||||
|
||||
pub mod convert;
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -10,19 +12,6 @@ pub fn get_v8_flags_from_env() -> Vec<String> {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn construct_v8_flags(
|
||||
default_v8_flags: &[String],
|
||||
v8_flags: &[String],
|
||||
env_v8_flags: Vec<String>,
|
||||
) -> Vec<String> {
|
||||
std::iter::once("UNUSED_BUT_NECESSARY_ARG0".to_owned())
|
||||
.chain(default_v8_flags.iter().cloned())
|
||||
.chain(env_v8_flags)
|
||||
.chain(v8_flags.iter().cloned())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn init_v8_flags(
|
||||
default_v8_flags: &[String],
|
||||
v8_flags: &[String],
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::shared::ReleaseChannel;
|
||||
|
||||
const GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH");
|
||||
const TYPESCRIPT: &str = env!("TS_VERSION");
|
||||
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
// TODO(bartlomieju): ideally we could remove this const.
|
||||
const IS_CANARY: bool = option_env!("DENO_CANARY").is_some();
|
||||
// TODO(bartlomieju): this is temporary, to allow Homebrew to cut RC releases as well
|
||||
const IS_RC: bool = option_env!("DENO_RC").is_some();
|
||||
|
||||
pub static DENO_VERSION_INFO: Lazy<DenoVersionInfo> = Lazy::new(|| {
|
||||
let release_channel = libsui::find_section("denover")
|
||||
.and_then(|buf| std::str::from_utf8(buf).ok())
|
||||
.and_then(|str_| ReleaseChannel::deserialize(str_).ok())
|
||||
.unwrap_or({
|
||||
if IS_CANARY {
|
||||
ReleaseChannel::Canary
|
||||
} else if IS_RC {
|
||||
ReleaseChannel::Rc
|
||||
} else {
|
||||
ReleaseChannel::Stable
|
||||
}
|
||||
});
|
||||
|
||||
DenoVersionInfo {
|
||||
deno: if release_channel == ReleaseChannel::Canary {
|
||||
concat!(
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
"+",
|
||||
env!("GIT_COMMIT_HASH_SHORT")
|
||||
)
|
||||
} else {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
},
|
||||
|
||||
release_channel,
|
||||
|
||||
git_hash: GIT_COMMIT_HASH,
|
||||
|
||||
// Keep in sync with `deno` field.
|
||||
user_agent: if release_channel == ReleaseChannel::Canary {
|
||||
concat!(
|
||||
"Deno/",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
"+",
|
||||
env!("GIT_COMMIT_HASH_SHORT")
|
||||
)
|
||||
} else {
|
||||
concat!("Deno/", env!("CARGO_PKG_VERSION"))
|
||||
},
|
||||
|
||||
typescript: TYPESCRIPT,
|
||||
}
|
||||
});
|
||||
|
||||
pub struct DenoVersionInfo {
|
||||
/// Human-readable version of the current Deno binary.
|
||||
///
|
||||
/// For stable release, a semver, eg. `v1.46.2`.
|
||||
/// For canary release, a semver + 7-char git hash, eg. `v1.46.3+asdfqwq`.
|
||||
pub deno: &'static str,
|
||||
|
||||
pub release_channel: ReleaseChannel,
|
||||
|
||||
/// A full git hash.
|
||||
pub git_hash: &'static str,
|
||||
|
||||
/// A user-agent header that will be used in HTTP client.
|
||||
pub user_agent: &'static str,
|
||||
|
||||
pub typescript: &'static str,
|
||||
}
|
||||
|
||||
impl DenoVersionInfo {
|
||||
/// For stable release, a semver like, eg. `v1.46.2`.
|
||||
/// For canary release a full git hash, eg. `9bdab6fb6b93eb43b1930f40987fa4997287f9c8`.
|
||||
pub fn version_or_git_hash(&self) -> &'static str {
|
||||
if self.release_channel == ReleaseChannel::Canary {
|
||||
self.git_hash
|
||||
} else {
|
||||
CARGO_PKG_VERSION
|
||||
}
|
||||
}
|
||||
}
|
118
cli/worker.rs
118
cli/worker.rs
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
|
@ -12,20 +11,16 @@ use deno_core::PollEventLoopOptions;
|
|||
use deno_error::JsErrorBox;
|
||||
use deno_lib::worker::LibMainWorker;
|
||||
use deno_lib::worker::LibMainWorkerFactory;
|
||||
use deno_runtime::code_cache;
|
||||
use deno_lib::worker::ResolveNpmBinaryEntrypointError;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::errors::ResolvePkgJsonBinExportError;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
use sys_traits::EnvCurrentDir;
|
||||
use tokio::select;
|
||||
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::NpmCachingStrategy;
|
||||
use crate::node::CliNodeResolver;
|
||||
use crate::npm::installer::NpmInstaller;
|
||||
use crate::npm::installer::PackageCaching;
|
||||
use crate::npm::CliNpmResolver;
|
||||
|
@ -40,15 +35,6 @@ pub trait HmrRunner: Send + Sync {
|
|||
async fn run(&mut self) -> Result<(), CoreError>;
|
||||
}
|
||||
|
||||
pub trait CliCodeCache: code_cache::CodeCache {
|
||||
/// Gets if the code cache is still enabled.
|
||||
fn enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn as_code_cache(self: Arc<Self>) -> Arc<dyn code_cache::CodeCache>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
pub trait CoverageCollector: Send + Sync {
|
||||
async fn start_collecting(&mut self) -> Result<(), CoreError>;
|
||||
|
@ -102,6 +88,8 @@ impl CliMainWorker {
|
|||
|
||||
log::debug!("main_module {}", self.worker.main_module());
|
||||
|
||||
// WARNING: Remember to update cli/lib/worker.rs to align with
|
||||
// changes made here so that they affect deno_compile as well.
|
||||
self.execute_main_module().await?;
|
||||
self.worker.dispatch_load_event()?;
|
||||
|
||||
|
@ -295,29 +283,6 @@ impl CliMainWorker {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum ResolveBinaryEntrypointError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
ResolvePkgJsonBinExport(ResolvePkgJsonBinExportError),
|
||||
#[class(generic)]
|
||||
#[error("{original:#}\n\nFallback failed: {fallback:#}")]
|
||||
Fallback {
|
||||
fallback: ResolveBinaryEntrypointFallbackError,
|
||||
original: ResolvePkgJsonBinExportError,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum ResolveBinaryEntrypointFallbackError {
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
PackageSubpathResolve(node_resolver::errors::PackageSubpathResolveError),
|
||||
#[class(generic)]
|
||||
#[error("Cannot find module '{0}'")]
|
||||
ModuleNotFound(ModuleSpecifier),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum CreateCustomWorkerError {
|
||||
#[class(inherit)]
|
||||
|
@ -336,7 +301,7 @@ pub enum CreateCustomWorkerError {
|
|||
UrlParse(#[from] deno_core::url::ParseError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
ResolveBinaryEntrypoint(#[from] ResolveBinaryEntrypointError),
|
||||
ResolveNpmBinaryEntrypoint(#[from] ResolveNpmBinaryEntrypointError),
|
||||
#[class(inherit)]
|
||||
#[error(transparent)]
|
||||
NpmPackageReq(JsErrorBox),
|
||||
|
@ -350,7 +315,6 @@ pub enum CreateCustomWorkerError {
|
|||
pub struct CliMainWorkerFactory {
|
||||
lib_main_worker_factory: LibMainWorkerFactory<CliSys>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_installer: Option<Arc<NpmInstaller>>,
|
||||
npm_resolver: CliNpmResolver,
|
||||
root_permissions: PermissionsContainer,
|
||||
|
@ -366,7 +330,6 @@ impl CliMainWorkerFactory {
|
|||
lib_main_worker_factory: LibMainWorkerFactory<CliSys>,
|
||||
maybe_file_watcher_communicator: Option<Arc<WatcherCommunicator>>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_installer: Option<Arc<NpmInstaller>>,
|
||||
npm_resolver: CliNpmResolver,
|
||||
sys: CliSys,
|
||||
|
@ -376,7 +339,6 @@ impl CliMainWorkerFactory {
|
|||
Self {
|
||||
lib_main_worker_factory,
|
||||
maybe_lockfile,
|
||||
node_resolver,
|
||||
npm_installer,
|
||||
npm_resolver,
|
||||
root_permissions,
|
||||
|
@ -446,8 +408,11 @@ impl CliMainWorkerFactory {
|
|||
package_ref.req(),
|
||||
&referrer,
|
||||
)?;
|
||||
let main_module = self
|
||||
.resolve_binary_entrypoint(&package_folder, package_ref.sub_path())?;
|
||||
let main_module =
|
||||
self.lib_main_worker_factory.resolve_npm_binary_entrypoint(
|
||||
&package_folder,
|
||||
package_ref.sub_path(),
|
||||
)?;
|
||||
|
||||
if let Some(lockfile) = &self.maybe_lockfile {
|
||||
// For npm binary commands, ensure that the lockfile gets updated
|
||||
|
@ -494,71 +459,6 @@ impl CliMainWorkerFactory {
|
|||
shared: self.shared.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_binary_entrypoint(
|
||||
&self,
|
||||
package_folder: &Path,
|
||||
sub_path: Option<&str>,
|
||||
) -> Result<ModuleSpecifier, ResolveBinaryEntrypointError> {
|
||||
match self
|
||||
.node_resolver
|
||||
.resolve_binary_export(package_folder, sub_path)
|
||||
{
|
||||
Ok(specifier) => Ok(specifier),
|
||||
Err(original_err) => {
|
||||
// if the binary entrypoint was not found, fallback to regular node resolution
|
||||
let result =
|
||||
self.resolve_binary_entrypoint_fallback(package_folder, sub_path);
|
||||
match result {
|
||||
Ok(Some(specifier)) => Ok(specifier),
|
||||
Ok(None) => Err(
|
||||
ResolveBinaryEntrypointError::ResolvePkgJsonBinExport(original_err),
|
||||
),
|
||||
Err(fallback_err) => Err(ResolveBinaryEntrypointError::Fallback {
|
||||
original: original_err,
|
||||
fallback: fallback_err,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// resolve the binary entrypoint using regular node resolution
|
||||
fn resolve_binary_entrypoint_fallback(
|
||||
&self,
|
||||
package_folder: &Path,
|
||||
sub_path: Option<&str>,
|
||||
) -> Result<Option<ModuleSpecifier>, ResolveBinaryEntrypointFallbackError> {
|
||||
// only fallback if the user specified a sub path
|
||||
if sub_path.is_none() {
|
||||
// it's confusing to users if the package doesn't have any binary
|
||||
// entrypoint and we just execute the main script which will likely
|
||||
// have blank output, so do not resolve the entrypoint in this case
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let specifier = self
|
||||
.node_resolver
|
||||
.resolve_package_subpath_from_deno_module(
|
||||
package_folder,
|
||||
sub_path,
|
||||
/* referrer */ None,
|
||||
ResolutionMode::Import,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.map_err(ResolveBinaryEntrypointFallbackError::PackageSubpathResolve)?;
|
||||
if specifier
|
||||
.to_file_path()
|
||||
.map(|p| p.exists())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(Some(specifier))
|
||||
} else {
|
||||
Err(ResolveBinaryEntrypointFallbackError::ModuleNotFound(
|
||||
specifier,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::print_stdout)]
|
||||
|
|
|
@ -33,7 +33,6 @@ deno_error.workspace = true
|
|||
deno_fetch.workspace = true
|
||||
deno_fs.workspace = true
|
||||
deno_io.workspace = true
|
||||
deno_media_type.workspace = true
|
||||
deno_net.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
|
@ -47,7 +46,6 @@ ecb.workspace = true
|
|||
ecdsa = "0.16.9"
|
||||
ed25519-dalek = { version = "2.1.1", features = ["digest", "pkcs8", "rand_core", "signature"] }
|
||||
elliptic-curve.workspace = true
|
||||
errno = "0.2.8"
|
||||
faster-hex.workspace = true
|
||||
h2.workspace = true
|
||||
hkdf.workspace = true
|
||||
|
@ -104,6 +102,9 @@ x25519-dalek = { version = "2.0.0", features = ["static_secrets"] }
|
|||
x509-parser = "0.15.0"
|
||||
yoke.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
errno = "0.3.8"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys.workspace = true
|
||||
winapi = { workspace = true, features = ["consoleapi"] }
|
||||
|
|
|
@ -226,7 +226,6 @@ deno_core::extension!(deno_node,
|
|||
ops::crypto::op_node_decipheriv_decrypt,
|
||||
ops::crypto::op_node_decipheriv_final,
|
||||
ops::crypto::op_node_decipheriv_set_aad,
|
||||
ops::crypto::op_node_decipheriv_take,
|
||||
ops::crypto::op_node_dh_compute_secret,
|
||||
ops::crypto::op_node_diffie_hellman,
|
||||
ops::crypto::op_node_ecdh_compute_public_key,
|
||||
|
|
|
@ -500,6 +500,11 @@ impl Decipher {
|
|||
auth_tag: &[u8],
|
||||
) -> Result<(), DecipherError> {
|
||||
use Decipher::*;
|
||||
|
||||
if input.is_empty() && !matches!(self, Aes128Gcm(_) | Aes256Gcm(_)) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match (self, auto_pad) {
|
||||
(Aes128Cbc(decryptor), true) => {
|
||||
assert!(input.len() == 16);
|
||||
|
|
|
@ -332,17 +332,6 @@ pub fn op_node_decipheriv_decrypt(
|
|||
true
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_node_decipheriv_take(
|
||||
state: &mut OpState,
|
||||
#[smi] rid: u32,
|
||||
) -> Result<(), cipher::DecipherContextError> {
|
||||
let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
|
||||
Rc::try_unwrap(context)
|
||||
.map_err(|_| cipher::DecipherContextError::ContextInUse)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
pub fn op_node_decipheriv_final(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -18,7 +18,6 @@ import {
|
|||
op_node_decipheriv_decrypt,
|
||||
op_node_decipheriv_final,
|
||||
op_node_decipheriv_set_aad,
|
||||
op_node_decipheriv_take,
|
||||
op_node_private_decrypt,
|
||||
op_node_private_encrypt,
|
||||
op_node_public_encrypt,
|
||||
|
@ -352,14 +351,6 @@ export class Decipheriv extends Transform implements Cipher {
|
|||
}
|
||||
|
||||
final(encoding: string = getDefaultEncoding()): Buffer | string {
|
||||
if (!this.#needsBlockCache || this.#cache.cache.byteLength === 0) {
|
||||
op_node_decipheriv_take(this.#context);
|
||||
return encoding === "buffer" ? Buffer.from([]) : "";
|
||||
}
|
||||
if (this.#cache.cache.byteLength != 16) {
|
||||
throw new Error("Invalid final block size");
|
||||
}
|
||||
|
||||
let buf = new Buffer(16);
|
||||
op_node_decipheriv_final(
|
||||
this.#context,
|
||||
|
@ -369,6 +360,13 @@ export class Decipheriv extends Transform implements Cipher {
|
|||
this.#authTag || NO_TAG,
|
||||
);
|
||||
|
||||
if (!this.#needsBlockCache || this.#cache.cache.byteLength === 0) {
|
||||
return encoding === "buffer" ? Buffer.from([]) : "";
|
||||
}
|
||||
if (this.#cache.cache.byteLength != 16) {
|
||||
throw new Error("Invalid final block size");
|
||||
}
|
||||
|
||||
buf = buf.subarray(0, 16 - buf.at(-1)); // Padded in Pkcs7 mode
|
||||
return encoding === "buffer" ? buf : buf.toString(encoding);
|
||||
}
|
||||
|
|
|
@ -23,11 +23,13 @@ libc.workspace = true
|
|||
netif = "0.1.6"
|
||||
once_cell.workspace = true
|
||||
serde.workspace = true
|
||||
signal-hook = "0.3.17"
|
||||
signal-hook-registry = "1.4.0"
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "psapi", "shlobj", "tlhelp32", "winbase", "winerror", "winuser", "winsock2"] }
|
||||
ntapi = "0.4.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
signal-hook = "0.3.17"
|
||||
signal-hook-registry = "1.4.0"
|
||||
|
|
|
@ -690,9 +690,7 @@ ObjectDefineProperty(GPUQuerySet, customInspect, {
|
|||
const GPUQuerySetPrototype = GPUQuerySet.prototype;
|
||||
|
||||
// Converters
|
||||
/*
|
||||
|
||||
// DICTIONARY: GPUPipelineErrorInit
|
||||
webidl.converters["GPUPipelineErrorInit"] = webidl.createDictionaryConverter(
|
||||
"GPUPipelineErrorInit",
|
||||
[
|
||||
|
@ -704,7 +702,6 @@ webidl.converters["GPUPipelineErrorInit"] = webidl.createDictionaryConverter(
|
|||
],
|
||||
);
|
||||
|
||||
// ENUM: GPUPipelineErrorReason
|
||||
webidl.converters["GPUPipelineErrorReason"] = webidl.createEnumConverter(
|
||||
"GPUPipelineErrorReason",
|
||||
[
|
||||
|
@ -713,16 +710,8 @@ webidl.converters["GPUPipelineErrorReason"] = webidl.createEnumConverter(
|
|||
],
|
||||
);
|
||||
|
||||
// TYPEDEF: GPUError
|
||||
webidl.converters["GPUError"] = webidl.converters.any /!** put union here! **!/;
|
||||
webidl.converters["GPUError"] = webidl.converters.any /* put union here! */;
|
||||
|
||||
// // INTERFACE: GPUUncapturedErrorEvent
|
||||
// webidl.converters.GPUUncapturedErrorEvent = webidl.createInterfaceConverter(
|
||||
// "GPUUncapturedErrorEvent",
|
||||
// GPUUncapturedErrorEvent.prototype,
|
||||
// );
|
||||
|
||||
// DICTIONARY: GPUUncapturedErrorEventInit
|
||||
const dictMembersGPUUncapturedErrorEventInit = [
|
||||
{ key: "error", converter: webidl.converters["GPUError"], required: true },
|
||||
];
|
||||
|
@ -733,71 +722,6 @@ webidl.converters["GPUUncapturedErrorEventInit"] = webidl
|
|||
dictMembersGPUUncapturedErrorEventInit,
|
||||
);
|
||||
|
||||
// BYOW
|
||||
|
||||
// ENUM: GPUCanvasAlphaMode
|
||||
webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter(
|
||||
"GPUCanvasAlphaMode",
|
||||
[
|
||||
"opaque",
|
||||
"premultiplied",
|
||||
],
|
||||
);
|
||||
|
||||
// NON-SPEC: ENUM: GPUPresentMode
|
||||
webidl.converters["GPUPresentMode"] = webidl.createEnumConverter(
|
||||
"GPUPresentMode",
|
||||
[
|
||||
"autoVsync",
|
||||
"autoNoVsync",
|
||||
"fifo",
|
||||
"fifoRelaxed",
|
||||
"immediate",
|
||||
"mailbox",
|
||||
],
|
||||
);
|
||||
|
||||
// DICT: GPUCanvasConfiguration
|
||||
const dictMembersGPUCanvasConfiguration = [
|
||||
{ key: "device", converter: webidl.converters.GPUDevice, required: true },
|
||||
{
|
||||
key: "format",
|
||||
converter: webidl.converters.GPUTextureFormat,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: "usage",
|
||||
converter: webidl.converters["GPUTextureUsageFlags"],
|
||||
defaultValue: GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
},
|
||||
{
|
||||
key: "alphaMode",
|
||||
converter: webidl.converters["GPUCanvasAlphaMode"],
|
||||
defaultValue: "opaque",
|
||||
},
|
||||
|
||||
// Extended from spec
|
||||
{
|
||||
key: "presentMode",
|
||||
converter: webidl.converters["GPUPresentMode"],
|
||||
},
|
||||
{
|
||||
key: "viewFormats",
|
||||
converter: webidl.createSequenceConverter(
|
||||
webidl.converters["GPUTextureFormat"],
|
||||
),
|
||||
get defaultValue() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
];
|
||||
webidl.converters["GPUCanvasConfiguration"] = webidl
|
||||
.createDictionaryConverter(
|
||||
"GPUCanvasConfiguration",
|
||||
dictMembersGPUCanvasConfiguration,
|
||||
);
|
||||
*/
|
||||
|
||||
let gpu;
|
||||
function initGPU() {
|
||||
if (!gpu) {
|
||||
|
|
|
@ -7,146 +7,16 @@
|
|||
/// <reference path="./lib.deno_webgpu.d.ts" />
|
||||
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
import {
|
||||
op_webgpu_surface_configure,
|
||||
op_webgpu_surface_create,
|
||||
op_webgpu_surface_get_current_texture,
|
||||
op_webgpu_surface_present,
|
||||
} from "ext:core/ops";
|
||||
import { GPUCanvasContext, UnsafeWindowSurface } from "ext:core/ops";
|
||||
const {
|
||||
ObjectDefineProperty,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
Symbol,
|
||||
SymbolFor,
|
||||
TypeError,
|
||||
} = primordials;
|
||||
|
||||
import * as webidl from "ext:deno_webidl/00_webidl.js";
|
||||
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
|
||||
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
|
||||
|
||||
const _surfaceRid = Symbol("[[surfaceRid]]");
|
||||
const _configuration = Symbol("[[configuration]]");
|
||||
const _canvas = Symbol("[[canvas]]");
|
||||
const _currentTexture = Symbol("[[currentTexture]]");
|
||||
const _present = Symbol("[[present]]");
|
||||
const _dim = Symbol("[[dimensions]]");
|
||||
|
||||
class GPUCanvasContext {
|
||||
/** @type {number} */
|
||||
[_surfaceRid];
|
||||
[_configuration];
|
||||
[_canvas];
|
||||
/** @type {GPUTexture | undefined} */
|
||||
[_currentTexture];
|
||||
[_dim];
|
||||
|
||||
get canvas() {
|
||||
webidl.assertBranded(this, GPUCanvasContextPrototype);
|
||||
return this[_canvas];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
webidl.illegalConstructor();
|
||||
}
|
||||
|
||||
configure(configuration) {
|
||||
webidl.assertBranded(this, GPUCanvasContextPrototype);
|
||||
const prefix = "Failed to execute 'configure' on 'GPUCanvasContext'";
|
||||
webidl.requiredArguments(arguments.length, 1, { prefix });
|
||||
configuration = webidl.converters.GPUCanvasConfiguration(configuration, {
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
|
||||
const { _device, assertDevice } = loadWebGPU();
|
||||
this[_device] = configuration.device[_device];
|
||||
this[_configuration] = configuration;
|
||||
const device = assertDevice(this, {
|
||||
prefix,
|
||||
context: "configuration.device",
|
||||
});
|
||||
|
||||
const { err } = op_webgpu_surface_configure({
|
||||
surfaceRid: this[_surfaceRid],
|
||||
deviceRid: device.rid,
|
||||
format: configuration.format,
|
||||
viewFormats: configuration.viewFormats,
|
||||
usage: configuration.usage,
|
||||
width: this[_dim].width,
|
||||
height: this[_dim].height,
|
||||
alphaMode: configuration.alphaMode,
|
||||
});
|
||||
|
||||
device.pushError(err);
|
||||
}
|
||||
|
||||
unconfigure() {
|
||||
const { _device } = loadWebGPU();
|
||||
|
||||
webidl.assertBranded(this, GPUCanvasContextPrototype);
|
||||
|
||||
this[_configuration] = null;
|
||||
this[_device] = null;
|
||||
}
|
||||
|
||||
getCurrentTexture() {
|
||||
webidl.assertBranded(this, GPUCanvasContextPrototype);
|
||||
const prefix =
|
||||
"Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'";
|
||||
|
||||
if (this[_configuration] === null) {
|
||||
throw new DOMException("Context is not configured", "InvalidStateError");
|
||||
}
|
||||
const { createGPUTexture, assertDevice } = loadWebGPU();
|
||||
|
||||
const device = assertDevice(this, { prefix, context: "this" });
|
||||
|
||||
if (this[_currentTexture]) {
|
||||
return this[_currentTexture];
|
||||
}
|
||||
|
||||
const { rid } = op_webgpu_surface_get_current_texture(
|
||||
device.rid,
|
||||
this[_surfaceRid],
|
||||
);
|
||||
|
||||
const texture = createGPUTexture(
|
||||
{
|
||||
size: {
|
||||
width: this[_dim].width,
|
||||
height: this[_dim].height,
|
||||
depthOrArrayLayers: 1,
|
||||
},
|
||||
mipLevelCount: 1,
|
||||
sampleCount: 1,
|
||||
dimension: "2d",
|
||||
format: this[_configuration].format,
|
||||
usage: this[_configuration].usage,
|
||||
},
|
||||
device,
|
||||
rid,
|
||||
);
|
||||
device.trackResource(texture);
|
||||
this[_currentTexture] = texture;
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Required to present the texture; browser don't need this.
|
||||
[_present]() {
|
||||
const { assertDevice } = loadWebGPU();
|
||||
|
||||
webidl.assertBranded(this, GPUCanvasContextPrototype);
|
||||
const prefix = "Failed to execute 'present' on 'GPUCanvasContext'";
|
||||
const device = assertDevice(this[_currentTexture], {
|
||||
prefix,
|
||||
context: "this",
|
||||
});
|
||||
op_webgpu_surface_present(device.rid, this[_surfaceRid]);
|
||||
this[_currentTexture].destroy();
|
||||
this[_currentTexture] = undefined;
|
||||
}
|
||||
|
||||
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
|
||||
ObjectDefineProperty(GPUCanvasContext, SymbolFor("Deno.privateCustomInspect"), {
|
||||
value(inspect, inspectOptions) {
|
||||
return inspect(
|
||||
createFilteredInspectProxy({
|
||||
object: this,
|
||||
|
@ -157,60 +27,8 @@ class GPUCanvasContext {
|
|||
}),
|
||||
inspectOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
const GPUCanvasContextPrototype = GPUCanvasContext.prototype;
|
||||
|
||||
function createCanvasContext(options) {
|
||||
// lazy load webgpu if needed
|
||||
const canvasContext = webidl.createBranded(GPUCanvasContext);
|
||||
canvasContext[_surfaceRid] = options.surfaceRid;
|
||||
canvasContext[_canvas] = options.canvas;
|
||||
canvasContext[_dim] = { width: options.width, height: options.height };
|
||||
|
||||
return canvasContext;
|
||||
}
|
||||
|
||||
// External webgpu surfaces
|
||||
|
||||
// TODO(@littledivy): This will extend `OffscreenCanvas` when we add it.
|
||||
class UnsafeWindowSurface {
|
||||
#ctx;
|
||||
#surfaceRid;
|
||||
#options;
|
||||
|
||||
constructor(options) {
|
||||
if (typeof options !== "object") {
|
||||
throw new TypeError("options must be provided.");
|
||||
}
|
||||
if (
|
||||
typeof options.width !== "number" || typeof options.height !== "number"
|
||||
) {
|
||||
throw new TypeError("width and height must be provided.");
|
||||
}
|
||||
|
||||
this.#surfaceRid = op_webgpu_surface_create(
|
||||
options.system,
|
||||
options.windowHandle,
|
||||
options.displayHandle,
|
||||
);
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
getContext(context) {
|
||||
if (context !== "webgpu") {
|
||||
throw new TypeError("Only 'webgpu' context is supported");
|
||||
}
|
||||
this.#ctx = createCanvasContext({
|
||||
surfaceRid: this.#surfaceRid,
|
||||
...this.#options,
|
||||
});
|
||||
return this.#ctx;
|
||||
}
|
||||
|
||||
present() {
|
||||
this.#ctx[_present]();
|
||||
}
|
||||
}
|
||||
|
||||
export { GPUCanvasContext, UnsafeWindowSurface };
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue